Rails 4:.save不更新现有记录的updated_at?

时间:2014-06-18 16:26:15

标签: ruby-on-rails rspec

我一直认为.save.save!会更新现有记录的updated_at列。这不是真的吗?如果是这样,那么每次保存时我是否需要创建一个before_save过滤器来更新它?

今天是6月18日:

    Loading development environment (Rails 4.1.1)
    irb(main):001:0>  o = Order.last
      Order Load (0.4ms)  SELECT  `orders`.* FROM `orders`   ORDER BY `orders`.`id` DESC LIMIT 1
    => #<Order id: 24, user_id: 1, order_date: nil, total_cents: 0, total_currency: "USD", shipping_cents: 0, shipping_currency: "USD", tax_cents: 0, tax_currency: "USD", subtotal_cents: 0, subtotal_currency: "USD", created_at: "2014-06-13 21:24:38", updated_at: "2014-06-13 21:24:38", status: "Incomplete", coupon_id: nil>
    irb(main):002:0> o.save!
       (0.4ms)  BEGIN
       (0.3ms)  COMMIT
    => true
    irb(main):003:0> o.updated_at
    => Fri, 13 Jun 2014 21:24:38 UTC +00:00
    irb(main):004:0> o.reload
      Order Load (0.7ms)  SELECT  `orders`.* FROM `orders`  WHERE `orders`.`id` = 24 LIMIT 1
    => #<Order id: 24, user_id: 1, order_date: nil, total_cents: 0, total_currency: "USD", shipping_cents: 0, shipping_currency: "USD", tax_cents: 0, tax_currency: "USD", subtotal_cents: 0, subtotal_currency: "USD", created_at: "2014-06-13 21:24:38", updated_at: "2014-06-13 21:24:38", status: "Incomplete", coupon_id: nil>
    irb(main):005:0> o.updated_at
    => Fri, 13 Jun 2014 21:24:38 UTC +00:00

我关心这个的原因是因为我用ActiveRecord::Base.transaction包裹了一个函数的内部结构,所以我想测试一下出现问题时它们没有更新:

Rspec测试(当它不应该时,它会一直传递,因为无论成功或失败都没有更改updated_at):

  it "rollsback the transaction" do
    ...
    order.stub(:save!).and_raise(StandardError)
    expect { payment_info.save }.not_to change { [billing_address.updated_at, 
                                                  shipping_address.updated_at,
                                                  order.user.updated_at,
                                                  order.updated_at] }
  end

我的方法:

def process_billing_info!
  ActiveRecord::Base.transaction do
    billing_address.save!
    shipping_address.save!
    user.save!
    order.update_all_fees!
  end
rescue Exception => e
  false
end

2 个答案:

答案 0 :(得分:15)

正如您在日志中看到的那样,没有执行UPDATE SQL查询。 Rails根本没有更新你的记录。这是因为.save实际只有在对该记录进行了更改时才会保存记录。

您可以调用.touch方法来更新updated_at字段,而无需对记录进行更改:

1.9.3p489 :005 > Intervention.first.touch
  Intervention Load (12.9ms)  SELECT "interventions".* FROM "interventions" LIMIT 1
  SQL (20.5ms)  UPDATE "interventions" SET "updated_at" = '2014-06-18 16:34:03.924648' WHERE "interventions"."id" = 1
 => true 

在这里,我们看到UPDATE SQL查询。

答案 1 :(得分:2)

与@ MrYoshiji的回答相配,这是使用.touch的另一种方式:

if o.save!
  o.touch unless o.changed?
end