Можете ли вы сбросить экземпляр ActiveRecord, если его проверка не удалась?

Допустим, у вас есть пользователь с атрибутом возраста, который не может быть отрицательным.

class User < ActiveRecord::Base
  validates :age, numericality: { greater_than: 0 }
end

Если вы попытаетесь обновить атрибуты до отрицательного числа, проверка не удастся, но экземпляр по-прежнему будет иметь отрицательное значение возраста.

#<User id: 1, age: 5, created_at: "2014-11-08 20:14:12", updated_at: "2014-11-08 20:14:12">
user.update_attributes!(:age => -5)
#<User id: 1, age: -5, created_at: "2014-11-08 20:14:12", updated_at: "2014-11-08 20:14:12">

Помимо перехвата ActiveRecord :: RecordInvalid и самостоятельного сброса значения - это способ сбросить экземпляр, если его проверки не пройдут?

Благодарность!


person kreek    schedule 08.11.2014    source источник


Ответы (2)


Вы можете позвонить model.reload, если проверка не удалась. Это будет выглядеть примерно так:

if @model.update_attributes(age: params[:age]) # params[:age] = -5 for example
  # model is valid and saved, continue...
else # update_attributes return false and will not raise an exception if model is invalid
  # model is invalid, reloading...
  @model.reload
  # if we call @model.age now, it will return previous value
end

В любом случае update_attributes установит атрибуты, даже если модель станет недействительной после этого обновления, хотя недопустимые атрибуты сохранятся в базе данных. Но помните, что он сбросит все другие изменения, которые могли быть выполнены внутри этого вызова, поэтому update_attributes(name: params[:name], age: params[age]) сбросит и имя, и возраст, даже если имя является допустимым.

person Felix Borzik    schedule 08.11.2014

Я бы сказал, что вам нужен собственный валидатор, например:

class MyValidator < ActiveModel::Validator

  def validate(record)
    unless record.age.to_i > 0
      record.errors[:name] << 'Invalid!'
      record.age = record.age_was # Rewrite new with old value
    end
  end
end

class Person
  include ActiveModel::Validations
  validates_with MyValidator
end

С ActiveModel::Dirty перезагружать не нужно.

person blelump    schedule 08.11.2014