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
一些select如何在rails4中做到这一点http://edgeguides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks
对于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指南中还有其他选项,但是我发现这种方法是最简单的。