Rails如何在保存后更新列?

Rai*_*ner 14 ruby ruby-on-rails ruby-on-rails-3

我想为我的费率操作创建一个after_save方法.它会将rating_score/ratings分开并更新列评级.

class KonkurrancersController < ApplicationController
  def rate
    @konkurrancer = Konkurrancer.find(params[:id])
    @container = "Konkurrancer"+@konkurrancer.id.to_s

    @konkurrancer.rating_score += params[:vind][:rating].to_i
    @konkurrancer.ratings += 1
    @konkurrancer.save

    respond_to do |format|
      format.js
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

这是我的模特:

class Konkurrancer < ActiveRecord::Base
  after_save :do_foobar

  private
    def do_foobar

      rating_score = self.rating_score
      ratings = self.ratings
      rating = (rating_score/ratings)
      self.update_attributes(:rating => rating)

    end
end
Run Code Online (Sandbox Code Playgroud)

我的rails日志:

Started POST "/konkurrancers/rate/46" for 127.0.0.1 at 2011-04-26 23:40:56 +0200

  Processing by KonkurrancersController#rate as */*
  Parameters: {"utf8"=>"Ô£ô", "authenticity_token"=>"MACFM37hX4S6XA9vryn7gtfl21P
vcaPBSiKDI8mfurg=", "vind"=>{"rating"=>"4"}, "id"=>"46"}
  ?[1m?[36mKonkurrancer Load (1.0ms)?[0m  ?[1mSELECT `konkurrancers`.* FROM `kon
kurrancers`?[0m
  ?[1m?[35mCACHE (0.0ms)?[0m  SELECT `konkurrancers`.* FROM `konkurrancers`
  ?[1m?[36mCACHE (0.0ms)?[0m  ?[1mSELECT `konkurrancers`.* FROM `konkurrancers`?
[0m
  ?[1m?[35mKonkurrancer Load (1.0ms)?[0m  SELECT `konkurrancers`.* FROM `konkurr
ancers` WHERE (`konkurrancers`.`cached_slug` = '46') LIMIT 1
  ?[1m?[36mSQL (2.0ms)?[0m  ?[1mSELECT sluggable_id FROM slugs WHERE ((slugs.slu
ggable_type = 'Konkurrancer' AND slugs.name = '46' AND slugs.sequence = 1))?[0m
  ?[1m?[35mKonkurrancer Load (1.0ms)?[0m  SELECT `konkurrancers`.* FROM `konkurr
ancers` WHERE (`konkurrancers`.`id` = 46) LIMIT 1
  ?[1m?[36mSQL (0.0ms)?[0m  ?[1mBEGIN?[0m
  ?[1m?[35mLink Load (1.0ms)?[0m  SELECT `links`.* FROM `links` WHERE (`links`.k
onkurrancer_id = 46) LIMIT 1
  ?[1m?[36mSQL (0.0ms)?[0m  ?[1mROLLBACK?[0m
Rendered konkurrancers/_rating.html.erb (1.0ms)
Rendered konkurrancers/rate.js.erb (22.0ms)
Completed 200 OK in 606ms (Views: 286.0ms | ActiveRecord: 6.0ms)
Run Code Online (Sandbox Code Playgroud)

我该怎么创造这个?

zak*_*ssi 72

回调中的任何update_attribute一个after_save都会在Rails3 +中引起递归.应该做的是:

after_save :updater
# Awesome Ruby code
# ...
# ...

private

  def updater
    self.update_column(:column_name, new_value) # This will skip validation gracefully.
  end
Run Code Online (Sandbox Code Playgroud)


Chr*_*ini 10

你想要的是一个回调.您可以在Konkurrancer模型上创建after_save回调,该模型在为该模型调用save()方法后触发.

例如:

class Konkurrancer < ActiveRecord::Base
  after_save :do_foobar

  private
    def do_foobar

      rating_score = self.rating_score
      ratings = self.ratings
      rating = (rating_score/ratings)
      self.update_attributes(:ratings => rating)

    end
end
Run Code Online (Sandbox Code Playgroud)

[编辑]您应该使用self,因为您正在编辑的模型是模型本身.测试它,并应用必要的逻辑/实现.

有关详细信息,请查看本指南.

希望有所帮助!

  • 但这不是一种陷入无限循环的方式,因为update_attributes会再次调用model.save使回调再次触发吗? (23认同)
  • 是Nozim,这将进行无休止的递归,永远不会真正起作用.正确的方法是根据Zakelfassi的回答使用`self.update_column`. (2认同)

Mik*_*any 10

不确定为什么人们正在歪曲错误的答案并低估正确的答案.

Zakelfassi是正确的,而基督教法齐尼对于Rails 3及以上版本是错误的.如果你在保存回调中执行#update_attributes,你会进入无休止的递归.你想按照他的例子做#update_column.

亲自尝试,你会看到.

  • 投票使我非常困惑,以至于我去检查了Rails的源代码,对我的代码进行了广泛的单元测试,只是为了100%保证... (2认同)