【问题标题】:Rails nested attributes: require at least two recordsRails 嵌套属性:至少需要两条记录
【发布时间】:2011-05-17 14:21:53
【问题描述】:

我怎样才能做到至少需要两个选项记录才能提交产品?

class Product < ActiveRecord::Base
  belongs_to :user
  has_many :options, :dependent => :destroy
  accepts_nested_attributes_for :options, :allow_destroy => :true, :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
  validates_presence_of :user_id, :created_at
  validates :description, :presence => true, :length => {:minimum => 0, :maximum => 500}
end

class Option < ActiveRecord::Base
  belongs_to :product
  validates :name, :length => {:minimum => 0, :maximum => 60}                  
end

【问题讨论】:

  • 使用自定义验证应该非常简单。类似self.errors.add_to_base("Two options are required") unless self.options.length &gt;= 2
  • 如果您使用accepts_nested_attributes_forallow_destroy: true,那么您必须使用marked_for_destruction? 和孩子关联来找到孩子的确切长度,因为从表单提交时可能有一些对象已经保存对象后标记为_destroy: true 用于销毁。长度、尺寸和数量不适合这种情况。这个链接有完美的答案。 link

标签: ruby-on-rails validation activerecord associations


【解决方案1】:
class Product < ActiveRecord::Base
  #... all your other stuff
  validate :require_two_options

  private
    def require_two_options
      errors.add(:base, "You must provide at least two options") if options.size < 2
    end
end

【讨论】:

  • add_to_base(msg) 已被弃用,请改用 Errors#add(:base, msg)
  • options.count 将生成一个 SQL COUNT 查询来查找您拥有的选项数。如果您的选项在内存中,而不是保存在数据库中,这将给出一个意外的答案,因为它们不会包含在计数中。 In cases like this consider using size.
  • 在对.count 的应答呼叫中替换为.size
【解决方案2】:

只是关于 karmajunkie 答案的考虑:我会使用 size 而不是 count 因为如果某些构建(而不是保存)的嵌套对象有错误,则不会考虑它(它还没有在数据库中)。

class Product < ActiveRecord::Base
  #... all your other stuff
  validate :require_two_options

  private
    def require_two_options
      errors.add(:base, "You must provide at least two options") if options.size < 2
    end
end

【讨论】:

  • .size 是您所说的要走的路,即使它不在数据库中,它也会考虑它。
  • .count 对我也不起作用。 .size 绝对是要走的路。
【解决方案3】:

如果您的表单允许删除记录,那么 .size 将不起作用,因为它包含标记为销毁的记录。

我的解决方案是:

validate :require_two_options

private
 def require_two_options
    i = 0
    product_options.each do |option|
      i += 1 unless option.marked_for_destruction?
    end
    errors.add(:base, "You must provide at least two option") if i < 2
 end

【讨论】:

  • +1 关于注意标记为销毁的记录的要点。但是,获得i 的更简洁的方法可能是i = product_options.reject { |option| option.marked_for_destruction? }.size
【解决方案4】:

更整洁的代码,使用 Rails 5 测试:

class Product < ActiveRecord::Base
  OPTIONS_SIZE_MIN = 2
  validate :require_two_options

  private

  def options_count_valid?
    options.reject(&:marked_for_destruction?).size >= OPTIONS_SIZE_MIN
  end

  def require_two_options
    errors.add(:base, 'You must provide at least two options') unless options_count_valid?
  end
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多