Using Rails 4.1.13 and Ruby 2.0.0 (although I had the same problem with Ralis 4.0 and Ruby 1.9.3. I have read numerous articles about this particular issue and cannot understand why my solution (which seems exactly like this) does not work, so please help me out.
I have two models BlogPost and Tag. A BlogPost can have many Tags and one Tag can have many BlogPosts. I connect them through a third model BlogPostRelation. Thus, this is my basic setup:
# blog_post.rb
has_many :blog_post_tag_relations, dependent: :destroy
has_many :tags, :through => :blog_post_tag_relations
accepts_nested_attributes_for :blog_post_tag_relations, :tags
# tag.rb
has_many :blog_post_tag_relations, dependent: :destroy
has_many :blog_posts, :through => :blog_post_tag_relations
# blog_post_tag_relation.rb
belongs_to :tag
belongs_to :blog_post
validates_uniqueness_of :tag_id, :scope => [:blog_post_id]
validates :blog_post_id, :presence => true
validates :tag_id, :presence => true
accepts_nested_attributes_for :tag, :blog_post
I have a form for BlogPost, using Formtastic, where I create checkboxes for the BlogPost using:
<%= f.input :blog_title %>
<%= f.input :tags, as: :check_boxes, :collection => tags.order(:name) %>
The problem I have is that BlogPost is not saved before the Tags are added which causes an validation failure of blog_post_id not being present (which it isn't):
Tag Load (1.6ms) SELECT "tags".* FROM "tags" WHERE "tags"."id" IN (678, 56)
(0.9ms) BEGIN
BlogPost Exists (1.6ms) SELECT 1 AS one FROM "blog_posts" WHERE ("blog_posts"."id" IS NOT NULL) AND "blog_posts"."slug" = 'de22323' LIMIT 1
BlogPostTagRelation Exists (1.2ms) SELECT 1 AS one FROM "blog_post_tag_relations" WHERE ("blog_post_tag_relations"."tag_id" = 678 AND "blog_post_tag_relations"."blog_post_id" IS NULL) LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "blog_posts" WHERE ("blog_posts"."id" IS NOT NULL) AND "blog_posts"."slug" = 'de22323' LIMIT 1
BlogPostTagRelation Exists (1.1ms) SELECT 1 AS one FROM "blog_post_tag_relations" WHERE ("blog_post_tag_relations"."tag_id" = 56 AND "blog_post_tag_relations"."blog_post_id" IS NULL) LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "blog_posts" WHERE ("blog_posts"."id" IS NOT NULL) AND "blog_posts"."slug" = 'de22323' LIMIT 1
(0.8ms) ROLLBACK
It seems like the solution should be to use inverse_of
, which I frankly don't understand to 100%. It should also be mentioned that I am not 100% sure on how to use accepts_nested_attributes_for
either for this type of issue. I have tried all different setups but as far as I understand the only place they should be is in the join model, BlogPostRelation, like this:
# blog_post_tag_relation.rb
belongs_to :tag, :inverse_of => :blog_post_tag_relations
belongs_to :blog_post, :inverse_of => :blog_post_tag_relations
validates_uniqueness_of :tag_id, :scope => [:blog_post_id]
validates :blog_post_id, :presence => true
validates :tag_id, :presence => true
accepts_nested_attributes_for :tag, :blog_post
This doesn't work either and I am completely lost now in what to do.
- Most important: What should I do?
- Is inverse_of the solution to this problem? If so, how should I use it?
- Am I using accepts_nested_attributes_for correctly?
- Does it have to do with the naming of BlogPostTagRelation (should it have been called BlogPostTag instead?