23

私はこのように定義された私のMessageモデルでbefore_saveを持っている:私が行うと"before_save"を実行せずに "update_attributes"を実行する方法は?

class Message < ActiveRecord::Base 
    before_save lambda { foo(publisher); bar } 
    end 

my_message.update_attributes(:created_at => ...) 

foobarが実行されています。

場合によっては、foobarを実行せずにメッセージのフィールドを更新したいとします。

foobarを実行せずに、たとえばcreated_atフィールド(データベース内)を更新するにはどうすればよいですか?

答えて

33

レール3.1では、update_columnを使用します。それ以外の場合は

:一般的な方法で

、コールバックを回避するための最もエレガントな方法は以下の通りです:

class Message < ActiveRecord::Base 
    cattr_accessor :skip_callbacks 
    before_save lambda { foo(publisher); bar }, :unless => :skip_callbacks # let's say you do not want this callback to be triggered when you perform batch operations 
end 

次に、あなたが行うことができます。

Message.skip_callbacks = true # for multiple records 
my_message.update_attributes(:created_at => ...) 
Message.skip_callbacks = false # reset 

それとも、ただ一つのために記録:

my_message.update_attributes(:created_at => ..., :skip_callbacks => true) 

Timeアトリビュートに特に必要な場合は、touchが@lucapetteで述べたようにトリックを行います。

+0

良い一般的なソリューションのように見えます! 1つの質問:正確に 'Message.batch = true'とは何ですか? –

+0

単なる旗です。あなたはそれをあなたが望むもので置き換えることができます。 – jbescoyez

+0

例をより明示的なフラグで更新しました。 – jbescoyez

17

update_allは、コールバック

my_message.update_all(:created_at => ...) 
# OR 
Message.update_all({:created_at => ...}, {:id => my_message.id}) 

http://apidock.com/rails/ActiveRecord/Base/update_all/class

+1

'my_message.update_all(:created_at => ...)'は構文エラーを発行しますが、2番目のオプションはうまくいきます! –

+1

my_message.update_allは '未定義メソッドupdate_all'を起動します。 Message.update_allはトリックを行います –

+0

increment_counterを使用すると、コールバックをスキップしてもインクリメントしたいと思う場合は、私は信じています。 – rogerdpack

6

touchメソッドを使用しますがトリガされません。エレガントで、あなたが望むものを正確に実行します

+0

_almost_のように見えます。私の場合の 'created_at'の新しい値は**現在の時刻ではありません**。 –

+0

ああ、面白いです。 – fl00r

+0

@Mishaあなたは明らかに正しいです。だから、あなたはhttp://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_attributeを使うことができます:D – lucapette

1

before_saveアクションを条件付きにすることもできます。

フィールド/インスタンス変数をいくつか追加し、それをスキップしたい場合にのみ設定し、そのメソッドでその変数をチェックします。

など。

before_save :do_foo_and_bar_if_allowed 

attr_accessor :skip_before_save 

def do_foo_and_bar_if_allowed 
    unless @skip_before_save.present? 
    foo(publisher) 
    bar 
    end 
end 

、その後はどこか

my_message.skip_before_save = true 
my_message.update_attributes(:created_at => ...) 
0

update_columnまたはupdate_columnsupdate_attributesに最も近い方法であり、それは手動で何かを回避することなく、コールバックを回避書きます。

関連する問題