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


76

我有一个具有:credits属性的用户模型。我想要一个简单的按钮,通过名为“ 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_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:

好的,这是一个验证问题,无法使“ EDIT”中的更改生效,但我仍然很乐意回答不使用回调进行更新的原始问题!


我提供了一个链接,其中列出了不触发回调的方法,并且Finbarr和我都建议使用条件回调-您还在寻找其他解决方案吗?
戴夫·牛顿

Answers:



15

作为一个普遍的答案,在Rails 4中,这是一种无需触发回调即可更新属性的简单方法:

@user.update_column :credits, 5

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

@user.update_columns credits: 5, bankrupt: false  

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


4
user.update_column积分:5不起作用。它应该是user.update_column'credits',5
Richard H Fung

我正在使用Rails 4.2,这绝对适合我。该行生成以下查询:UPDATE "users" SET "credits" = $1, "updated_at" = $2 WHERE "users"."id" = $3 [["credits", 5], ["updated_at", "2017-04-01 21:34:52.746626"], ["id", 1]]
Matt

1
使用时update_column,您不能通过像这样的对象credits: 5。您必须传递两个参数,第一个是列名,第二个是将其更新为的值。因此,您可以这样做update_column :credits, 5,通常比使用String作为列名更可取。
约书亚·品特

8

要在没有回调的情况下更新多个属性,可以按以下方式在模型中使用update_all:

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

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

要更新一个属性,可以使用update_column。另外,在Rails指南http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks中可以找到一些特定的方法



3

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

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

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

我希望将此逻辑放入模型中,但这应该可以解决控制器中指定的原始问题。



1

也许您的另一个before_save钩子应该在再次加密之前检查用户密码是否确实更改过。


1

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

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

您也可以在更改密码时使用任何条件回调形式(甚至是观察者)。参见ActiveModel :: Dirty,例如@user.password_changed?


好的,我将其更改为“ after_create”,但仍然无法正常工作!查看我的新代码编辑,我无法更改积分。
山姆·斯特恩

@hatboysam好吧,它的功能有所不同-在添加之前,现在要进行设置。使用save!,看看是否有异常(和/或检查日志,和/或删除回溯消音器)。
戴夫·牛顿

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.