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:
profile.lifestyle_ids = [1,2]
And this obviously works for forms if you've set the attr_accessible for lifestyle_ids:
class Profile < ActiveRecord::Base
attr_accessible :lifestyle_ids
end
In ActiveAdmin, because it uses Formtastic, you can use this method to output the correct fields (in this case checkboxes):
f.input :lifestyles, as: :check_boxes, collection: Lifestyle.all
Also, I have simplified my form view so it's now merely this:
form do |f|
f.inputs # Include the default inputs
f.inputs "Lifestlyes" do # Make a panel that holds inputs for lifestyles
f.input :lifestyles, as: :check_boxes, collection: Lifestyle.all # Use formtastic to output my collection of checkboxes
end
f.actions # Include the default actions
end
Ok, now this rendered perfectly in the view, but if I try and submit my changes, it gives me this database error:
PG::Error: ERROR: null value in column "created_at" violates not-null constraint
: INSERT INTO "lifestyles_profiles" ("profile_id", "lifestyle_id") VALUES (2, 1) RETURNING "id"
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 a has_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 of lifestyles
from profiles
, which I don't think is particularly useful when using active admin (just modify lifestyles
directly).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With