Rails:更新模型属性而不调用回调

时间:2011-12-28 01:36:14

标签: ruby-on-rails ruby model attributes callback

我有一个具有:credits属性的User模型。我想要一个简单的按钮,通过一个名为“add”的路由为用户的积分增加5个,这样/ users / 3 / add会为用户id = 3的积分增加5个。

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

这是我的控制器的相关部分。问题是,我不想调用@ user.save,因为我有一个before_save回调,它根据当前的UTC时间重新加密用户的密码。我只想简单地在属性中添加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:

好的,这是一个验证问题,导致“编辑”中的更改不起作用,但我仍然喜欢没有回调的原始更新问题的答案!

10 个答案:

答案 0 :(得分:127)

Rails 3.1引入了update_column,它与update_attribute相同,但没有触发验证或回调:

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

答案 1 :(得分:7)

要在没有回调的情况下更新多个属性,您可以在模型中使用update_all,如下所示:

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

如果你真的想要甚至可以尝试使用update_columns方法并将其混合到你的活动记录基类中。

要更新一个属性,您可以使用update_column。此外,还可以在导轨指南http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

中找到一些具体方法

答案 2 :(得分:4)

作为一般答案,在Rails 4中,这是一种在不触发回调的情况下更新属性的简单方法:

@user.update_column 'credits', 5

如果您需要在没有触发器回调的情况下更新多个属性:

@user.update_columns credits: 5, bankrupt: false  

如果您愿意,还有其他选项here in the Rails Guides,但我发现这种方式最简单。

答案 3 :(得分:3)

我认为在这种情况下你应该使用方法update_counters。在控制器操作中使用它:

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

答案 4 :(得分:2)

您应该可以使用update_all来避免触发回调。

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

我更倾向于将此逻辑放在模型中,但这应该可以解决控制器中规定的原始问题。

答案 5 :(得分:2)

有关如何在rails4 http://edgeguides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

中执行此操作的一些选项

答案 6 :(得分:2)

对于mongoid,我最终使用http://mongoid.org/en/mongoid/docs/persistence.html 具体来说,您可以使用:

person.set(name:"Robert Pulson")

并且不会发出回调。太酷了。

答案 7 :(得分:1)

也许你的其他before_save挂钩应该在再次加密之前检查用户的密码是否已经实际更改。

答案 8 :(得分:1)

您有多种选择,包括更改您使用的回调,例如after_create

您可以在不触发回调的情况下更新列,请参阅AR指南中的Skipping Callbacks。例如,update_column不会触发回调。上一个链接列出了非触发函数。

您还可以使用任何Conditional Callback表单(甚至是观察者)来更改密码。请参阅ActiveModel::Dirty,例如@user.password_changed?

答案 9 :(得分:0)

您可以这样做来更新列

  

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