【问题标题】:Reloading ActiveRecord objects in Rspec (particularly after a POST request)在 Rspec 中重新加载 ActiveRecord 对象(特别是在 POST 请求之后)
【发布时间】:2015-09-28 16:36:01
【问题描述】:

我的User 模型上有一个time_zone 属性,用于跟踪用户的首选时区。默认以nil 开头。

在他们的个人编辑页面上,用户可以通过从下拉列表中选择另一个时区来更改他们的时区。

我的测试如下——

it "updates the user's time zone on submit" do
  # Creates with FactoryGirl
  @user = create(:user)

  # BEFORE state confirmation
  expect(@user.time_zone).to be_nil

  # Simulate the user selecting a timezone from the dropdown on their edit page. 
  # Capybara is used for selection and clicking.
  visit edit_profile_path
  select_time_zone_from_dropdown("America/New_York")

  # Submit, which sends a POST request to update the User model
  click_button("Submit")

  # AFTER state confirmation - this FAILS
  # Apparently the reload doesn't work and `time_zone` is still set to
  # nil for this user 
  @user.reload
  expect(@user.time_zone).to eq("America/New_York")
end

如您所见,测试失败是因为 time_zone 从未为此用户记录更新。

这就是奇怪的地方 -

  1. 在数据库中,正确的值确实发生了变化。只是ActiveRecord 对象没有

  2. 为了绕过#1,我尝试重新加载对象属性,但没有成功

  3. 如果我在 reload 之后使用 binding.pry 暂停它并运行 @user.reload 手动,它可以工作。所以它只是在测试套件期间运行时不起作用。

缓存和重新加载值的方式有什么奇怪的吗?

谢谢!

【问题讨论】:

  • 您确定@user 对象是被更改的对象吗? “edit_profile_path”如何知道要编辑哪个用户?
  • 可能是时间问题,你能不能加一个expect(page).to have('some_selector')然后@user.reload

标签: ruby-on-rails ruby activerecord rspec


【解决方案1】:

这是因为 Capybara 使用不同的数据库连接。我遇到了这个问题并使用这个补丁解决了这个问题,它强制所有线程使用相同的连接。

class ActiveRecord::Base
  mattr_accessor :shared_connection
  @@shared_connection = nil

  def self.connection
    @@shared_connection || retrieve_connection
  end
end

# Forces all threads to share the same connection. This works on
# Capybara because it starts the web server in a thread.
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection

source

确保在您的 spec_helper 文件中需要此代码

【讨论】:

  • 谢谢,这似乎是正在发生的事情。我在这里找到了更多关于它的文献 - gist.github.com/josevalim/470808 - 似乎仍然有点问题!我仍然感到困惑的是为什么测试中的user.reload 不起作用。即使它与 Capybara 使用的连接不同,它也应该从根本上重新从数据库中提取所有信息(已正确更新),所以不应该单独解决问题吗?再次感谢! (编辑:澄清一下,它确实适用于你的修复 + user.reload。我只是说我希望它在没有你的补丁的情况下也能工作,对吧?)
  • @user2490003,补丁前的问题是因为每次测试之前,rspec都会打开一个事务,最后回滚。然后,当您在测试中调用 user.reload 时,事务是打开的,并且更改不会提交到数据库。
  • 这很有意义,再次感谢您。你为我省了很多麻烦
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-19
  • 2011-09-30
相关资源
最近更新 更多