2009-07-27 13 views
36

簡単な例:ユーザーがフォームにユーザー名を入力すると、アプリケーションのデータベースに保存する前にそのテキストのユーザー名を作成する必要があります。Ruby on Rails - データを保存する前に変更することはできますか?

このコードはどこに置かれますか?小文字にするにはどのようにデータにアクセスしますか?

ありがとうございました。

答えて

46

あなたは例えば、あなたのUserモデル、そのようなことでActiveRecordをコールバックのいずれかを使用できます。一般的なケースでは

before_save { |user| user.username = user.username.downcase } 
+1

ActiveRecordコールバックの詳細:http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html – Zargony

+1

あなたがそのようなフックをたくさん持っている場合や、属性に対して多くの操作が実行されている場合、それらのメソッドを作成して与えることもできますラムダの代わりにメソッド名。 属性を変更するように設計されたコールバックが多数ある場合は、そのプロセスを簡素化する[attribute-filters](http://rubydoc.info/gems/attribute-filters/1.2.2/)gemが表示される場合もあります。 – siefca

0

、コントローラのアクション に委任する必要がありますフォーム上のボタンを提出する場所のparams [: user_name]を使用できます。あなたは SomeModel.update(params)またはcreate(params)を実行する前に小文字にすることができます。

コントローラアクションで実行できます。私はObserverモデルとbefore_save方法でこのアクションを実行を追加することをお勧め

class User < ActiveRecord::Base 
    def username=(val) 
    write_attribute(:username, val.downcase) 
    end 
end 
+0

コントローラーとモデルを強く結合することの結果について考える必要があります。 2つのコントローラがこのモデルのインスタンスを作成する必要がある場合はどうなりますか?コンソールを使用してユーザーを作成すると、開発者はユーザー名がダウンしてしまうのを忘れてしまいますか?ユニットテストはどうですか?私はより良いアプローチは、effkayによって提案されたActiveRecordのコールバックを使用することだと思います。 –

+0

はい私も彼をあきらめました。私の推論:一箇所にいる限り、私は本当に気にしません。それはOPの質問から複数の場所があるように実際には見えなかった。だから私はおそらく働くことができる最も単純なものに行った。また、あなたは常にモデルを持っているとは限りません。しかし、このシナリオでは、OPが1つを使用しているように見えます。 – Gishu

70

あなたは属性ライターを上書きする必要があります。そして、どのコントローラやアクションがそれを作成しているかに関係なく、ユーザ名を小文字にすることが保証され、オブザーバ内で何らかのアクションを実行する際に問題が発生すると、例外がスローされ、オブジェクトは保存されません。

編集:ご注意くださいできませんそのモデルに関連付けられてbefore_save内のModel.saveを行う、そうでなければ無限ループに終わる。あなたはupdate_attributesなどをする必要があります。あなたのUserモデル(モデル/ user.rb)で

+4

はい、これが優れたソリューションです。オブジェクトがデータベースに保存される前でも一貫性が保証されます。 – molf

+0

お疲れ様でした。ありがとうございました! :) – Vicer

+1

この回答は受け入れる必要があります、それをトップに移動! – RonLugge

0

11

、ActiveRecordのコールバックを利用する:

before_save do 
    self.username = self.username.downcase 
end 
+0

私の場合、 – Neeraj

4

私はこのコードを使用してから私を停止するバグを見ながら過ごしました。私のデータベースは、属性を傍受し、保存する前にfalseに変更しようとするたびにロールバックされていました。

このスレッドはこのタスクを達成するためのGoogleの最初の結果でしたが、返された全体をカバーしていなかったので私の答えは貢献していますfalse問題。

コールバックのいずれかがfalseを返すと、すべてがdbにロールバックされます。

私は、データベースまたは@offer.accepted = falseで受け入れられないように作成するオファーを設定しようとしていました。問題は、この行がメソッド全体をfalseに戻し、プロセス全体をロールバックさせることでした。

は、私が働いていた暗黙のリターン trueその後

コードで投げてそれを固定:

before_save {|offer| offer.accepted = false; true}

テイクアウト:あなたは彼らが成功したい場合はあなたのコールバックがfalseを返すことができません。

出典:rails 3 : Do i need to give return true in a before_save callback for an object.save to work?

1
def username=(str) 
super(str.downcase) 
end 

私はこのはるかに簡単と思いました。

関連する問題