I am having trouble figuring out how to make a nested form using a has_many :through relationship. I used this Railscast and I took at look at this tutorial and lots of the questions on Stack Overflow and elsewhere around Google.
I'm trying to make a way to create tags via the articles form. My code has gone through lots of iterations based on information from lots of different sources and none of them have worked, but right now I have
A class for articles
class Article < ActiveRecord::Base
attr_accessible :content, :heading, :image, :tag_ids, :tags, :tag_name, :tag_attributes
belongs_to :user
has_many :comments, :dependent => :destroy
has_many :article_tags
has_many :tags, :through => :article_tags
accepts_nested_attributes_for :tags, :reject_if => proc { |attributes| attributes['tag_name'].blank? }
...
end
A class for tags
class Tag < ActiveRecord::Base
attr_accessible :tag_name
has_many :article_tags
has_many :articles, :through => :article_tags
end
A class for article_tags
class ArticleTag < ActiveRecord::Base
belongs_to :article
belongs_to :tag
end
The New in my articles_controller.rb is like this:
def new
@article = Article.new
@tags = Tag.find(:all)
article_tag = @article.article_tags.build()
@article_tags = @article.tags.all
@article.article_tags.build.build_tag
3.times do
article_tag = @article.article_tags.build()
end
end
And my form for articles is currently like this (I have gone back and forth between nesting the fields_for :tags inside the fields_for :article_tags or just letting them be on their own):
<%= form_for @article , :html => { :multipart => true } do |f| %>
...excerpted...
<%= f.fields_for :article_tags do |t| %>
<%= t.fields_for :tags do |ta| %>
<%= ta.label :tag_name, "Tag name" %>
<%= ta.text_field :tag_name %>
<% end %>
<% end %>
I realize this is probably messy; I'm pretty new at this and I'm trying to figure it out. Do I have to add anything to the articles_controller create? Is it something to do with the attr_accessible? Or should I do something completely different?
EDIT:
Here are the request parameters after making the change suggest开发者_运维百科ed by Hck and creating a new article, selecting an existing tag with tag_id 3 and trying to also create a new tag at the same time:
Started POST "/articles" for 127.0.0.1 at 2011-08-10 19:05:46 +1000 Processing by ArticlesController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"5CQuV4RWfFZD1uDjv1DrZbIe+GB/sDQ6yiAETZutmZ4=", "article"=>{"heading"=>"Test heading", "content"=>"Test Content", "tag_ids"=>["3"], "article_tags"=>{"tags"=>{"tag_name"=>"Test tag"}}}, "commit"=>"Submit"} User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1 WARNING: Can't mass-assign protected attributes: article_tags Tag Load (0.4ms) SELECT "tags".* FROM "tags" WHERE "tags"."id" = 3 LIMIT 1 AREL (0.4ms) INSERT INTO "articles" ("content", "user_id", "created_at", "updated_at", "heading", "image_file_name", "image_content_type", "image_file_size") VALUES ('Test Content', 1, '2011-08-10 09:05:46.228951', '2011-08-10 09:05:46.228951', 'Test heading', NULL, NULL, NULL) AREL (0.2ms) INSERT INTO "article_tags" ("article_id", "tag_id", "created_at", "updated_at") VALUES (88, 3, '2011-08-10 09:05:46.243076', '2011-08-10 09:05:46.243076') [paperclip] Saving attachments. Redirected to [localhost] Completed 302 Found in 212ms
And if I add :article_tags to the attr_accessible for Article and try again, I get:
Started POST "/articles" for 127.0.0.1 at 2011-08-10 19:11:49 +1000 Processing by ArticlesController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"5CQuV4RWfFZD1uDjv1DrZbIe+GB/sDQ6yiAETZutmZ4=", "article"=>{"heading"=>"Test heading", "content"=>"Test content", "tag_ids"=>["3"], "article_tags"=>{"tags"=>{"tag_name"=>"Test tag "}}}, "commit"=>"Submit"} User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1 Tag Load (0.4ms) SELECT "tags".* FROM "tags" WHERE "tags"."id" = 3 LIMIT 1 Completed in 119ms
ActiveRecord::AssociationTypeMismatch (ArticleTag(#2165285820) expected, got Array(#2151973780)): app/controllers/articles_controller.rb:32:in `create'
Try to replace @article.article_tags.build.build_tag
with @article.tags.build
in your controller`s action.
I don't think you have to nest the article tags in it too. Article tags is just an association between the articles and tags. You can simply create the new tag within the articles because you already associated with them. I believe it is from the magic of the "accepts_nested_attributes". try this.
<%= form_for @article , :html => { :multipart => true } do |f| %>
...excerpted...
<%= f.fields_for :tags, Tag.new do |t| %>
<%= t.label :tag_name, "Tag name" %>
<%= t.text_field :name %>
<% end %>
<% end %>
Also, you should try to mass assign it instead of saving every attribute piece by piece by using private params. I had a nested forms problem before too, so you can take a look at how I wrote my code: Cannot save record to database RAILS nested forms
The only thing I left out there was the private params section, which I recommended you to do.
private
def venue_params
params.require(:venue).permit(:name, :address, :discount, :latitude, :longitude, :tags_attributes =>[:name],:tag_ids => [])
end
I also wrote a blog post about nested forms, so you can take a look at it too
http://minling.github.io/
精彩评论