I have a form that lets me create new blog posts and I’d like to be able to create new categories from the same form.
I have a habtm relationship between posts and categories, which is why I’m having trouble with this.
I have the following 2 models:
class Post < ActiveRecord::Base
has_and_belongs_to_many :categories
attr_accessible :title, :body, :category_ids
accepts_nested_attributes_for :categories # should this be singular?
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :posts
attr_accessible :name
end
My form lets me pick from a bunch of existing categories or create a brand new one. My form is as follows.
# using simple_form gem
.inputs
= f.input :title
= f.input :body
# the line below lets me choose from existing categories
= f.association :categories, :label => 'Filed Under'
# I was hoping that the code below would let me create new categories
= f.fields_for :category do |builder|
= builder.label :content, "Name"
= builder.text_field :content
When I submit my form, it gets processed but the new category is not created. My command prompt output tells me:
WARNING: Can't mass-assign protected attributes: category
But, if I add attr_accessible :category, I get a big fat crash with error message “unknown attribute: category”.
If I change the fields_for target to :categories (instead of category) then my form doesn’t even display.
I’ve spent a while trying to figure this out, and watched the recent railscasts on nested_models and simple_form but couldn’t get my problem fixed.
Would this be easier if I was using a has_many :through relationship (with a join model) instead of a habtm?
Thanks to everyone who answered. After much trial and error, I managed to come up with a fix.
First of all, I switched from a HABTM to a has_many :through relationship, calling my join model categorization.rb (instead of categorizations_posts.rb) – NB: the fix detailed below will likely work with a HABTM too:
Step 1: I changed my models to look like this:
From the post model above: obviously, the accessor named :category_ids must be present if you want to enable selecting multiple existing categories, but you do not need an accessor method for creating new categories… I didn’t know that.
Step 2: I changed my view to look like this:
From the view code above, it’s important to note the use of
fields_for :categoryas opposed to the somewhat unintuitivefields_for :categories_attributesStep 3
Finally, I added some code to my controller:
Now, when I create a new post, I can simultaneously choose multiple existing categories from the select menu and create a brand new category at the same time – it’s not a case of one-or-the-other
There is one tiny bug which only occurs when editing and updating existing posts; in this case it won’t let me simultaneously create a new category and select multiple existing categories – if I try to do both at the same time, then only the existing categories are associated with the post, and the brand-new one is rejected (with no error message). But I can get round this by editing the post twice, once to create the new category (which automagically associates it with the post) and then a second time to select some additional existing categories from the menu – like I said this is not a big deal because it all works really well otherwise and my users can adapt to these limits
Anyway, I hope this helps someone.
Amen.