Doing Checkbox Adds with HABTM
For some of you this may be a “what?” kind of post. But it’s something that other people playing with the Ruby on Rails framework might be able to use.
I’ve spent a while developing a production pipeline for Meticulous and I am thankful that I am not trying to build this beast in PHP. But Rails is relatively young (and rapidly changing) and that limits the amount of existing info for the newbies in the crowd. So doing an insert to a join table isn’t exactly something they run through in Agile Development with Rails.
So let’s say you’ve been making an app and you have a
has_and_belongs_to_many relationship between two models. For the sake of this exercize, we’re going to use the Manuals model that we’re creating in the Koji Production Pipeline. Manuals would be user manuals. Various manuals generally belong to one department, however, there’s a lot of hardware and software that is shared between departments. We want to be able to show, on the department page, any manuals that belong to it. Simple enough, right?
Your schema/migration would look something like this:
create_table "departments_manuals", :id => false do |t| t.column "manual_id", :integer, :limit => 10, :default => 0, :null => false t.column "department_id", :integer, :limit => 10, :default => 0, :null => false end
and then your models…
class Manual < ActiveRecord::Base has_and_belongs_to_many :departments end class Department < ActiveRecord::Base has_and_belongs_to_many :manuals end
Once this is setup, it’s pretty much view hacking to get this to play nice. In your form partial for manuals (which is used in new and edit for scaffolded code), you basically get something setup that will return a list of departments and an applicable check box.
<p>What Departments should this appear in?</p> <ul> <% Department.find(:all, :order => "name ASC").each do |d| %> <li><%= check_box_tag 'manual[department_ids]', d.id, @manual.departments.include?(d) %> <%= d.name %></li> <% end %> </ul>
check_box_tag is a sexy little piece of code (full details in the api) that basically creates a check box with all the trappings. You can call a
:checked => 1 is you want in the form tag helper and it will auto check the box, but then you’d be assuming that all the boxes in the array were checked.
<li><input id="manual[department_ids]" name="manual[department_ids]" type="checkbox" value="5" />Animation</li> etc. etc.
So basiclaly, the code finds all the departments, orders them by the
:order conditional statement (in this case by name in ascending order) and then loops through each one, echoing a list item with a checkbox followed by the department name.
Simple. Sexy. Took forever to figure out the first time (and a lot of questions in the #ror channel). Anyways. Hopefully that can help someone else out when they run into a similar issue.
Back to the code!