153

after_save コールバックを持つモデルがいくつかあります。通常はそれで問題ありませんが、開発データを作成するときなど、状況によっては、コールバックを実行せずにモデルを保存したいことがあります。それを行う簡単な方法はありますか?に似た何か...

Person#save( :run_callbacks => false )

また

Person#save_without_callbacks

Railsのドキュメントを調べましたが、何も見つかりませんでした。しかし、私の経験では、Rails のドキュメントが必ずしもすべてを説明しているわけではありません。

アップデート

次のようなモデルからコールバックを削除する方法を説明しているブログ投稿を見つけました。

Foo.after_save.clear

その方法が文書化されている場所を見つけることができませんでしたが、うまくいくようです。

4

28 に答える 28

238

update_column(Rails >= v3.1) またはupdate_columns(Rails >= 4.0) を使用して、コールバックと検証をスキップします。また、これらのメソッドでupdated_atは、更新されません。

#Rails >= v3.1 only
@person.update_column(:some_attribute, 'value')
#Rails >= v4.0 only
@person.update_columns(attributes)

http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column

#2:オブジェクトの作成中にも機能するコールバックをスキップする

class Person < ActiveRecord::Base
  attr_accessor :skip_some_callbacks

  before_validation :do_something
  after_validation :do_something_else

  skip_callback :validation, :before, :do_something, if: :skip_some_callbacks
  skip_callback :validation, :after, :do_something_else, if: :skip_some_callbacks
end

person = Person.new(person_params)
person.skip_some_callbacks = true
person.save

更新 (2020)

どうやら Railsは常に:ifand :unlessoptionsをサポートしていたようで、上記のコードは次のように簡略化できます。

class Person < ActiveRecord::Base
  attr_accessor :skip_some_callbacks

  before_validation :do_something, unless: :skip_some_callbacks
  after_validation :do_something_else, unless: :skip_some_callbacks
end

person = Person.new(person_params)
person.skip_some_callbacks = true
person.save
于 2011-09-12T10:08:18.910 に答える
71

このソリューションは Rails 2 のみです。

これを調査したところ、解決策があると思います。使用できる ActiveRecord プライベート メソッドは 2 つあります。

update_without_callbacks
create_without_callbacks

これらのメソッドを呼び出すには send を使用する必要があります。例:

p = Person.new(:name => 'foo')
p.send(:create_without_callbacks)

p = Person.find(1)
p.send(:update_without_callbacks)

これは間違いなく、コンソールで、またはランダムなテストを実行しているときにのみ使用したいものです。お役に立てれば!

于 2009-03-11T04:29:37.333 に答える
30

更新しました:

@Vikrant Chaudharyのソリューションの方が優れているようです:

#Rails >= v3.1 only
@person.update_column(:some_attribute, 'value')
#Rails >= v4.0 only
@person.update_columns(attributes)

私の元の答え:

このリンクを参照してください: ActiveRecordコールバックをスキップする方法は?

Rails3では、

クラス定義があると仮定します。

class User < ActiveRecord::Base
  after_save :generate_nick_name
end 

アプローチ1:

User.send(:create_without_callbacks)
User.send(:update_without_callbacks)

アプローチ2:rspecファイルなどでそれらをスキップしたい場合は、次のことを試してください。

User.skip_callback(:save, :after, :generate_nick_name)
User.create!()

注:これが完了したら、rspec環境にいない場合は、コールバックをリセットする必要があります。

User.set_callback(:save, :after, :generate_nick_name)

Rails3.0.5で問題なく動作します

于 2011-11-30T02:59:48.790 に答える
26

コールバックや検証を行わずに単純にレコードを挿入することが目標であり、gem を追加したり、条件付きチェックを追加したり、RAW SQL を使用したり、何らかの方法で既存のコードを操作したりせずに挿入したい場合は、「シャドウ」の使用を検討してください。 object" が既存の db テーブルを指しています。そのようです:

class ImportedPerson < ActiveRecord::Base
  self.table_name = 'people'
end

これは、Rails のすべてのバージョンで動作し、スレッドセーフであり、既存のコードを変更することなく、すべての検証とコールバックを完全に排除します。実際のインポートの直前にそのクラス宣言を投げ込むだけで、準備完了です。次のように、新しいクラスを使用してオブジェクトを挿入することを忘れないでください。

ImportedPerson.new( person_attributes )
于 2015-12-09T22:41:27.893 に答える
21

レール 3:

MyModel.send("_#{symbol}_callbacks") # list  
MyModel.reset_callbacks symbol # reset
于 2010-11-26T08:03:40.230 に答える
17

Person モデルで次のようなことを試すことができます。

after_save :something_cool, :unless => :skip_callbacks

def skip_callbacks
  ENV[RAILS_ENV] == 'development' # or something more complicated
end

編集: after_save はシンボルではありませんが、それを作成しようとしたのは少なくとも 1,000 回目です。

于 2009-03-11T00:02:55.663 に答える
11

使用できますupdate_columns

User.first.update_columns({:name => "sebastian", :age => 25})

save を呼び出さずにオブジェクトの指定された属性を更新するため、検証とコールバックをスキップします。

于 2013-04-02T23:05:06.450 に答える
6

Rails 2.3 でこれを処理する 1 つの方法のように見えます (update_without_callbacks がなくなったためなど)、Rails Guide to validations and callbacks のセクション 12に従ってコールバックをスキップするメソッドの 1 つである update_all を使用することです。

