2012-04-15 13 views
0

[OK]を、私はタイヤという名前のモデルを持っていると私はいくつかの予約名レールで保存された値を取得するにはどうすればよいですか?

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

+0

コールバック内のIDを使用して既存のデータベースレコードを読み取り、比較しますか? Leventixが提案したように、name_wasを使用してください。 – Trace

+0

はあなたのことができないこのような状況に制約を追加する方法を

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

答えて

1

問題は、予約名と似ているが同じではない文字列ですか? 「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がありますが、この種の問題のための防水ソリューションはありません。

3

あなたが名前場合が予約された変更前の任意の変更を許可したくないわけ場合は、name_wasとして古い名前にアクセスすることができます。

+0

私はself.name_wasのように使用します – Trace

+0

あなたはすでに 'name_was'というオブジェクトのコンテキストに入っているので、' self.'は必要ありません。 'errors'の前から削除することもできます。 'self.name =" something "'のようなセッターを使うときは、Rubyがローカル変数名を設定し、オブジェクトの 'name =(value)'メソッドを呼び出さないので、この変数が必要になります。 – Leventix

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 
1

これはトリックを行う必要があります:

その後、名前を変更しようと、それらをキャッチするために、別の検証を追加

私は
+0

あなたはこれを私に説明することができます... – Trace

+0

確かに、より良い注入を理解するにはhttp://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-injectを見てください。基本的には、RESERVED_TIRESのすべての値をループし、現在のレコード値をブロックの2番目の引数(tire_name)に格納します。最初の引数はこの例ではboolean値で、injectメソッドが返すものです。これは、trueで初期化されます。 is_allowed && = ...はis_allowed = is_allowed && ...と同じです。これは、前のループインスタンスで2回目の検証(タイヤ名の検証)がfalseを返すと常にfalseを返します。 – emrass

+0

これは機能しますか? – emrass

関連する問題