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

big*_*ato 6 rspec ruby-on-rails

我一直以为.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
Run Code Online (Sandbox Code Playgroud)

我关心这个的原因是因为我正在包装一个函数的内部,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
Run Code Online (Sandbox Code Playgroud)

我的方法:

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
Run Code Online (Sandbox Code Playgroud)

MrY*_*iji 16

正如您在日志中看到的那样,没有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 
Run Code Online (Sandbox Code Playgroud)

这里我们看到UPDATESQL查询.


Fel*_*ger 5

与@MrYoshiji 的回答一起,这是另一种使用方法.touch

if o.save!
  o.touch unless o.changed?
end
Run Code Online (Sandbox Code Playgroud)