【问题标题】:How do I grab the saved value in rails?如何在 rails 中获取保存的值?
【发布时间】:2012-04-15 17:41:27
【问题描述】:

好的,我有一个名为 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”。关于如何解决这个问题的任何想法

【问题讨论】:

  • 在这种情况下如何添加约束
  • 您不能在回调中使用 id 读取现有数据库记录并进行比较吗?或者,更确切地说,按照 Leventix 的建议使用 name_was。

标签: ruby-on-rails ruby ruby-on-rails-3 validation


【解决方案1】:

如果您的意思是如果保留了更改之前的名称,则不允许进行任何更改,那么您可以使用 name_was 访问旧名称。

【讨论】:

  • 我会像 self.name_was 一样使用它
  • 您不需要self.,因为您已经在对象的上下文中,只需name_was。您也可以从errors 之前删除它。当使用像 self.name = "something" 这样的 setter 时,你会需要它,因为否则 Ruby 会设置局部变量名称,而不是在对象上调用方法 name=(value)
【解决方案2】:

首先,您可能想要使用验证而不是 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 =&gt; :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

【讨论】:

    【解决方案3】:

    这应该可以解决问题:

    name_allowed = RESERVED_TIRES.inject(true) { |is_allowed, tire_name|
      is_allowed &&= !self.name.include?(tire_name)
    }
    unless name_allowed
      # add error
    end
    

    【讨论】:

    • 当然,只要看看ruby-doc.org/core-1.9.3/Enumerable.html#method-i-inject 就可以更好地了解注入。基本上,它会遍历 RESERVED_TIRES 中的所有值,并将当前记录值放入块的第二个参数(tire_name)中。在这个例子中,第一个参数是一个布尔值,是注入方法返回的值。它用 true 初始化。 is_allowed &&= ... 与 is_allowed = is_allowed && ... 相同,一旦第二次验证(轮胎名称的验证)在前一个循环实例中返回 false,它将始终返回 false
    【解决方案4】:

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

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

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

    但是,这只会捕获某些类型的相似名称。 There are more general ways to calculate string similarity,但是这种问题没有水密的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-02
      • 1970-01-01
      • 2012-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多