# HABTM updating/saving behaviour

**URL:** <https://www.ruby-forum.com/t/habtm-updating-saving-behaviour/162696>\
**Category:** Rails\
**Created:** [May 17, 2007, 9:27am UTC](https://www.ruby-forum.com/t/habtm-updating-saving-behaviour/162696 "2007-05-17T09:27:06Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Andrea\_Morandini](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/c6cbf5/32.png) [@Andrea\_Morandini](https://www.ruby-forum.com/u/Andrea_Morandini)\
**Post date:** [May 17, 2007, 9:27am UTC](https://www.ruby-forum.com/t/habtm-updating-saving-behaviour/162696/1 "2007-05-17T09:27:06Z")

</div>

Newbie question (I guess).

I have a User whom can have some Preference. So the scracth model is:

class User \< ActiveRecord:Base  
[…]  
has\_and\_belongs\_to\_many :preferences  
[…]  
end

class Preference \< ActiveRecord:Base  
[…]  
has\_and\_belongs\_to\_many : users  
[…]  
end

In the migration I have created a table preferences\_users with primary  
keys  
preference\_id and user\_id

In the view the choice of which preferences are connected to and user is  
performed by means of a checkbox sets.

In my user\_controller scalffold generated actions “create” and “update”  
I  
added the following lines:

[…]  
params[:preferences].each { |k,v|  
if v == 1 then #if checkbox is checked  
preferences \<\< Preference.find(k)  
end  
}  
[…]  
the user is saved or updated

So I have two question:

1. Is there a better way to perform that check, ot any helper that  
already  
do that task?
2. Actually in the join table preferences\_users nothing is saved. I have  
to  
force the saving ?

---

<div class="post-metadata">

**Author:** ![Andrea\_Morandini](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/c6cbf5/32.png) [@Andrea\_Morandini](https://www.ruby-forum.com/u/Andrea_Morandini)\
**Post date:** [July 28, 2007, 1:34am UTC](https://www.ruby-forum.com/t/habtm-updating-saving-behaviour/162696/2 "2007-07-28T01:34:19Z")

</div>

## The ROR Wiki has a pretty complete solution that might do what you want

[http://wiki.rubyonrails.org/rails/pages/CheckboxHABTM](http://wiki.rubyonrails.org/rails/pages/CheckboxHABTM)

The crux of the matter involves creating a sub-hash of preference\_ids  
that  
is then used to find the preferences and map them to the user. Then  
user.save saves the user and all the dependent preference data. It does  
involve one oddity - you have to use the older style check\_box\_tag  
helper -  
even if the rest of your form is written using form\_for syntax. I did  
some  
searching and experimenting and could not find any way to use the  
check\_box  
helper and constrict the list I would need for mapping.

I followed the directions on the wiki page - and snagged some code from  
an  
older version of ActiveRBAC - and my first attempt worked. However, I am  
trying to add another, practically identical set of checkboxes but the  
mapping isn’t working. Or to be more specific, the log shows that the  
original mappings are deleted, the new mappings are created, AND THEN  
THE  
MAPPINGS ARE DELETED AGAIN!? I cannot for the life of me figure out  
where  
that extra delete is coming from. I tried removing the roles stuff from  
the  
view and controller, but that didn’t make the event mapping work.

development.log

Processing UserController#update (for 131.215.130.72 at 2007-07-27  
14:34:59)  
[POST]  
Session ID: 663471e0ab9cbe10e33b4ce5d4bbffd6  
Parameters: {“user”=\>{“event\_ids”=\>[“1”, “6”], “role\_ids”=\>[“1”, “2”],  
“first\_name”=\>“C”, “last\_name”=\>“K”, “email”=\>“removed\_email\_address@domain.invalid”},  
“commit”=\>“Update”, “action”=\>“update”, “id”=\>“2”,  
“controller”=\>“admin/user”}  
^[[4;35;1mUser Columns (0.002214)^[[0m ^[[0mSHOW FIELDS FROM  
users^[[0m  
^[[4;36;1mUser Load (0.000595)^[[0m ^[[0;1mSELECT \* FROM users WHERE  
(users.`id` = 2) LIMIT 1^[[0m  
^[[4;35;1mRole Columns (0.001494)^[[0m ^[[0mSHOW FIELDS FROM  
roles^[[0m  
^[[4;36;1mRole Load (0.000513)^[[0m ^[[0;1mSELECT \* FROM roles WHERE  
(roles.`rolename` = ‘Admin’) LIMIT 1  
^[[0m  
^[[4;35;1mJoin Table Columns (0.001440)^[[0m ^[[0mSHOW FIELDS FROM  
roles\_users^[[0m  
^[[4;36;1mRole Load (0.000601)^[[0m ^[[0;1mSELECT \* FROM roles INNER  
JOIN roles\_users ON roles.id = roles  
\_users.role\_id WHERE (roles\_users.user\_id = 2 ) ^[[0m  
^[[4;35;1mUser Load (0.000620)^[[0m ^[[0mSELECT \* FROM users WHERE  
(users.`id` = 2) ^[[0m  
^[[4;36;1mJoin Table Columns (0.001443)^[[0m ^[[0;1mSHOW FIELDS FROM  
events\_users^[[0m  
^[[4;35;1mEvent Load (0.000583)^[[0m ^[[0mSELECT \* FROM events INNER  
JOIN events\_users ON events.id = eve  
nts\_users.event\_id WHERE (events\_users.user\_id = 2 ) ^[[0m  
^[[4;36;1mSQL (0.000158)^[[0m ^[[0;1mBEGIN^[[0m  
^[[4;35;1mSQL (0.000139)^[[0m ^[[0mCOMMIT^[[0m  
CNK after collecting all the role and event info but before  
update\_attributes  
^[[4;36;1mEvent Columns (0.001768)^[[0m ^[[0;1mSHOW FIELDS FROM  
events^[[0m  
^[[4;35;1mEvent Load (0.000623)^[[0m ^[[0mSELECT \* FROM events WHERE  
(events.`id` IN (1,6)) ^[[0m  
^[[4;36;1mSQL (0.000163)^[[0m ^[[0;1mBEGIN^[[0m  
^[[4;35;1mevents\_users Columns (0.001388)^[[0m ^[[0mSHOW FIELDS FROM  
events\_users^[[0m  
^[[4;36;1mSQL (0.000391)^[[0m ^[[0;1mINSERT INTO events\_users  
(`event_id`, `user_id`) VALUES (1, 2)^[[0m  
^[[4;35;1mevents\_users Columns (0.001350)^[[0m ^[[0mSHOW FIELDS FROM  
events\_users^[[0m  
^[[4;36;1mSQL (0.000362)^[[0m ^[[0;1mINSERT INTO events\_users  
(`event_id`, `user_id`) VALUES (6, 2)^[[0m  
^[[4;35;1mSQL (0.004550)^[[0m ^[[0mCOMMIT^[[0m  
^[[4;36;1mRole Load (0.000557)^[[0m ^[[0;1mSELECT \* FROM roles WHERE  
(roles.`id` IN (1,2)) ^[[0m  
^[[4;35;1mJoin Table Columns (0.001406)^[[0m ^[[0mSHOW FIELDS FROM  
roles\_users^[[0m  
^[[4;36;1mRole Load (0.000636)^[[0m ^[[0;1mSELECT \* FROM roles INNER  
JOIN roles\_users ON roles.id = roles  
\_users.role\_id WHERE (roles\_users.user\_id = 2 ) ^[[0m  
^[[4;35;1mSQL (0.000164)^[[0m ^[[0mBEGIN^[[0m  
^[[4;36;1mSQL (0.000153)^[[0m ^[[0;1mCOMMIT^[[0m  
^[[4;35;1mSQL (0.000138)^[[0m ^[[0mBEGIN^[[0m  
^[[4;36;1mSQL (0.000444)^[[0m ^[[0;1mDELETE FROM events\_users WHERE  
user\_id = 2 AND event\_id IN (1,6)^[[0  
m  
^[[4;35;1mSQL (0.000612)^[[0m ^[[0mCOMMIT^[[0m  
^[[4;36;1mSQL (0.000159)^[[0m ^[[0;1mBEGIN^[[0m  
^[[4;35;1mUser Load (0.000810)^[[0m ^[[0mSELECT \* FROM users WHERE  
(LOWER(users.email) = 'removed\_email\_address@domain.invalid   
AND users.id \<\> 2) LIMIT 1^[[0m  
^[[4;36;1mUser Update (0.000581)^[[0m ^[[0;1mUPDATE users SET  
`created_at` = ‘2007-07-10 16:25:56’, `last_name` = 'K, `first_name` =  
'C,  
`email` = 'removed\_email\_address@domain.invalid, `updated_at` = ‘2007-07-27 14:34:59’ WHERE  
`id`  
= 2^[[0m  
^[[4;35;1mSQL (0.000540)^[[0m ^[[0mCOMMIT^[[0m  
Redirected to http://

The models:

class User \< ActiveRecord::Base  
has\_and\_belongs\_to\_many :roles  
has\_and\_belongs\_to\_many :events  
…  
end

class Event \< ActiveRecord::Base  
has\_and\_belongs\_to\_many :users  
…  
end

The view:

\<% form\_for :user do |f| %\>  
…

## Roles

\<% for role in Role.find(:all) %\> \<%= check\_box\_tag "user[role\_ids][]", "#{role.id}", current\_role?(role) %\> \<%= role.rolename %\> \<% end %\>

## Events

\<% for event in Event.find(:all, :conditions =\> "signup = true") %\> \<%= check\_box\_tag "user[event\_ids][]", "#{event.id}", current\_event?(event) %\> \<%= event.title %\> \<% end %\>

\<%= submit\_tag 'Update' %\>

\<% end %\>

Helpers - to get the current roles/events checked:

module Admin::UserHelper

def current\_role?(role)  
if @user  
@user.roles.include?(role)  
else  
false  
end  
end

def current\_event?(event)  
if @user  
@user.events.include?(event)  
else  
false  
end  
end

end

And the controller:

class Admin::UserController \< ApplicationController  
require\_dependency ‘user’

def update  
@user = User.find(params[:id].to\_i)  
if request.post?  
# get an array of roles and set the role associations  
params[:user][:roles] = [] if params[:user][:roles].nil?  
roles = params[:user][:roles].collect { |i| Role.find(i) }  
@user.roles = roles

```
  # get an array of events and set the event associations
  params[:user][:events] = [] if params[:user][:events].nil?
  events = params[:user][:events].collect { |i| Event.find(i) }
  @user.events = events

  if @user.update_attributes(params[:user])
    redirect_to :action => "show", :id => @user.id
  end
end

```

end  
end