また、after_ コールバックで何かを行っている場合、それは多くの関連付けに基づいて計算を行います (つまり、accepts_nested_attributes_for も行う has_many assoc)。 、そのメンバーの 1 つが削除されました。

于 2010-04-13T05:27:26.520 に答える
3

gem やプラグインを使用せずに Rails のすべてのバージョンで機能するソリューションは、 update ステートメントを直接発行することです。例えば

ActiveRecord::Base.connection.execute "update table set foo = bar where id = #{self.id}"

これは、更新の複雑さに応じて、オプションである場合とない場合があります。これは、(コールバックを再トリガーせずに) after_save コールバックからレコードのフラグを更新する場合などにうまく機能します。

于 2013-02-08T18:02:40.113 に答える
3

https://gist.github.com/576546

このモンキーパッチをconfig/initializers/skip_callbacks.rbにダンプするだけです

それから

Project.skip_callbacks { @project.save }

など。

著者へのすべてのクレジット

于 2012-02-24T23:26:42.190 に答える
1

Rails 2を使用している場合。コールバックと検証を実行せずに、SQLクエリを使用して列を更新できます。

YourModel.connection.execute("UPDATE your_models SET your_models.column_name=#{value} WHERE your_models.id=#{ym.id}")

Railsのどのバージョンでも動作するはずだと思います。

于 2012-08-31T11:31:13.770 に答える
1
# for rails 3
  if !ActiveRecord::Base.private_method_defined? :update_without_callbacks
    def update_without_callbacks
      attributes_with_values = arel_attributes_values(false, false, attribute_names)
      return false if attributes_with_values.empty?
      self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).arel.update(attributes_with_values)
    end
  end
于 2010-12-17T07:21:17.203 に答える
1

Rails 3 で update_without_callbacks を実装するプラグインを作成しました。

http://github.com/dball/skip_activerecord_callbacks

正しい解決策は、そもそもコールバックを回避するようにモデルを書き直すことだと思いますが、それが短期的に現実的でない場合は、このプラグインが役立つかもしれません。

于 2012-04-13T14:59:38.227 に答える
1

Sneaky-save gem: https://rubygems.org/gems/sneaky-saveを使用できます。

これは、検証なしで関連付けを保存する際には役に立たないことに注意してください。モデルとは異なり、SQLクエリを直接挿入するため、「created_atをnullにすることはできません」というエラーがスローされます。これを実装するには、自動生成された db のすべての列を更新する必要があります。

于 2011-10-26T03:47:24.943 に答える
1

without_callbacks必要なことだけを行うプラグインへのこれらのポイントはありません...

class MyModel < ActiveRecord::Base
  before_save :do_something_before_save

  def after_save
    raise RuntimeError, "after_save called"
  end

  def do_something_before_save
    raise RuntimeError, "do_something_before_save called"
  end
end

o = MyModel.new
MyModel.without_callbacks(:before_save, :after_save) do
  o.save # no exceptions raised
end

http://github.com/cjbottaro/without_callbacksは Rails 2.x で動作します

于 2010-10-15T15:26:49.413 に答える
0

ActiveRecord存在するかどうかにかかわらず、オプションまたはアクティブレコードメソッドに依存せずに、すべてのバージョンで動作するはずの何か。

module PlainModel
  def self.included(base)
    plainclass = Class.new(ActiveRecord::Base) do
      self.table_name = base.table_name
    end
    base.const_set(:Plain, plainclass)
  end
end


# usage
class User < ActiveRecord::Base
  include PlainModel

  validates_presence_of :email
end

User.create(email: "")        # fail due to validation
User::Plain.create(email: "") # success. no validation, no callbacks

user = User::Plain.find(1)
user.email = ""
user.save

TLDR: 同じテーブルに対して「別のアクティブ レコード モデル」を使用する

于 2016-03-07T05:17:11.590 に答える
0

なぜ開発でこれを実行できるようにしたいのですか? 確かに、これは無効なデータを使用してアプリケーションを構築していることを意味し、本番環境では期待どおりに動作せず、奇妙な動作をすることになります。

dev db にデータを入力したい場合は、faker gem を使用して有効なデータを作成し、それを db にインポートして必要な数のレコードを作成する rake タスクを作成することをお勧めします。 update_without_callbacks と create_without_callbacks は問題なく動作すると思いますが、自分の意志でレールを曲げようとしているときは、正当な理由があるかどうか、自分が行っていることが本当に良いアイデアであるかどうかを自問してください。

于 2009-03-11T09:18:13.440 に答える
0

1 つのオプションは、同じテーブルを使用して、そのような操作用に別のモデルを用意することです。

class NoCallbacksModel < ActiveRecord::Base
  set_table_name 'table_name_of_model_that_has_callbacks'

  include CommonModelMethods # if there are
  :
  :

end

(同じアプローチにより、検証をバイパスすることが容易になる場合があります)

ステファン

于 2011-06-06T19:00:06.317 に答える
0

別の方法は、コールバックの代わりに検証フックを使用することです。例えば:

class Person < ActiveRecord::Base
  validate_on_create :do_something
  def do_something
    "something clever goes here"
  end
end

そうすれば、デフォルトで do_something を取得できますが、次のように簡単にオーバーライドできます。

@person = Person.new
@person.save(false)
于 2009-08-14T21:44:58.207 に答える
-7

最もクリーンな方法ではありませんが、Rails 環境をチェックする条件でコールバック コードをラップすることができます。

if Rails.env == 'production'
  ...
于 2009-03-10T23:59:26.513 に答える