Associated List - A little "has many" widget for rails

Posted by Craig Ambrose on October 09, 2006 at 02:07 AM

Ok, so I know that I’m not the first person to ever take a stab at a form widget for use in selecting multiple foreign key model objects, but I had a use for this in a project, and perhaps some of you will as well.

If you are producing a form for a rails model object and it has a “has_many” or “has_and_belongs_to_many” relationship of some other simple objects (which can be identified by name), then this plugin might be for you. It uses a select box to add items to the list, and delete buttons to remove them. It’s all client side, using hidden fields, until you submit the form and it saves the relationships in your model.

Don’t listen to me rambling, if you’re interested, Click Here to go look at the demo, then come back and read the rest.

Installing


script/plugin install svn://rubyforge.org/var/svn/ambroseplugins/associated_list

If you install with the rails plugin systems, then it will copy a associated_list.css file into your stylesheets directory. If it’s not there, or you install via some other method, or you’re updating, then do this:


cd vendor/plugins/associated_list/
rake update_scripts

And finally, make sure you include that stylesheet in your layout:


<%= stylesheet_link_tag 'associated_list' %>

Usage

If you have a model @widget of class Widget, that has_and_belongs_to_many :categories, then you simply use the form helper as follows (ie: the same as all the other helpers):


<%= associated_list 'widget', 'categories' %>

When the form is saved, params‘widget’ will contain an array of strings representing integer ids of the categories. Note: This will include one empty string object. This is to ensure that empty lists get saved, just ignore it.

Now, since your model object has a categories= method, but no category_ids= method, you’ll have to create one (in category.rb):


def category_ids=(category_id_array)
self.categories = category_id_array.reject{ |category_id| category_id == '' }.collect { |category_id| WidgetCategory.find(category_id.to_i) }
end

Not how I’m rejecting that empty string. Everything else is pretty straight forward. Really the plugin should extend the rails association helpers to add this method. If anyone wants to code that for me, drop me a line and I’ll patch it into the plugin.

Credits

This plugin was factored out of my railsday project, and so appart from some cleanup work and plugin-ification, it was coded by myself, Nigel Thorne and Simon Hildebrandt. If you use this plugin, please consider them to rock just as thoroughly as I do. :)

Tags: (none)
Hierarchy: previous, next

Comments

There are 12 comments on this post. Post yours →

Why not use blank?

def category_ids=(category_id_array)
self.categories = category_id_array.reject(&:blank?).collect { |category_id| WidgetCategory.find(category_id.to_i) }
end

Craig

Nice one Victor. The answer is, that I didn’t know about :blank? And, I must admit that I only learned about passing procs in as blocks this month, so it’s not an area that I use much. Still, your implementation above is nicer than mine, I like it. :)

This looks like it could come in very handy for a few projects I’ve got going. Thanks for plugify-ing it :)

This looks like it could come in very handy for a few projects I’ve got going. Thanks for plugify-ing it :)

I have created a minor patch for this plugin. It’s a great idea, but a few parts were still very specific to your app. This path adds some configuration options:

Patch pasted here: http://rafb.net/paste/results/iUHAOd95.nln.html

  • :label_method: provide symbol that is the name of the method to be called on the associated object to generate their displayed names. This is necessary because you may not have a method named to_label.
  • :conditions: simply passed into the find method that retrieves the available associated objects. This lets you tailor exactly what records appear in the list.

In my app I can now do this:

:title, 
:conditions =&gt; ['tags.category = ?', true] %&gt;

That patch got nuked somehow.

http://pastie.caboo.se/19139

Jim Scheirer

Great Job Craig and Nice addition Alex. Alex, I have done the same thing as you, but i added :include, :order, :limit, and other find-based config options to allow it to work with a habtm style setup.

Example: You want to have user select which categories they wish to see, so for the habtm (users_categories table) you could call it such as:

:full_name,
:include =&gt; [:users] #habtm lookup
:conditions =&gt; ['user_id = ?', @current_user.id,
:order =&gt; 'categories.name asc' } %&gt;

Note: For those who don’t know, the :to_label (or with alex’s code what you define as :label_method) needs to be located in the model for your lookup table (e.g. Category in the sample above)

This article explains the benefits of playing those free and best casino games. Have fun with casino gambling parties and become an expert player on your own.

Davo

Thanks for the plugin guys! I just have one Q.

You say:

since your model object has a categories= method, but no category_ids= method, you’ll have to create one (in category.rb):

Do you really mean category.rb? or should it be the widget model?

Cheers,
:-Davo

Chris

Thank you for the associated_list helper. I made the modifications suggested by Alex and Jim above, and am already using your helper in our application. This, or a similar helper, is needed in Rails.

offramP

Thanks for this beautiful plugin i have this trouble when launch:

method `reflect_on_association’ for NilClass:Class

Extracted source (around line #1):

1:

My Controllers :

class UsersController “users_votes”
end

class Vote “users_votes”
end

i have user_votes table with user_id and vote_id column.

Sorry I couldn’t see the Demo. It said erer

Post a comment

Required fields in bold.