Sorry to resurrect the dead, but I found a much simpler solution that lets one use the default controller action code and use the ActiveModel setter logic for a has_many. Yes, it's totally magic.
<%= f.select :category_ids, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>
Specifically, using the :category_ids (or :your_collection_ids) param name will automagically tell Rails to call
@post.category_ids = params[:post][:category_ids]
to set the categories for that post accordingly, all without modifying the default controller/scaffold #create and #update code.
Oh, and it works with has_many :something, through: :something_else
automatically managing the join model. Freaking awesome.
So from the OP, just change the field/param name to :category_ids
instead of :categories
.
This will also automatically have the model's selected categories populate the select field as highlighted when on an edit form.
References:
From the has_many API docs where I found this.
Also the warning from the form helpers guide explains this "type mismatch" when not using the proper form-field/parameter name.
By using the proper form-field/param name, you can dry up new and edit forms and keep the controllers thin, as encouraged by the Rails way.
note for rails 4 and strong parameters:
def post_params
params.require(:post).permit(:title, :body, category_ids: [])
end
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…