为啥在保存对象后使用“重新加载”方法? (Hartl Rails Tut 6.30)

Posted

技术标签:

【中文标题】为啥在保存对象后使用“重新加载”方法? (Hartl Rails Tut 6.30)【英文标题】:Why use 'reload' method after saving object? (Hartl Rails Tut 6.30)为什么在保存对象后使用“重新加载”方法? (Hartl Rails Tut 6.30) 【发布时间】:2014-04-11 03:56:17 【问题描述】:

我正在编写 Hartl 的 Rails 4 教程第 6 章的练习。第一个练习测试以确保用户电子邮件地址的大小写正确:

require 'spec_helper'

describe User do
  .
  .
  .
  describe "email address with mixed case" do
    let(:mixed_case_email)  "Foo@ExAMPle.CoM" 

    it "should be saved as all lower-case" do
      @user.email = mixed_case_email
      @user.save
      expect(@user.reload.email).to eq mixed_case_email.downcase
    end
  end
  .
  .
  .
end

我不明白为什么这里需要“重新加载”方法。一旦将@user.email 设置为mixed_case_email已保存 的内容,@user.reload.email@user.email 不是同一个东西吗?我拿出 reload 方法只是为了尝试它,它似乎没有改变任何测试。

我在这里错过了什么?

【问题讨论】:

【参考方案1】:

该示例要检查的是app/models/user.rb 中的before_save 回调是否完成了它的工作。 before_save 回调应该在将每个用户的电子邮件保存到数据库之前将其设置为小写,因此第 6 章练习 1 想要测试它在数据库中的值(可以使用方法 reload 检索)是否有效地保存为小写。

【讨论】:

【参考方案2】:

内存与数据库

了解内存和数据库的区别很重要。您编写的任何 ruby​​ 代码都在内存中。例如,每当执行查询时,它都会使用数据库中的相应数据创建一个新的内存对象。

# @student is a in-memory object representing the first row in the Students table.
@student = Student.first

你的例子

这是你用 cmets 解释的例子

it "should be saved as all lower-case" do
    # @user is an in-memory ruby object. You set it's email to "Foo@ExAMPle.CoM"
    @user.email = mixed_case_email

    # You persist that objects attributes to the database.
    # The database stores the email as downcase probably due to a database constraint or active record callback.
    @user.save

    # While the database has the downcased email, your in-memory object has not been refreshed with the corresponding values in the database. 
    # In other words, the in-memory object @user still has the email "Foo@ExAMPle.CoM".
    # use reload to refresh @user with the values from the database.
    expect(@user.reload.email).to eq mixed_case_email.downcase
end

要查看更详尽的说明,请参阅post。

【讨论】:

【参考方案3】:
reload 

从数据库中重新加载对象(此处为@user)的属性。它始终确保对象具有当前存储在数据库中的最新数据。

这样我们也可以避免

ActiveRecord::StaleObjectError

这通常发生在我们尝试更改旧版本的对象时。

【讨论】:

【参考方案4】:

是的,在这种情况下 @user.reload.email@user.email 是一回事。但是使用@user.reload.email 而不是@user.email 来检查数据库中究竟保存了什么是一个很好的做法我的意思是你不知道你或某人是否在 after_save 中添加了一些代码来改变它的值然后它不会对你的测试。

编辑: 而且您正在检查的是数据库中保存的内容,因此@user.reload.email 准确反映了数据库中保存的内容然后@user.email

【讨论】:

这个答案是正确的,但不是那么简洁。如果测试模型中定义了诸如 after_create/after_save 等创建后事件,则需要调用 reload()。在这种情况下,执行 save() 方法后,您的内存表示将过时。【参考方案5】:

应该是一样的。重点是 reload 方法从数据库中重新加载对象。现在您可以检查新创建的测试对象是否实际保存了正确/预期的属性。

【讨论】:

以上是关于为啥在保存对象后使用“重新加载”方法? (Hartl Rails Tut 6.30)的主要内容,如果未能解决你的问题,请参考以下文章

场景重新加载后不保存对象名称

python对象保存和重新加载

需要保存 NSmutableArray 的 PathDrawingInfo 对象,以便在重新加载应用程序时使用

为啥使用 Docker 容器的 NextJS 在更改开发环境的代码后没有重新加载?

为啥我的 UIView 在重新加载后没有响应?

Flutter:为啥我的构建器在 Web 服务调用后没有重新加载?