user12882
user12882

Reputation: 4792

Trouble with accepts_nested_attributes_for on validating foreign key

I am using Ruby on Rails v3.2.2. I would like to solve the issue related to the validation of a foreign key when using accepts_nested_attributes_for and validates_associated RoR methods. That is, I have following model classes:

class Article < ActiveRecord::Base
  has_many :category_associations, :foreign_key => 'category_id'

  accepts_nested_attributes_for :category_associations, :reject_if => lambda { |attributes| attributes[:category_id].blank? }
  validates_associated :category_associations
end

class CategoryAssociation < ActiveRecord::Base
  belongs_to :article, :foreign_key => 'article_id'
  belongs_to :category, :foreign_key => 'category_id'

  validates :article_id, :presence => true
  validates :category_id, :presence => true
end

... and I have following controller actions:

class ArticlesController < ApplicationController
  def new
    @article = Article.new
    5.times { @article.category_associations.build }

    # ...
  end

 def create
   @article = Article.new(params[:article])

   if @article.save
     # ...
   else
     # ...
   end
 end
end

With the above code ("inspired" by the Nested Model Form Part 1 Rails Cast) my intent is to store category associations when creating an article (note: category objects are already present in the database; in my case, I would like just storing-creating category associations). However, when I submit the related form from the related view file, I get the following error (I am logging error messages):

{:"category_associations.article_id"=>["can't be blank"], :category_associations=>["is invalid"]}

Why it happens since validates_associated seems to run the method article.category_association.valid? but only if the article.category_association.article_id is not nil? How can I solve the problem with the presence validation of the article_id foreign key?

However, if I comment out the validates :article_id, :presence => true in the CategoryAssociation model class, it works as expected but it seems to be not a right approach to do not validate foreign keys.


If I comment out the validates_associated :category_associations in the Article model class, I still get the error:

{:"category_associations.article_id"=>["can't be blank"]}

Upvotes: 30

Views: 8782

Answers (4)

Lucas Correa
Lucas Correa

Reputation: 1

If you're stucked with this kind of errors too, try to replace:

validates :article_id, :presence => true
validates :category_id, :presence => true

with:

validates :article, :presence => true
validates :category, :presence => true

worked for me.

Upvotes: 0

Arctodus
Arctodus

Reputation: 5847

Use inverse_of to link the associations and then validate the presence of the associated object, not the presence of the actual foreign key.

Example from the docs:

class Member < ActiveRecord::Base
  has_many :posts, inverse_of: :member
  accepts_nested_attributes_for :posts
end

class Post < ActiveRecord::Base
  belongs_to :member, inverse_of: :posts
  validates_presence_of :member
end

Upvotes: 45

user1322092
user1322092

Reputation: 4270

Since you have a possible nested form with accepts_nested_attributes_for, therefore in CategoryAssociation you need to make the validation conditional, requiring presence for only for only updates:

validates :article_id, presence: true, on: :update

Aside from Active Record associations, you should have a foreign key constraints at the db level.

Upvotes: 0

ian
ian

Reputation: 12251

Validations will run on create or save (as you'd expect), so ask yourself, "at each one of those is there a saved instance being referred to?", because without a save an instance won't have an id as it's the database that assigns the id.


Edit: Like I've said in the comments, if you're going to downvote then leave a comment as to why.

Upvotes: -2

Related Questions