I have a Rails database with Schools and Majors in it. Once the user selects his school, I want to fill up the major's drop down with only the majors from the corresponding school. Currently I have two working drop downs, but as you can see they just select all values. Will I need Json/Ajax/JavaScript for this, and if so how can I go about implementing it?
<div class="field">
<%= f.label :school_id %><br>
<%= f.collection_select :school_id, School.order(:name),:id,:name, include_blank: false %>
</div>
<div class="field">
<%= f.label :major_id %><br>
<%= f.collection_select :major_id, Major.order(:name),:id,:name, include_blank: false %>
</div>
In the same or in another spreadsheet, select a cell or several cells in which you want your primary drop-down list to appear. Go to the Data tab, click Data Validation and set up a drop-down list based on a named range in the usual way by selecting List under Allow and entering the range name in the Source box.
The current solution is using an async request on each dropdown selection. Assuming you have a small total corpus of choices (let's say <5k), it may be better to only have 1 async operation when the page loads, and then use JS to populate the dropdowns as the user makes their choices. This would save a lot of network calls, and provide a better user experience.
Alright, so after much searching I've arrived at a working AJAX request (which I will post here for posterity).
When creating a new course in my database there is a Schools and a Major foreign key that must be non-null. Here are the dropdowns
<!-- app/views/courses/_form.html.erb -->
<div class="field">
<%= f.label :school_id %><br>
<%= f.collection_select :school_id, School.order(:name),:id,:name, {include_blank: false},{:id=>'school_id_select'} %>
</div>
<div class="field">
<%= f.label :major_id %><br>
<%= f.collection_select :major_id, [],:id,:name, {include_blank: false},{:id=>'major_id_select'} %>
</div>
Now that the HTML is up, we need some JavaScript (and jQuery) to process the AJAX request
//app/assests/javascripts/courses.js (note this was generated as a .coffee file, which I changed to .js as I don't know CoffeeScript
console.log('loaded courses.js')//check that the file is loaded
$(document).on('change','#school_id_select', function () {//change majors when user changes school
load_majors_from_school_dropdown();
});
$(document).ready(load_majors_from_school_dropdown);//populate majors when page loads with first school
function load_majors_from_school_dropdown(){
var request = "/majors/find_majors_given_school_id?school_id=" //access controller of interest
+ $('#school_id_select').val();
var aj = $.ajax({
url: request,
type: 'get',
data: $(this).serialize()
}).done(function (data) {
change_majors(data);//modify the majors' dropdown
}).fail(function (data) {
console.log('AJAX request has FAILED');
});
};
//modify the majors' dropdown
function change_majors(data) {
$("#major_id_select").empty();//remove all previous majors
for(i = 0;i<data.length;i++){
$("#major_id_select").append(//add in an option for each major
$("<option></option>").attr("value", data[i].id).text(data[i].name)
);
}
};
Take note of the 'request' variable. This indicates the controller & action that will process the request. Now we must make it. My Major controller already existed, so we only have to add the action. First add the action's route to make the Rails server aware of the action.
#config/routes.rb
Rails.application.routes.draw do
#...
get 'majors/find_majors_given_school_id'
#...
end
Now create the action in the Major controller
#app/controllers/majors_controller.rb
#custom action for AJAX/JSON calls. Note this can be done multiple ways
def find_majors_given_school_id
school_id = params[:school_id]#utilizes the url to extract school_id ".../find_majors_given_school_id?school_id=123123"
puts "THIS IS MY SCHOOL ID :: #{school_id}"#view this in teminal
majors = Major.search_for_school_id(school_id).as_json#query the model for the data and convert it to a hash using as_json
puts "THESE ARE MY MAJORS IN A HASH :: #{majors}"
respond_to do |format|
format.json {
render json: majors
}
end
end
Finally, we have to create the query to extract this information in our model.
#app/models/major.rb
class Major < ActiveRecord::Base
has_many :courses, dependent: :destroy
belongs_to :school, :foreign_key => "school_id"
def self.search_for_school_id(id)
where("school_id = ?",id)
end
#...
end
I think that's everything. There are certainly other ways of implementing this, but this one worked for me. Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With