0

好的,我有一个名为 Tire 的模型,我无法更新某些保留名称的名称字段

class Tire < ActiveRecord::Base

  RESERVED_TIRES = ['Michelin', 'Good Year', 'Firestone']

  before_update :reserved_tires

  def reserved_tires
    if RESERVED_TIRES.include?(self.name)
      self.errors.add(:base, "Cant be changed")
      false
    end
  end
end

而且我需要不允许用户更新任何字段,因为当前名称在保留字中……这适用于除用户更新名称之外的所有字段。

例如,用户更新到“Michelinnnn”,然后它允许更新,因为 self.name 是“Michelinnnn”,而不是保存在数据库中的“Michelin”。关于如何解决这个问题的任何想法

4

4 回答 4

3

如果您的意思是如果更改之前的名称被保留,则您不想允许任何更改,那么您可以将旧名称访问为name_was.

于 2012-04-15T17:52:54.630 回答
1

所以问题是与保留名称相似但不相同的字符串?“michelinnnn”示例将通过使用正则表达式而不是精确字符串匹配来捕获:

RESERVED_TIRES = [/michelin/i, /good\s*year/i, /firestone/i]
...
if RESERVED_TIRES.find{|r| self.name =~ r}

内置的 Rails 函数是validates_exclusion_of,但我不知道它是否可以处理(数组)正则表达式。

但是,这只会捕获某些类型的相似名称。 计算字符串相似度有更通用的方法,但是对于这类问题没有无懈可击的解决方案。

于 2012-04-15T17:52:19.807 回答
1

首先,您可能想要使用验证而不是您的before_update

class Tire < ActiveRecord::Base
  RESERVED_TIRES = ['Michelin', 'Good Year', 'Firestone']
  validate :reserved_tires, :unless => :new_record?

private

  def reserved_tires
    if RESERVED_TIRES.include?(self.name)
      self.errors.add(:base, "Cant be changed")
    end
  end
end

跳过对新记录的:unless => :new_record?验证,因此您将能够创建它们,但将阻止更改。

然后添加另一个验证来捕捉他们试图更改名称:

validate :cant_change_reserved_name, :if => :name_changed?
#...
def cant_change_reserved_name
  if RESERVED_TIRES.include?(self.name_was)
    self.errors.add(:name, "You cannot change a reserved name.")
  end
end
于 2012-04-15T17:57:48.953 回答
1

这应该可以解决问题:

name_allowed = RESERVED_TIRES.inject(true) { |is_allowed, tire_name|
  is_allowed &&= !self.name.include?(tire_name)
}
unless name_allowed
  # add error
end
于 2012-04-15T17:57:53.977 回答