Gre*_*sen 5 forms oop validation activerecord ruby-on-rails
在处理Form对象和常规Rails模型时,基本验证器在哪里?
遵循从Rails中的持久层解耦表单的概念.我已经设置了一个Form对象Cage,它可以一起创建两个对象...说Animal和Plant.
以下表格对象示例来自http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/或https://github.com/solnic/virtus或https://github.com/makandra/active_type,每个都表明Form对象本身有验证......没问题......部分好处包括能够以更加上下文的方式验证对象.
问题:
class Animal < ActiveRecord::Base
  validates :color, presence: true
  validate :only_one_brown
  private
  def only_one_brown
    if some_complex_thing
      errors.add(:color, 'can not have more than one brown animal.')
    end
  end
end
class Plant < ActiveRecord::Base
  validates :color, presence: true
end
class Cage
  include Virtus.model # or ActiveType or whatever
  include ActiveModel::Validations
  attribute :bird_color, String
  attribute :plant_color, String
  validates :bird_color, presence: true
  validates :plant_color, presence: true
  def save
    if valid?
      animal.save!
      plant.save!
      true
    else
      false
    end
  end
  def animal
    @animal ||= Animal.new(color: bird_color)
  end
  def plant
    @plant ||= Plant.new(color: plant_color)
  end
end
如何在没有以下情况下验证动物的"只有一条褐色"规则:
如果我们不重复验证代码,当"只有一个棕色"为假时,Cage没有错误...我们会提高,这需要控制器捕获和处理,这是不好的.
如果我们复制代码,并且如果有多个自定义验证,我们将复制大量代码,并且每个处理Animal的对象需要现在重复的验证.
如果我们将验证代码完全从Animal转移到Cage,类似的问题:与Animal交互的所有对象都需要知道"只有一个棕色"规则,这只是复制验证器并开辟一个忘记强制执行它的简单方法某处.
如果我们将Animal的错误数组移动到Cage,则会出现Animal的错误:color,这对Cage来说是不明确的,并且在客户端从未发送的属性名称上显示错误.如果要将Animal的错误键映射到Cage,现在需要保留每个表单对象的地图,感觉很臭.
有没有好的模式或方法来处理这种情况?我觉得当你开始使用表单对象时很常见,但所有的例子都非常简单.
提前致谢!
在http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/第 3 点的末尾,作者说:“作为奖励,自从验证以来逻辑通常是上下文相关的,它可以在重要的地方定义,而不需要在 ActiveRecord 本身中保护验证。” 我同意 Bryan Helmkamp 的观点,将验证放在重要的地方,您不需要重复它。
编辑:
如果我是您,我将仅对 ActiveRecord 模型进行验证。我将更新 Cage 类:
def save
  if valid?
    ActiveRecord::Base.transaction do
      animal.save!
      plant.save!
    end
    true
  else
    false
  end
rescue Exception => exception
  raise if valid?
  false
end
我将添加一个错误方法,该方法返回 Cage、Plant 和 Animal 实例的错误。
编辑:
我认为你可以重新定义有效吗?方法,然后错误就可以正常工作:
class Cage
  include ActiveModel::Model
  def valid_with_mymodels?
    valid_without_mymodels? && animal.valid? && plant.valid?
    animal.errors.each do |attribute, error|
      self.errors.add :"bird_#{attribute.to_s}", error
    end
    plant.errors.each do |attribute, error|
      self.errors.add :"plant_#{attribute.to_s}", error
    end
    errors.empty?
  end
  alias_method_chain :valid?, :mymodels
  ...
end
只是,请注意您的属性名称。
我不确定 Virtus 如何工作,对于 Rails 4,您可以使用 ActiveModel::Model,如果使用 Rails 3,我需要研究。
编辑:
如果您使用 Rails 3.2,则不能使用 ActiveModel::Model,但您会得到相同的结果:
class Cage
  extend ActiveModel::Naming
  include ActiveModel::Conversion
  include ActiveModel::Validations
  ... 
end
| 归档时间: | 
 | 
| 查看次数: | 1214 次 | 
| 最近记录: |