steel
steel

Reputation: 12520

Account for instance variable set by session value in controller

I am trying to test a 'post create' action in a controller. During 'create', in the controller, I assign a variable whose values modify the new record before that record is saved. That variable, @trip, is created from a session value that I can't seem to account for.

So my question is, given what I am trying to test, what is the best way (or any way) to account for an instance variable in a controller when that variable is set by a session value?

Error message:

OrderItemsController POST create with valid attributes creates a new order item
Failure/Error: expect{ post :create, order_item: FactoryGirl.attributes_for(:order_item) }.to change(OrderItem,:count).by(1)
NoMethodError:
       undefined method `company_id' for nil:NilClass
 # ./app/controllers/order_items_controller.rb:29:in `create'
 # ./spec/controllers/order_items_controller_spec.rb:47:in `block (4 levels) in <top (required)>'

Controller spec:

describe "POST create action" do
    let(:trip)              { create(:trip)}
    let(:trip_date)         { create(:trip_date) }
    let(:buyer)             { create(:buyer) }
    let(:company)           { create(:company) }
    let(:order_item)        { attributes_for(:order_item, trip_date_id: trip_date.id, buyer_id: buyer.id, company_id: company.id) }
    let(:bad_order_item)    { attributes_for(:bad_order_item, trip_date_id: trip_date.id, buyer_id: buyer.id, company_id: company.id) }

    context "given valid order item attributes" do
        it "creates a new order item" do
            expect{ post :create, { order_item: order_item, trip_id: trip.id } }.to change(OrderItem, :count).by(1)
        end
    end
end

Error references line 29 of my order_items_controller.rb, where the variable comes in:

line 25:    def create
line 26:        @trip = Trip.find_by_id(session[:current_trip_id])
line 27:        @order_item = OrderItem.new(order_item_params)
line 28:        @order_item.buyer_id            = current_user.id
> line 29:      @order_item.company_id          = @trip.company_id
line 30:        @order_item.first_person_cost   = @trip.first_person_cost
line 31:        @order_item.second_person_cost  = @trip.second_person_cost

line 32:        if @order_item.save
line 33:            redirect_to cart_path(current_user), notice: 'New order item created.'
line 34:        else
line 35:            render 'new', notice: 'Unable to create new order item.'
line 36:        end    
line 37:    end  

OTHER ATTEMPTS

b. I have also tried:

    let(:trip_date)         { create(:trip_date) }
    let(:buyer)             { create(:buyer) }
    let(:company)           { create(:company) }
    let(:order_item)        { attributes_for(:order_item, trip_date_id: trip_date.id, buyer_id: buyer.id, company_id: company.id) }
    let(:bad_order_item)    { attributes_for(:bad_order_item, trip_date_id: trip_date.id, buyer_id: buyer.id, company_id: company.id) }

    describe "POST create" do
        let(:trip)     {create(:trip) }
        context "with valid attributes" do
            it "creates a new order item" do
              Trip.stub_chain(:friendly, :find_by_id).and_return(trip)
              expect{ post :create, order_item: order_item }.to change(OrderItem,:count).by(1)
              end
          end
        end
    end

Resulting in the same error.

c. I have also tried

describe "POST create action" do
    let(:trip)              { create(:trip) }
    let(:trip_date)         { create(:trip_date) }
    let(:buyer)             { create(:buyer) }
    let(:company)           { create(:company) }
    let(:order_item)        { attributes_for(:order_item, trip_date_id: trip_date.id, buyer_id: buyer.id, company_id: company.id) }
    let(:bad_order_item)    { attributes_for(:bad_order_item, trip_date_id: trip_date.id, buyer_id: buyer.id, company_id: company.id) }

    context "given valid order item attributes" do
        it "creates a new order item" do
            expect{ post :create, order_item: order_item, trip_id: trip.id }.to change(OrderItem, :count).by(1)
        end
    end
end

Resulting in the same error.

d. I have also tried:

    describe "POST create action" do
        let(:trip_date)         { create(:trip_date) }
        let(:buyer)             { create(:buyer) }
        let(:company)           { create(:company) }
        let(:bad_order_item)    { attributes_for(:bad_order_item, trip_date_id: trip_date.id, buyer_id: buyer.id, company_id: company.id) }

        context "given valid order item attributes" do
            it "creates a new order item" do
            Trip.stub_chain(:friendly, :find_by_id).and_return(trip)
            order_item = attributes_for(:order_item, trip_date_id: trip_date.id, buyer_id: buyer.id, company_id: company.id)
            expect{ post :create, order_item: order_item }.to change(OrderItem, :count).by(1)
        end
    end

Resulting in:

1) OrderItemsController POST create action given valid order item attributes creates a new order item
    Failure/Error: Trip.stub_chain(:friendly, :find_by_id).and_return(trip)
    NameError:
        undefined local variable or method `trip' for #<RSpec::ExampleGroups::OrderItemsController_2::POSTCreateAction::GivenValidOrderItemAttributes:0x0000010154d5d8>
        # ./spec/controllers/order_items_controller_spec.rb:41:in `block (4 levels) in <top (required)>'

Any help is appreciated. It's been a couple weeks. Thanks.

Upvotes: 1

Views: 200

Answers (2)

steel
steel

Reputation: 12520

I finally googled the right terms, and found the Rails docs that discuss how to set session variables for each action. My solution looked like this:

expect{ post :create, {order_item: order_item}, {"current_trip_id" => trip.id}  }.to change(OrderItem, :count).by(1)

My salvation lay here: http://guides.rubyonrails.org/testing.html

Upvotes: 1

zetetic
zetetic

Reputation: 47548

expect{ post :create, order_item: order_item, trip_id: trip.id }

Try changing this to:

expect{ post :create, { order_item: order_item, trip_id: trip.id } }

post takes both a params hash and a session hash as arguments; all of the posted params should be in a single hash.

Upvotes: 0

Related Questions