简体   繁体   中英

Restore Rails callbacks after save(validate:false)

I have a rather complex business logic in a model with associations. I want to allow users to save incomplete (invalid) models for future completion. In my controller, I therefore call instance.save(validate: false) .

Here are the 3 models, that I have extracted from my application. The models may seen overblown, since I extracted only the relevant part.

1) Container model:

class Container < ApplicationRecord
    Languages = %w(fr en de it es)

    belongs_to :name, class_name: "Name", foreign_key: :name_id

    accepts_nested_attributes_for :name

    validates :name, presence: true

    # create an empty model 
    def self.create_new
        c = Container.new

        c.name = Name.new
        c.name.save
        Languages.each do |l|
            c.name.translations << NameItem.new(language: l, text: "")
        end # Languages.each do |l|

        c.description = Description.new
        c.description.save
        Languages.each do |l|
            c.description.translations << DescriptionItem.new(language: l, text: "")
        end # Languages.each do |l|

        c
    end 
end

2) Name model:

class Name < ApplicationRecord
    has_many :translations, class_name: "NameItem", foreign_key: :parent_id

    accepts_nested_attributes_for :translations
end

3) NameItem model:

class NameItem < ApplicationRecord
    validates :language, presence: true
    validate  :text_validation

    private
    def text_validation
        return if language.nil?

        errors.add(:text, :blank_text, language: language) if text.nil? || text.size == 0
    end
end

Given the following sequence of instructions, I am at a loss why the last instruction ( instance.valid? ) returns true. It seems to me that the validation callbacks are disabled, but I'm not sure this is the proper diagnostic. Could this be related to the use of accepts_nested_attributes_for ?:

# create an invalid model (since empty)
instance = Container.create_new

# check that this instance is invalid
instance.valid? # returns false, this is the expected behavior

# save the model, skipping the validations
instance.save(validate: false)

# now instance.valid? will always return true, because it will
# skip the validations. How can I restore the callbacks ?
instance.valid? # returns true, but this is not the desired behavior,
                # hence my question

I tried to disable and re-enable the callbacks with instructions like the following, but to no avail.

[:create, :save, :update].each do |action|
  Container.skip_callback(action)
end

[:create, :save, :update].each do |action|
  Container.set_callback(action)
end

So my question is: after having invoked instance.save(validate: false) , what instructions do I need to run so that instance.valid? does indeed perform the validation checks again and return false ?

Running save(validate: false) doesn't leave callbacks turned off, you must have some other code that runs after save that makes the record pass validation.

Check your before/after_save callbacks, and maybe post the model.

Edit:

Using nested attributes for new records will give you validation trouble, it really works best with existing records as the association doesn't exist properly on a new record. There's a good explanation of this and a workaround in the last paragraph of this answer .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM