1

更新 2

ちなみに、私が入力しUpdate 1ていると、@muffinista は私が思いついたのと同じ結論を投稿しましたUpdate 1。質問を投稿した後、もう少し考えてみると、問題が何であるかがわかりました。@muffinista は原因を投稿しましたが、彼の解決策は不十分でした。そのため、私はUpdate 1そのまま残しています。より良い解決策を見つけ、他の人が完全なコンテキストを取得することは理にかなっているからです。

更新 1

そこで、このエラーの原因である無限ループを突き止めました。

クライアント レコードclientのコールバック内にレコードを保存しようとしています。after_saveそのため、クライアント レコードを保存しようとし続け、client_record を保存しようとする after_save コールバックを実行します。

client.weighted_scoreこのループにジャンプせずに、レコードが更新されるたびにこの属性を更新するなど、目的を達成するにはどうすればよいですか?

元の質問

私はこのコールバックを持っています:

after_save :calculate_weighted_score, :if => Proc.new { |c| c.score.present? }

def calculate_weighted_score
    # Sum products of weight & scores of each attribute
        client = self
        weight = Weight.first
        score = self.score
        client.weighted_score = (weight.firm_size * score.firm_size) + (weight.priority_level * score.priority_level) + 
                (weight.inflection_point * score.inflection_point) + (weight.personal_priority * score.personal_priority) +
                (weight.sales_priority * score.sales_priority) + (weight.sales_team_priority * score.sales_team_priority) +
                (weight.days_since_contact * score.days_since_contact) + (weight.does_client_vote * score.does_client_vote) +
                (weight.did_client_vote_for_us * score.did_client_vote_for_us) + (weight.days_until_next_vote * score.days_until_next_vote) +
                (weight.does_client_vote_ii * score.does_client_vote_ii) + (weight.did_client_vote_ii_for_us * score.did_client_vote_ii_for_us) + 
                (weight.days_until_vote_ii * score.days_until_vote_ii)
        client.o
            # self.save
        # client.update_attributes(:weighted_score => weighted_score)
end

これは、このコールバックが実行される前のクライアント レコードの状態の例です。

#<Client:0x007fe00dbcea90> {
                   :id => 10,
                 :name => "Manta-Jar Gale",
                :email => "mj@gmail.com",
                :phone => 8769876435,
              :firm_id => 1,
           :created_at => Fri, 23 Nov 2012 23:50:09 UTC +00:00,
           :updated_at => Tue, 27 Nov 2012 17:50:01 UTC +00:00,
              :user_id => 1,
    :personal_priority => true,
         :last_contact => Sat, 08 Jan 2011,
                 :vote => true,
        :vote_for_user => false,
            :next_vote => Thu, 02 Jan 2014,
              :vote_ii => true,
       :vote_ii_for_us => true,
         :next_vote_ii => Mon, 01 Jul 2013,
       :weighted_score => nil,
            :firm_size => 100.0
}

weighted_score => nil属性に注意してください。

コールバックの後、この同じレコードは次のようになります。

#<Client:0x007fe00dbcea90> {
                   :id => 10,
                 :name => "Manta-Jar Gale",
                :email => "mj@gmail.com",
                :phone => 8769876435,
              :firm_id => 1,
           :created_at => Fri, 23 Nov 2012 23:50:09 UTC +00:00,
           :updated_at => Tue, 27 Nov 2012 17:50:01 UTC +00:00,
              :user_id => 1,
    :personal_priority => true,
         :last_contact => Sat, 08 Jan 2011,
                 :vote => true,
        :vote_for_user => false,
            :next_vote => Thu, 02 Jan 2014,
              :vote_ii => true,
       :vote_ii_for_us => true,
         :next_vote_ii => Mon, 01 Jul 2013,
       :weighted_score => 9808,
            :firm_size => 100.0
}

weighted_score => 9808属性に注意してください。

だから私はコールバックcalculate_weighted_scoreが実行されていることを知っており、コールバック全体がclient.weighted_score. 問題は、ログUPDATEにその属性のデータベース トランザクションが表示されないことです。

Started PUT "/clients/10" for 127.0.0.1 at 2012-11-27 12:50:01 -0500
Processing by ClientsController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"J172LuZQ=", "client"=>{"name"=>"Manta-Jar Gale", "email"=>"mj@gmail.com", "phone"=>"8769876435", "firm_id"=>"1", "topic_ids"=>["1", "2", "9"], "personal_priority"=>"1", "last_contact"=>"2011-01-08", "vote"=>"1", "vote_for_user"=>"0", "next_vote"=>"2014-01-02", "vote_ii"=>"1", "vote_ii_for_us"=>"1"}, "commit"=>"Update Client", "id"=>"10"}
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
  Client Load (0.2ms)  SELECT "clients".* FROM "clients" WHERE "clients"."user_id" = 1 AND "clients"."id" = ? LIMIT 1  [["id", "10"]]
  Topic Load (0.3ms)  SELECT "topics".* FROM "topics" 
   (0.1ms)  begin transaction
  Topic Load (0.2ms)  SELECT "topics".* FROM "topics" WHERE "topics"."id" IN (1, 2, 9)
  Topic Load (0.1ms)  SELECT "topics".* FROM "topics" INNER JOIN "clients_topics" ON "topics"."id" = "clients_topics"."topic_id" WHERE "clients_topics"."client_id" = 10
   (0.5ms)  UPDATE "clients" SET "name" = 'Manta-Jar Gale', "updated_at" = '2012-11-27 17:50:01.856893' WHERE "clients"."id" = 10
  Firm Load (0.2ms)  SELECT "firms".* FROM "firms" WHERE "firms"."id" = 1 LIMIT 1
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
  Score Load (0.2ms)  SELECT "scores".* FROM "scores" WHERE "scores"."client_id" = 10 LIMIT 1
  SalesTeam Load (0.1ms)  SELECT "sales_teams".* FROM "sales_teams" WHERE "sales_teams"."id" = 2 LIMIT 1
  PriorityLevel Load (0.1ms)  SELECT "priority_levels".* FROM "priority_levels" WHERE "priority_levels"."id" = 1 LIMIT 1
  CACHE (0.0ms)  SELECT "scores".* FROM "scores" WHERE "scores"."client_id" = 10 LIMIT 1
  Max Load (0.2ms)  SELECT "maxes".* FROM "maxes" WHERE "maxes"."user_id" = 1 LIMIT 1
  CACHE (0.0ms)  SELECT "scores".* FROM "scores" WHERE "scores"."client_id" = 10 LIMIT 1
  Weight Load (0.2ms)  SELECT "weights".* FROM "weights" LIMIT 1
   (3.2ms)  commit transaction
Redirected to http://localhost:3000/clients
Completed 302 Found in 796ms (ActiveRecord: 26.4ms)

唯一のUPDATEトランザクションは、コールバックをテストするために行った名前の編集です。

UPDATE技術的にはレコードを保存していないため、トランザクションがないことはわかっています。

しかし、コメントアウトされたステートメントのいずれかを実行しようとすると、つまりclient.saveエラーclient.update_attributes(....)Stack Level Too Deep発生します。

何が原因で、このレコードを保存するにはどうすればよいですか?

4

3 に答える 3

3

@muffinistaで示されているように(そして質問自体の更新で指定されています)、ここでの問題は、コールバックがレコードを保存しようとしているコールバックを呼び出しているレコードを保存しようとしていることです... Stack Overflow(盗んだこの同様の質問で@ivanからのジョーク)。

最良の答えは使用することですupdate_column-ドキュメントはここで見ることができます

これは同じことをupdate_attributes行いますが、検証やコールバックは行いません。これは、この特定のインスタンスで必要なことには問題ありません。

update_columnの形式はと同じではないことに注意してくださいupdate_attributes

あなたがすることは次のとおりです。

client.update_column(:weighted_score, weighted_score)

は列:weighted_scoreweighted_scoreです。 は上記のコード例で設定した、計算を行ったローカル変数です。

それだけの価値があるので、この SO answerからこの答えを得ました。

于 2012-11-27T18:30:07.150 に答える
1

元のレコードが保存された後にコールバックが実行されていますが、レコードを変更して再保存しようとしています。これにより、コールバックが無限にトリガーされます。これは基本的に重複する質問です。たとえば、ここで説明します。保存後にレコードを更新するタイミングは?

于 2012-11-27T18:07:47.850 に答える
1

代わりに before_save フィルターを使用するのはどうですか?

于 2012-11-27T18:18:45.347 に答える