Example: Recently I needed to bash together a quick admin screen with a couple of models. We have an organisation model that belongs_to :region and a Region model that has_many :organisations. This dictates a foreign key in organisation that points at a single region. In our generated Rails forms we enter that as a number, but it'd really be a nicer user experience to select the region from a drop down list right?
Enter collection_select. This little helper generates a selection dropdown from a collection (not surprisingly). So if in my organisation_controller's edit method I return @regions = Region.all we can get instant rails gratification.
Finally, since Edit and New use EXACTLY the same form, we're going to try be DRY and pull all the duplicated code out into a partial. I usually use the default form builder to base it on (you know, "form_for(@organisation) do |f|" ) and call "render :partial => f"
When this renders it looks for the partial pointed at by f, which is a form. so _form.html.erb will be rendered. A final note, even though the partial here will be able to see @regions, I like to explicitly pass it in the locals hash, so I know where the heck it came from in 6 months time. If that's confusing you can just strip out that code and use the global set in the organisation controller. Here's the code:
models/organisation.rb
class Organisation < ActiveRecord::Base
belongs_to :region
end
models/region.rb
class Region< ActiveRecord::Base
has_many :organisations
end
controllers/organisations_controller.rb
class OrganisationsController < ApplicationController
# GET /organisations/new
# GET /organisations/new.xml
def new
@organisation = Organisation.new
@regions = Region.all
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @organisation }
end
end
# GET /organisations/1/edit
def edit
@organisation = Organisation.find(params[:id])
@regions = Region.all
end
end
views/organisations/_form.html.erb
<%= form.error_messages %>
<p>
<%= form.label :org_name %><br />
<%= form.text_field :org_name %>
</p>
<p>
<%= form.label :org_code %><br />
<%= form.text_field :org_code %>
</p>
<p>
<%= form.label :provider %><br />
<%= form.text_field :provider %>
</p>
<p>
<%= form.label :region_id %><br />
<%= collection_select(:organisation, :region_id, regions, :id, :full_name, {:prompt => false}) %>
</p>
views/organisations/edit.html.erb
<% form_for(@organisation) do |f| %>
#:region => regions exposes the regions array as a local variable in the partial
<%= render :partial => f, :locals => { :regions => @regions } %>
<p>
<%= f.submit 'Update' %>
</p>
<% end %>
Thanks! Was just looking for exactly this method!
ReplyDeleteI am surprised this - or at least similar - example is not a part of Ruby on Rails documentation. If it is, it is harder to find.
ReplyDeleteThanks for writing this up. Exactly what I was looking for!
Hmmmm... so simple? I love rails!
ReplyDeleteAwesome, just what I was looking for
ReplyDeletevery useful thanks
ReplyDeleteExactly what I was looking for! Thanks a ton!
ReplyDelete