0

タイヤという名前のモデルがあり、いくつかの予約済みの名前の名前フィールドを更新できません

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」に更新すると、DB に保存されている「Michelin」ではなく、self.name が「Michelinnnn」であるため、更新が許可されます。これに対処する方法についてのアイデア

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 に答える