可选时Railsbelongs_to不验证id

jsm*_*rtt 6 activerecord ruby-on-rails rails-models ruby-on-rails-5

我正在运行 Rails 5.1.4,我有一个看起来像这样的模型:

class Quota < ActiveRecord::Base
  belongs_to :domain, optional: true
  belongs_to :project, optional: true
end
Run Code Online (Sandbox Code Playgroud)

配额应属于域或项目,但不能同时属于两者(因此设置optional: true)。

但是,如果提供了无效的项目或域 ID,我似乎无法弄清楚如何使 rails 抛出错误。

这是发生的事情:

q = Quota.create!(domain_id: nil, project_id: 'invalid_id')
q.project_id # -> nil
Run Code Online (Sandbox Code Playgroud)

即使我明确传递了 project_id,如果它与有效项目不匹配,它也会神奇地将其清除。我尝试添加自定义验证方法,但是在调用验证方法时,它已经设置为 nil。它甚至不使用该project_id=方法;我检查了。

如果 ID 无效而不是将其设置为 nil,有没有办法让 Rails 引发错误?(同时仍然允许一个 nil 值)

jsm*_*rtt 3

我能想到的最好的解决方案是:

class Quota < ActiveRecord::Base
  belongs_to :domain,  optional: true
  belongs_to :project, optional: true

  validate :validate_associations

  def project_id=(val)
    Project.find(val) unless val.nil?
    super
  end

  def domain_id=(val)
    Domain.find(val) unless val.nil?
    super
  end

  private

  def validate_associations
    errors.add(:base, 'Specify a domain or a project, not both') if domain && project
    errors.add(:base, 'Must specify a domain or a project') if domain.nil? && project.nil?
  end
end
Run Code Online (Sandbox Code Playgroud)

感谢您帮助解决问题@vane-trajkov。find我发现在设置domain_id或project_id时我确实需要使用该方法,因为Rails很乐意将其设置为无效ID。按原样使用project=domain=工作正常,因为它们几乎确保 ID 已设置为有效值。