Rails:更新模型属性,无需调用callback

我有一个具有:credits特性的用户模型。 我想要一个简单的button,通过名为“add”的路由添加5到用户的信用点,以便/ users / 3 / add将添加5到用户id = 3的信用点。

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

这是我的控制器的相关部分。 问题是,我不想调用@ user.save,因为我有一个before_savecallback,根据当前的UTC时间重新encryption用户的密码。 我只想简单地加上5个属性,避免callback,我从来没有想过这么简单的事情可能是如此艰难。

编辑:

我把callback改为: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:

好吧,这是一个validation问题,使“编辑”的变化不起作用,但我仍然喜欢回答没有callback更新的原始问题!

Rails 3.1引入了update_column ,它与update_attribute相同,但没有触发validation或callback:

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

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

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

如果你真的想要甚至可以尝试一个update_columns方法,并将其混入到活动logging基类中。

要更新一个属性,你可以使用update_column。 另外还有一些具体的方法可以在rails guide中findhttp://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

你应该可以使用update_all来避免触发callback。

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

我宁愿把这个逻辑放在模型中,但是这应该能够解决你在控制器中的原始问题。

我想你应该在这种情况下使用方法update_counters 。 在你的控制器动作中像这样使用它:

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

对于mongoid,我结束了使用http://mongoid.org/en/mongoid/docs/persistence.html特别是,你可以使用:;

 person.set(name:"Robert Pulson") 

不会发生callback。 非常酷。

也许你的其他before_save钩子应该检查用户的密码是否已经改变,然后再次encryption。

您有许多选项,包括更改您使用的callback,例如after_create

您可以在不触发回叫的情况下更新列,请参阅AR指南中的“ 跳过回叫 ”。 例如, update_column不会触发callback。 上一个链接列出了非触发function。

您也可以使用任何条件callbackforms(甚至观察员)来更改密码。 请参阅ActiveModel :: Dirty ,例如@user.password_changed?

作为一般的答案,在Rails 4中,这是更新属性而不触发callback的简单方法:

 @user.update_column credits:5 

如果您需要更新多个属性而不触发callback:

 @user.update_columns credits: 5, bankrupt: false 

如果您愿意, Rails指南中还有其他选项,但是我发现这种方法是最简单的。