【问题标题】:Validation error on has_many association not preventing savehas_many 关联的验证错误不会阻止保存
【发布时间】:2016-08-16 23:27:51
【问题描述】:

我有一个模特 eclub,有很多邀请,我想限制可以添加的邀请数量。我的模型是这样的

class Eclub < ActiveRecord::Base
    has_many :invites, dependent: :destroy
    validates :invites, length: {maximum: 50, message: 'The maximum number of invites have been sent' }

根据这个SO answer 应该可以工作,前提是我不关心标记为销毁的邀请。我的 rspec 测试首先创建了一个 eclub 并成功添加了 50 个邀请。那么

  invite = Invite.new(name: 'Too Many', email: 'extra@gmail.com')
  eclub.invites << invite
  expect(eclub).to be_invalid
  expect(eclub.errors[:invites].first).to include 'maximum number'
  expect(eclub.reload.invites.size).to eq 50

前两个期望通过,但最后一个失败了

Failure/Error: expect(eclub.reload.invites.size).to eq 50

       expected: 50
            got: 51

如何防止额外的邀请被添加到集合中?

【问题讨论】:

  • 我已经澄清了。

标签: ruby-on-rails rspec


【解决方案1】:

添加此验证的最佳位置不是Eclub,而是Invite 模型。试试这个:

class Invite < ActiveRecord::Base
  belongs_to :eclub
  validate :check_invite_count!, on: :create

  private

  def check_invite_count!
    return if eclub.nil?
    if eclub.invites.count > 50
      errors.add(:base, 'Cannot add more than 50 invites for an Eclub')
    end
  end
end

此外,此代码 validates :invites, length: {maximum: 50, message: 'The maximum number of invites have been sent' } 将不起作用,因为它假定 invites 是一个字符串。

【讨论】:

  • 这是我目前看到的最好的想法,会试一试。
  • 对与何时运行此验证相关的答案进行了编辑。
  • 谢谢您,我已接受您的回答并点赞。我还对其进行了编辑以使其更清晰,添加了对 nil eclub 的检查,并将测试更改为 >=。如果一切都按预期工作,使用 == 应该没问题,但我习惯了不工作的事情。
【解决方案2】:

validates length 用于测量字符串的长度,可能不适用于整数。

你可能想试试validates :numericality =&gt; {:maximum =&gt; 50}

编辑 是的,我在这里可能不会工作,因为它是我们需要验证的邀请计数(而不是邀请关联本身),所以这里有一个自定义验证器,应该可以满足您的需求:

validate :invite_count_is_ok

private

def invite_count_is_ok
  return unless invites.present?
  errors.add(:base, "You may only have up to 50 invites at a time") unless invites.count <= 50
end

【讨论】:

  • 我尝试了validates :invites, numericality: {maximum: 50 },并在 Factory(:eclub) 上收到了验证错误,即在没有任何邀请的情况下创建了 eclub。消息是ActiveRecord::RecordInvalid: Validation failed: Invites is not a number。我也尝试了validates :invites, size: {maximum: 50},但这是一个带有Unknown validator: SizeValidator 错误的非首发。
  • 是的,您可能需要 :allow_blank =&gt; true 以使其在邀请计数为零时不会爆炸...尽管实际上您希望它检查他的邀请计数
  • 我已经尝试了几个这样的,问题是它确实将eclub标记为无效,它确实添加了错误消息,但它并没有阻止邀请被添加到集合中。到目前为止唯一有效的是 Jagdeep 的建议,但我很惊讶我不能直接作为 eclub 上的验证者这样做。我也很惊讶我提到的原始 SO 帖子没有看到这个问题。
【解决方案3】:
validates(
  :invites,
  numericality: {
    greater_than_or_equal_to: 0,
    less_than_or_equal_to: 50
  }
)

【讨论】:

  • 我尝试了这个,但收到了与执行 Taryn East 的建议时相同的错误。
  • 试试这个 validates_length_of :invites, maximum: 50
  • 它和我上面的原始验证器有同样的问题,它确实将 eclub 标记为无效,但不会阻止保存额外的 eclub。
  • 哦,比在当前 eclub 邀请中使用 before_validation 做一件事。如果它大于返回 false 并添加 errors.add(:your_filed, "message") 的条件,否则返回 true 可能这一项工作... :)
  • 嗨 bk chovatiya :如果您建议对答案进行更改,最好编辑答案以进行这些更改。这样,原始提问者和任何其他读者都可以轻松找到他们正在寻找的内容,而无需浏览每条评论。
猜你喜欢
  • 2015-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-31
  • 1970-01-01
  • 2019-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多