Topic: array/table style form with checkboxes

I am looking for a railesque solution for following situation:

I have an array of permissions and an array of roles.
Each role can have 0-n permissions. Each permission can belong to 0-n roles.

To assign permissions to roles i display a form with two dimensional array of checkboxes (roles on the x-axis, permissions on the y-axis).

I see following solutions for this form:

- with AJAX: onClick/onChange handler to send
id=<%=role.id%>_<%=perm.id%>
and if it is checked or unchecked
to the controller. the controller can figure out role and permission, handles assignment/removal and returns just the new checkbox trough a partial

- with Submit button: give the checkboxes a name like
role_<%=role.id%>
and a value of <%=perm.id%>
. In the controller loop trough all roles and get the according parameters. Get the permissions and assign to role.


especialy the second example seems to complicated and i think there is something easier (i.e. arrays ?)

thanks for hints and ideas...

pascal

Re: array/table style form with checkboxes

I'm assuming the two models have a has_and_belongs_to_many association? (instead of has_many :through). In that case the Role model will have a "permission_ids=" method for setting the permissions. It expects an array of ids. If you make the checkboxes like this:

<% for role in @roles %>
  <% for permission in role.permissions %>
    <%= check_box_tag "roles[#{role.id}][permission_ids][]", permission.id, role.permissions.include?(permission) %>
  <% end %>
<% end %>

You can loop through the roles in the controller and update it:

def update
  params[:roles].each do |id, role_attr|
    Role.update(id, role_attr)
  end
end

Untested.

Railscasts - Free Ruby on Rails Screencasts

Re: array/table style form with checkboxes

hey thanks for the reply... yes it's a HABTM relationship.
I will take a look at your solution ASAP (doing ugly Java stuff at work right now :-) )

pascal

Last edited by pascal (2006-12-19 19:19:23)

Re: array/table style form with checkboxes

One problem you may come across is when leaving all checkboxes unchecked. This will cause none of the checkbox values to be sent, so the params[:roles] hash will be missing some roles (if none are checked). Instead you'll probably want to loop through the roles from the database then fetch the referenced role from the params. If you can't find it, default to an empty array for permissions_id. I can post some code if you need it.

Railscasts - Free Ruby on Rails Screencasts

Re: array/table style form with checkboxes

Ok, i found the time to check out your solution. And i did not get to work that way...

     Role.update(id, role_attr)

did not work, because of a "unknown method permission_ids". (I am  back in my office and do not ave the Rails code here. So i don't know the exact message)

I assume this is because it's actualy the join table (it's a many-to-many relationship) that has the permission_id/role_id columns ?

i managed to solve the problem by loading the Role and the Permissions and then associate them and update the Role....

but i am sure there is an easier way (as i am just learning ruby/rails i have to discover the patterns used) ... will look into it again this evening and then post some code.

and yes, i had to init the array when no checkbox was checked. thanks.


pascal

Re: array/table style form with checkboxes

Was the unknown method with an equal sign? "permission_ids=". If so, are you certain the association is has_and_belongs_to_many and not has_many :through? Hmmm, that's weird. You may want to try playing with the model in script/console and see if you can set the permissions:

role = Role.find(:first)
role.permission_ids = [1, 2]

Railscasts - Free Ruby on Rails Screencasts

Re: array/table style form with checkboxes

Ryan

tried again and now it works like a charm. probably i had a type in the naming of the checkboxes.

thanks for your help

pascal

Re: array/table style form with checkboxes

and again....

i will probably move the name of the property to update (permission_ids) from html to the controller to prevent malicious users messing with my model.

pascal