user2490003
user2490003

Reputation: 11920

Reloading ActiveRecord objects in Rspec (particularly after a POST request)

I have a time_zone attribute on my User model which tracks the user's preferred time_zone. This starts off as nil by default.

On their personal EDIT page, the user can change their timezone by selecting another one from a dropdown list.

My test is as follows -

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

As you can see, the test fails because the time_zone is never updated for this User record.

Here's what's strange -

  1. In the database, the value correctly DOES change. It's just the ActiveRecord object which doesn't

  2. To get around #1, I tried reloading the object attributes, but no luck

  3. If I pause it with binding.pry just after the reload and run @user.reload manually, it works. So it's just while running during the test suite that it's not working.

Is there something strange going on here with how the value is cached and reloaded?

Thanks!

Upvotes: 1

Views: 1405

Answers (1)

Rodrigo
Rodrigo

Reputation: 4802

this happens because Capybara uses a different connection to database. I had this problem and solved using this patch, which forces all threads to use the same connection.

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

Make sure to require this code in your spec_helper file

Upvotes: 2

Related Questions