我有一个具有: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:
好的,这是一个验证问题,导致“编辑”中的更改不起作用,但我仍然喜欢没有回调的原始更新问题的答案!
答案 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')