This problem leads to a bunch of code duplication and messy table generation.
So I decided to create associate_with_list, which is a plugin that will manage all of these lists for you, but leaves the front end up to you to make as simple or fancy as you like.
First, get the plugin: http://www.tomonrails.com/docs/associate_with_list.tar.gz
After you've unzipped the plugin, and placed it in your /vendor/plugins directory, from you rails project root, run:
ruby ./vendor/plugins/associate_with_list/install.rb
This will create a migration file and run it. The migration file creates a table in your database which will manage all these lists.
Now the awesome part, tell associate_with_list to associate a column with a list. In your model you need to add the following line:
associate_with_list :tag
You can give it an optional second parameter for the name of list which is helpful if you need to manage the same list across different fields, potentially in different models, or you might want to make sure your list is distinct for other lists you want to create. (NOTE: this plugin will even work with accessors, not just ActiveRecord::Base fields)
To access my new list I now have a new instance method called tag_list which is the column_name + _list, and returns all the previous entries into the list. This is how you use it:
@post.tag_list
You can even pass this method a hash which is used just like a hash passed to ActiveRecord::Base's find method. So for instance if I wanted to define an order in which the list is returned:
class="ruby">
@post.tag_list(:order => 'value')
So where is the magic happening? How are all the values getting stored into this list? The plugin defines an after_save filter which takes the value of the field, after it has been saved, and stores it into the list if it is not already there.
To delete an entry in the list just use the new instance method tag_list_remove which takes a parameter which is the value you wish to remove. E.g.:
@post.remove_from_tag_list 'jungle'
So to recap, lets create a new list for the posted_by field in my post model, and this time I want to define the list name, because I'll use the same list in another model.
post.rb
associate_with_list :posted_by, :author_list
Done!
Now I can use the generated methods posted_by_list and remove_from_posted_by_list to my hearts content.
UPDATE: Also if you wanted to just add values to your list you can use the dynamically generated method add_to_[column_name]_list, which takes a single parameter, which is the value you wish to store. So for instance in the previous example I could do:
add_to_posted_by_list 'tdoggy'
This would check to see if tdoggy was already added to the :author_list (remember we associated posted_by with the author_list), and add it if not.
No comments:
Post a Comment