I have a very simple model
class Lifestyle < ActiveRecord::Base
attr_accessible :name
has_and_belongs_to_many :profiles
end
that has a has_and_belongs_to_many
relationship with Profile
class Profile < ActiveRecord::Base
attr_accessible ...
belongs_to :occupation
has_and_belongs_to_many :lifestyles
accepts_nested_attributes_for :lifestyles
end
I want to use ActiveAdmin to edit the Profile object, but also assign Lifestyles to a profile. It should be similar to dealing with belongs_to :occupation
, as this is sorted out automatically by ActiveAdmin to a dropbox with the options pre-filled with available occupations.
I've tried to use the has_many
form builder method, but that only got me to show a form to type in the name of the Lifestyle and on submission, it returned an error.
f.object.lifestyles.build
f.has_many :lifestyles do |l|
l.input :name
end
Error I get:
Can't mass-assign protected attributes: lifestyles_attributes
The perfect way for me would be to build several checkboxes, one for each Lifestyle in the DB. Selected means that the lifestyle is connected to the profile, and unselected means to delete the relation.
I'm having great doubts that this is possible using ActiveAdmin and without having to create very complex logic to deal with this. I would really appreciate it if you'd give your opinion and advise me if I should go this way or approach it differently.
After some research, I am ready to answer my own question.
First, I have to say thanks to @Lichtamberg for suggesting the fix. However, that only complicates things (also regarding security, though not an issue in this case), and doesn't help me reach my ideal solution.
Digging more, I found out that this is a very common scenario in Rails, and it's actually explained in Ryan Bates' screencast no #17.
Therefore, in Rails, if you have a has_and_belongs_to_many (short form HABTM) association, you can easily set the ids of the other associated object through this method:
And this obviously works for forms if you've set the attr_accessible for lifestyle_ids:
In ActiveAdmin, because it uses Formtastic, you can use this method to output the correct fields (in this case checkboxes):
Also, I have simplified my form view so it's now merely this:
Ok, now this rendered perfectly in the view, but if I try and submit my changes, it gives me this database error:
I found out that this is due to the fact that Rails 3.2 doesn't automatically update the timestamps for a HABTM association table (because they are extra attributes, and Rails only handles the
_id
attributes.There are 2 solutions to fix this:
has_many, :through =>
)I'm going to go for 2) because I will never need the timestamps or any extra attributes.
I hope this helps other people having the same problems.
Edit: @cdesrosiers was closest to the solution but I already wrote this answer before I read his. Anyway, this is great nevertheless. I'm learning a lot.
Active Admin creates a thin DSL (Domain-Specific Language) over formtastic, so it's best to look at the formastic doc when you need form customization. There, you'll find that you might be able to use
f.input :lifestyles, :as => :check_boxes
to modify ahas_and_belongs_to_many
relationship.I say "might" because I haven't tried this helper myself for your particular case, but these things have a tendency to just work automagically, so try it out.
Also, you probably won't need
accepts_nested_attributes_for :lifestyles
unless you actually want to modify the attributes oflifestyles
fromprofiles
, which I don't think is particularly useful when using active admin (just modifylifestyles
directly).Add
f.e.: