开发者

How to access associated table attributes in validation before they are saved in Ruby on Rails

开发者 https://www.devze.com 2023-03-09 03:49 出处:网络
I want to be able to skip validation if a certain attribute is set to false, say status,problem is this model has many nested attributes to them, and they need to skip validation too if status is fals

I want to be able to skip validation if a certain attribute is set to false, say status, problem is this model has many nested attributes to them, and they need to skip validation too if status is false.

The purpose of such implantation is that if one wanted to save a draft of there form entry, for whatever reason, having it going through validation could halt them saving it, which is not desirable behavior, and only need to validate entries that are going public by setting status to true.

Example below

attribute status located in Article

model Article
  has_many :sub_articles
  accepts_nested_attributes_for :sub_articles, :allow_destroy => true

  validate_presence_of :body, :unless => Proc.new{|article| !article.status }

model SubArticle
  belongs_to :article
  has_many :foos
  accepts_nested_attributes_for :foos, :allow_destroy => true    

  validate_presence_of :body, :unless => Proc.new{|sub_article| !sub_article.article.status }

model Foo
  belongs_to :sub_article

  validate_presence_of :body, :unless => Proc.new{|foo| !foo.sub_article.article.status }

validation skipping for Article will work, but will not for SubArticle or Foo since they have not been saved an there ids are not set, not making them able to traverse up the associations like in the example.

Is it possible to access associated table attributes at the point of validation?

Any help would be greatly appreciated.

------Updated------

The reason validation for SubArticle and Foo fail is because of a

undefined method `status' for nil:NilClass

This is expected because of the time of validation the article_id or sub_article_id is still nil, I've comfirmed this by doing

model SubArticle
  belongs_to :article
  has_many :foos

  validate_presence_of :body, :unless => Proc.new{|sub_article| !sub_article.article.check_attributes }

def check_attributes
  pp self
end

witch gives

#<SubArticle id: nil, body: "", article_id: nil, created_at: nil, updated_at: nil &开发者_C百科gt;

-----updated 2----------

I forgot and important detail, all of the data for the models are entered at once using a nested form, so at the moment of create, all of the entries on all of the models are only in memory, fixing example code so that would be more obvious.


It is possible but you need to use => instead of =. Like this:

validate_presence_of :body, :unless => Proc.new{|article| !article.status }

Please look at: http://guides.rubyonrails.org/active_record_validations_callbacks.html#conditional-validation for more information about conditional validations.


What about conditionally validating on the ID?

model Article
  has_many :sub_articles

  validate_presence_of :body, :unless => Proc.new{|article| !article.status }

    model SubArticle
      belongs_to :article
      has_many :foos

      validate_presence_of :body, :unless => Proc.new{|sub_article| !sub_article.article_id}

model Foo
  belongs_to :sub_article

  validate_presence_of :body, :unless => Proc.new{|foo| !foo.sub_article_id }

Not sure if this will work but you're essentially only running validation if the parent model has saved and therefore has an ID. Won't work for updates though. Perhaps a mix between this and your original code would do for update?


I've got it working, although hack-ish, solved the can't traverse associations since ids are nil by using the :inverse_of

model Article
  has_many :sub_articles, :inverse_of => :article

  validate_presence_of :body, :unless => Proc.new{|article| !article.status }

model SubArticle
  belongs_to :article, :inverse_of => :sub_articles
  has_many :foos, :inverse_of => :foo

  validate_presence_of :body, :unless => Proc.new{|sub_article| !sub_article.article.status }

model Foo
  belongs_to :sub_article, :inverse_of => :foos

  validate_presence_of :body, :unless => Proc.new{|foo| !foo.sub_article.article.status }

Which will make the instance being examined in all layers have access to the status attribute.

0

精彩评论

暂无评论...
验证码 换一张
取 消