Search code examples
ruby-on-railsrubyrspecfactory-botlet

the right way to change the associated object in rspec


I recently started to test with rspec, so I can strongly be mistaken, correct me if there is a better way

I create two related models

let(:user) {FactoryGirl.create :user} 
let!(:participation) {FactoryGirl.create :participation, user: user}

and before one of the tests change one of the related objects

context "when" do
  before {participation.prize = 100}
  it "" do
    binding.pry
  end
end

But inside it

participation.prize => 100
user.participatons.select(:prize) => nil

what am I doing wrong ? and how to fix it?


Solution

  • When you say user.participations.select(:prize), you're making a query to the db to get values in the user's participations' prize columns. But when you say before {participation.prize = 100} you're only setting the prize attribute on the participation object. Try saving the participation before the select line:

    participation.prize # => 100
    participation.save
    user.participatons.select(:prize) # => nil
    

    Another possible issue is that user.participations has been memoized by a previous call. Ensure that user.participations.first == participation. If it doesn't, check

    1) puts participation.user_id and

    2) puts user.participations, user.reload.participations


    Lastly, a better way of setting up the test so that you run into this issue less often is something along the lines of:

    # let(:price) { 0 } # default price. Optional so that tests won't throw errors if you forget to set it in a context/describe block.
    let(:user) {FactoryGirl.create :user} 
    let!(:participation) {FactoryGirl.create :participation, user: user, price: price}
    
    # ...
    
    context "when ..." do
      let(:price) { 100 }
      it "" do
        binding.pry
      end
    end
    

    This way, the price is set when you create the model. Following this pattern generally means running into this problem less.