如何为ActiveRecord belongs_to关联声明可选条件?

时间:2017-12-30 17:11:55

标签: ruby-on-rails ruby rails-activerecord

Rails ActiveRecord为optional提供belongs_to选项。考虑允许外键为null并允许在对象创建期间关联为空但在后续保存期间要求其存在的用例。例如,新成员可能没有初始组,但成员的任何进一步更新都需要组关联。

optional选项值本身是否有条件?例如,

class Member < ApplicationRecord
  belongs_to :group, optional: -> { new_record? }
end

optional: true的行为相同,我们可以推断optional选项解析仅检查真值。

自定义验证器是否能够满足此用例的实用方法?

3 个答案:

答案 0 :(得分:4)

看起来为optional选项提供lambda是行不通的(尽管我还没试过)。我查看了source code,这就是optional的使用方式。

required = !reflection.options[:optional]

如果需要,Rails只会添加这样的状态验证:

model.validates_presence_of reflection.name, message: :required

我相信你可以用这样的东西去自定义路线:

class Member < ApplicationRecord
  belongs_to :group, optional: true
  validates :group, presence: true, on: :update
end

答案 1 :(得分:0)

您没有描述数据库约束,而是描述业务逻辑。添加验证器以强制执行条件:

validates :group, presence: true, on: :update 

这仅强制更新条件,而不是创建。

答案 2 :(得分:0)

我遇到了同样的问题。我的解决方案是重写belongs_to并添加一个unless选项,该选项为谓词函数添加符号。似乎是个好主意...

这样,您可以写belongs_to :group, unless: :new_record?

这是我的代码

  def self.belongs_to(name, scope = nil, options = {})
    if scope.is_a?(Hash)
      options = scope
      scope   = nil
    end

    if options.has_key? :unless
      super name, scope, options.merge(optional: true).except(:unless)
      validates name, presence: true, if: ->{ !self.send(options[:unless]) }
    else
      super
    end
  end