Predefined models? No different than any others.
Earlier today I was trying to figure out how to make a list of potential models to be created. For example: I have some User
s and some Group
s. I have a many-to-many Membership
join model with some has_many :through
s. The fundamental goal is to provide the user an interface to add Membership models that link a User
to a Group
. I could use a bunch of checkboxes, but I’d rather pull up a list of possible Group
s with little “add” links next to them.
Since I’m using RESTful controllers, we have a MembershipsController
that implements all the standard methods. We’re also nesting our routes such that MembershipsController
nested beneath the UsersController
. In order to create the Membership, we need to POST to /users/1/memberships. But how do we get a list of Membership
s that we can quickly add?
How about modifying MembershipsController.new
? We don’t need the normal definition of new
, since we’re never going to be manually creating a new Membership.
# controllers/memberships_controller.rb
def new
@memberships = Groups.find(:all).collect do |group|
Membership.new(:user_id => params[:user_id], :group_id => group.id)
end
end
Now we have a list of potential Membership
objects available to our view. Remember, the Membership
s haven’t been saved yet. They’re just there for convenience for holding attributes. We are doing object-oriented programming after all.
# views/memberships/new.html.erb
<% @memberships.each do |membership| %>
<% form_for :membership, membership, :url => memberships_path do |f| %>
<%= f.hidden_field :user_id %>
<%= f.hidden_field :group_id %>
<%= f.submit membership.group.name %>
<% end %>
<% end %>
Basically what we have here is a big list of predefined join models wrapped up in form tags. When you click on one of them, you’ll end up submitting the form that actually creates the model. Eventually, we could make this into an AJAX widget that uses form_remote_for
with very little effort.
Nothing I have described here is particularly revolutionary. Rather than just returning a single new Membership
in the new
method, we return a list of objects. Rather than rendering one form with editable fields, we render multiple forms with predefined, hidden fields. Whichever you submit creates the corresponding object. These two very simple changes to the standard REST actions allow us to easily and elegantly create our join models.