开发者

ActiveModel: Disable failing validation when associated models fail

开发者 https://www.devze.com 2023-03-20 07:14 出处:网络
Does Rails3 always run validates_associated against all models by default? In a simple setup like this

Does Rails3 always run validates_associated against all models by default?

In a simple setup like this

class Post < ActiveRecord::Base
    has_many :comments
end

class Comment < ActiveRecord::Base
    belongs_to :post

    def validate
        errors.add_to_base("its always invalid")
    end
end

A new post with an attached comment fails because the comment is invalid.

a = Post.new
a.comments << Comment.new
a.errors
    => {:comments=>["is invalid"]}

If validates_associated always runs, then why is it there (to change :message?) and how do I turn it off? I have tried validates_associated :comments, :unless => proc{true} but it doesn't do anything.

I simply want a model to save, try to save each associated record if each is valid, but not fail itself if an associated model is invalid.


EDIT: This is closer to what I'm trying to do

# t.string :name
class Game < ActiveRecord::Base
    has_one :wikipedia_paragraph
    has_one :ign_rating

    def name=(_name)
        ret = super
        self.build_wikipedia_paragraph
        self.build_ign_rating
        ret
    end
end


# t.text :paragraph
class WikipediaParagraph < ActiveRecord::Base
    belongs_to :game

    validates_presence_of :paragraph

    def game=(_game)
        ret = super
        self.paragraph = Wikipedia.find(self.game.name)
        ret
    end
end

class IgnRating..

There are more models that follow the same structure as Game, like Book, Movie. If WikipediaParagraph.paragraph == nil then Game fails validation. I would prefer if Game saved and WikipediaParagraph didn't, but has_one :wikipedia_paragraph, :validate => false makes both save, without it neither save.

I was hoping for something more elegant than using

self.build_wikipedia_paragraph
self.wikipedia_paragraph = nil unless self.wikipedia_paragraph.valid?

for every has_one/many but now I realize its probabl开发者_如何学运维y not possible.


Check out the documentation http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many. It shows that a has_many association is validated by default when the parent object is saved. You can set it to false like this:

class Post < ActiveRecord::Base
    has_many :comments, :validate => false
end

I suppose validates_associated could come in handy if you aren't validating an association by default and wanted to handle it yourself. The whole situation is a bit confusing, so I hope that this helps.


Your validations enforce the business logic of your application. If you always want the Post object to save, regardless of the state of the associated comments, you can save posts, and comments independently. This would allow you to iterate over a collection of comments, and try to save each on, continuing if there is an error

post = Post.new
post.valid? # true

comments.each do |comment|
  comment.save # some will some wont
end

I know this doesn't exactly fix your issue as you have describe it, but it may be good to think about why you want to disable validations on an association. The problem with :validate => false on the has_many call is that it will always save without validation, which may not be what you intend.

Is there a more orthodox way to solve this issue while keeping validations present?

0

精彩评论

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