web-dev-qa-db-ja.com

Rails:コールバックを呼び出さずにモデル属性を更新します

:credits属性を持つユーザーモデルがあります。 「add」と呼ばれるルートを通じて、ユーザーのクレジットに5を追加するシンプルなボタンが必要です。これにより、/ users/3/addがユーザーID = 3のクレジットに5を追加します。

def add
    @user = User.find(params[:id])
    @user.credits += 5
    redirect_to root_path
end

それが私のコントローラーの重要な部分です。問題は、現在のUTC時間に基づいてユーザーのパスワードを再暗号化するbefore_saveコールバックがあるため、@ user.saveを呼び出したくないことです。単純に属性に5を追加して、コールバックを回避したいだけです。このような単純なことをこれほど難しいとは思っていませんでした。

編集:

コールバックを:before_createに変更しました。新しいコントローラーコードを次に示します(関連部分)。

  def add
    @user = User.find(params[:id])
    @user.add_credits(5)
    @user.save
    flash[:success] = "Credits added!"
    redirect_to root_path
  end

そして、ここにモデル内の私のコードがあります:

 def add_credits(num)
    self.credits = num
 end

編集2:

[編集]の変更が機能しなかったのは検証の問題でしたが、コールバックなしで更新するという元の質問に対する答えがまだ欲しいです!

67
Sam Stern

Rails 3.1はupdate_columnを導入しました。これはupdate_attributeと同じですが、検証またはコールバックをトリガーしません。

http://apidock.com/Rails/ActiveRecord/Persistence/update_column

130
cvshepherd

コールバックなしで複数の属性を更新するには、モデルでupdate_allを次のように使用できます。

self.class.update_all({name: value, name: value}, self.class.primary_key => id)

本当に必要な場合は、update_columnsメソッドでも試して、これをアクティブなレコードの基本クラスにミックスインすることもできます。

1つの属性を更新するには、update_columnを使用できます。さらに、Railsガイド http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks にある特定のメソッドがあります。

7
Matt Smith

一般的な答えとして、Rails 4では、これはコールバックをトリガーせずに属性を更新する簡単な方法です。

@user.update_column 'credits', 5

トリガーコールバックなしで複数の属性を更新する必要がある場合:

@user.update_columns credits: 5, bankrupt: false  

他のオプションがあります ここでRails Guides にありますが、この方法が最も簡単であることがわかりました。

4
Matt

この場合、メソッド pdate_counters を使用する必要があると思います。コントローラーアクションで次のように使用します。

def add
  User.update_counters params[:id], :credits => 5
  redirect_to root_path
end
3
DanneManne

Rails4でこれを行う方法のいくつかのオプション http://edgeguides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

2
katzmopolitan

pdate_all を使用して、コールバックのトリガーを回避できる必要があります。

def add
 @user = User.find(params[:id])
 User.where(:id=>@user.id).update_all(:credits => @user.credits+5)
 redirect_to root_path
end

このロジックをモデルに配置することを希望しますが、これはコントローラーで指定された元の問題を解決するために機能するはずです。

2
miked

Mongoidの場合、 http://mongoid.org/en/mongoid/docs/persistence.html を使用することになりました。具体的には、次を使用できます。

person.set(name:"Robert Pulson")

コールバックは発行されません。とてもクール。

2
hb922

他のbefore_saveフックは、ユーザーのパスワードが実際に変更されたかどうかを再度暗号化する前にチェックする必要があるかもしれません。

1
Finbarr

使用するコールバックの変更など、多くのオプションがあります。例:after_create

コールバックをトリガーせずに列を更新できます。ARガイドの Skipping Callbacks を参照してください。例えば、 update_columnはコールバックをトリガーしません。前のリンクには、非トリガー関数がリストされています。

また、パスワードが変更されたときに 条件付きコールバック フォーム(またはオブザーバー)を使用することもできます。 ActiveModel :: Dirty (例:@user.password_changed?

1
Dave Newton

これを行う列を更新できます

User.where(name: 'lily').update_all(age: '10')

0
Abdul Monam