The problem: I need to filter a collection of Units based upon the selection of a collection of Organizations.
Upon selecting an Organization, the Unit dropdown-menu should refresh to show only the Units that belong to informed Organization.
I've checked these questions:
Rails forms: updating collection_select options based on other collection_select value using AJAX
UJS, AJAX, Rails 4, form_for collection_select to pass value into method and return value back to form
ajax in rails with collection_select
How to add an onchange event to select tag in rails
Rails forms: updating collection_select options based on other collection_select value using AJAX
Rails form_for collection_select ignoring remote ajax call that select_tag accepts
remote select, controller needs more form data
And these documentations:
This is my code so far:
Models
class Organization < ActiveRecord::Base
has_many :units
has_many :projects, through: :units
end
class Unit < ActiveRecord::Base
belongs_to :organization
has_many :projects
end
class Project < ActiveRecord::Base
belongs_to :organizaton
has_one :organization, through: :unit
end
Views app/views/projects/_form.html.erb
<%= form_for(@project) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :organization_id %><br>
<%= f.collection_select :organization_id, Organization.all, :id, :name %>
</div>
<div class="field">
<%= f.label :unit_id %><br>
<%= f.collection_select :unit_id, Unit.all.where(organization_id: :organization_id), :id, :name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Controllers Projects Controller
def new
@project = Project.new
end
def project_params
params.require(:project).permit(:name, :description, :organization_id, :unit_id)
end
How can I make this work?
I made it, the solution was pretty simple, but the lack of updated material regarding this simple issue made it a chore bigger than it should have:
config/routes.rb
get 'filter_units_by_organization' => 'projects#filter_units_by_organization'
controllers/projects_controller.rb
def filter_units_by_organization
@filtered_units = Unit.where(organization_id: params[:selected_organization])
end
views/projects/filter_units_by_organization.js.erb
$('select#project_unit_id').html('<%= j options_from_collection_for_select(@filtered_units, :id, :name) %>');
assets/javascripts/application.js
$(function() {
$("select#project_organization_id").on("change", function() {
$.ajax({
url: "/filter_units_by_organization",
type: "GET",
data: { selected_organization: $("select#project_organization_id").val() }
});
});
});
views/projects/_form.html.erb
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :organization_id %><br>
<%= f.collection_select :organization_id, Organization.all, :id, :name, { prompt: 'Please select' } %>
</div>
<div class="field">
<%= f.label :unit_id %><br>
<%= f.collection_select :unit_id, Unit.all.where(organization_id: :organization_id), :id, :name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
Instead of placing an duplicate organization_id
on the projects
table you should set the relationship up to go through the Unit model.
class Organization < ActiveRecord::Base
has_many :units
has_many :projects, through: :units
end
class Unit < ActiveRecord::Base
belongs_to :organization
has_many :projects
end
class Project < ActiveRecord::Base
belongs_to :unit
has_one :organizaton, through: :unit
end
This avoids the awkward issue where you have to ensure that a unit and a project have the same organizaton_id
.
This also means that you no longer need a input to select the organization when creating a Project - just the unit.
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