Checkbox list in Ruby on Rails using HABTM

Checkboxes are one of those things that look easy and should be easy, but they aren't always easy. I needed a solution that could create a checkbox list of languages that a user speaks. So I don't forget here's how to do it:

The migrations are important. You have to be sure to exclude the id parameter when you create languages_users or you will get ' Mysql::Error: #23000Duplicate entry' due to the fact that ActiveRecord will try to store a value in the id field that indicates which model created the entry (User.languages false, :force => true do |t|

5.              t.integer :user_id

6.              t.integer :language_id

7.              t.timestamps

8.          end

9.      end

10.  

11.     def self.down

12.         drop_table :languages_users

13.     end

14. end

15.  

1.   

2.  class Languages < ActiveRecord::Migration

3.  &nbsp;

4.      def self.up

5.          create_table "languages", :force => true do |t|

6.              t.string  "name"

7.              t.string  "english_name"

8.              t.integer "is_default", :default => 

9.          end

10.     end

11. &nbsp;

12.     def self.down

13.         drop_table "languages"

14.         drop_table "users_languages"

15.     end

16. end

17. &nbsp;

1.  &nbsp;

2.  class Users < ActiveRecord::Migration

3.  &nbsp;

4.      def self.up

5.          create_table "users", :force => true do |t|

6.              t.string  "login"

7.              # other fields excluded for brevity

8.          end

9.      end

10. &nbsp;

11.     def self.down

12.         drop_table "users"

13.     end

14. end

15. &nbsp;

Here are my models:
user.rb

1.  &nbsp;

2.  class User < ActiveRecord::Base

3.      has_and_belongs_to_many :languages

4.  end

5.  &nbsp;

language.rb:

1.  &nbsp;

2.  class Language < ActiveRecord::Base

3.    has_and_belongs_to_many :users

4.  end

5.  &nbsp;

In my user_controller.rb the create and update methods are simple. This is thanks to the fact that you get a language_ids method on the user object because of the HABTM relationship.

1.  &nbsp;

2.      def create

3.          @user = User.new&#40;params&#91;:user&#93;&#41;

4.          @user.save

5.      end

6.  &nbsp;

7.      def update

8.          params&#91;:user&#93;&#91;:language_ids&#93; ||= &#91;&#93;

9.  &nbsp;

10.         @user = User.find&#40;current_user&#41;

11. &nbsp;

12.         if @user.update_attributes params&#91;:user&#93;

13.             flash&#91;:notice&#93; = "Settings have been saved."

14.             redirect_to edit_user_url&#40;@user&#41;

15.         else

16.             flash.now&#91;:error&#93; = @user.errors

17.             setup_form_values

18.             respond_to do |format|

19.                 format.html &#123; render :action => :edit&#125;

20.             end

21.         end

22. &nbsp;

23.     end

24. &nbsp;

On to the view:

1.  &nbsp;

2.  

3.    

4.   

5.    

6.  

7.  &nbsp;

NOTE: I had an error in my original method. This code:

1.  &nbsp;

2.   user_speaks_language?&#40;language&#41;&#125;, "#{language.id}", ""  -%> 

3.  &nbsp;

should be this:

1.  &nbsp;

2.   

3.  &nbsp;

And we'll need this helper method:

1.  &nbsp;

2.  def user_speaks_language?&#40;language&#41;

3.      if @user && !@user.login.nil? # no sense in testing new users that have no languages

4.          @user.languages.include?&#40;language&#41;

5.      else

6.          false

7.      end

8.  end

9.  &nbsp;

The result is that you will get a list of check boxes that update values in the join table that is part of the has_and_belongs_to_many relationship. Rails is very cool

Comments

blog comments powered by Disqus