19 Mar 2013, 10:48
Generic-user-small

Mr H (8 posts)

Hi guys, After I have fixed the NameError in LineItemsController#create I have got this weird issue:

ActionController::ActionControllerError in LineItemsController#create

Cannot redirect to nil!

app/controllers/line_items_controller.rb:50:in `block (2 levels) in create'

Which is in app/controllers/line_items_controller.rb line 50

 format.html { redirect_to(@line_item.cart,
          :notice => 'Line item was successfully created.') }

I thought cart is built in her in app/controllers/line_items_controller.rb

   @cart = current_cart
    product = Product.find(params[:product_id]) 
    @line_item = @cart.line_items.build(:product_id => product.id)
    @line_item = LineItem.new(params[:line_item])

Apparently not. Any solution? Cheers and thank you in advance

19 Mar 2013, 13:19
Samr_small_pragsmall

Sam Ruby (584 posts)

The following line does indeed correctly create a line item in the cart:

@line_item = @cart.line_items.build(:product_id => product.id)

Unfortunately, the next line creates a new line item, without a cart:

@line_item = LineItem.new(params[:line_item])

Delete that line, and the code should work.

20 Mar 2013, 10:39
Generic-user-small

Mr H (8 posts)

Hmmm. This is indeed fixed the problem.

Can you have a quick explanation for it. I am a bit confused now. I understand this one:

@line_item = @cart.line_items.build(:product_id => product.id)

Dont we need this line to add a new line to it though?

@line_item = LineItem.new(params[:line_item])

Thank you for your help in advance.

20 Mar 2013, 11:19
Samr_small_pragsmall

Sam Ruby (584 posts)

The short answer is that build calls new for you. And automatically sets up one column for you (in addition to the columns it sets up based on the arguments you pass to the method).

In other words, the following two statements are equivalent:

@line_item = @cart.line_items.build(:product_id => product.id)
@line_item = LineItem.new(:cart_id => @cart.id, :product_id => product.id)

If you take a look at the form, you will see that the only parameter (params) you are passing for :line_item is a single parameter: product_id. Given this, a third way to accomplish the same thing would be:

@line_item = LineItem.new(params[:line_item])
@line_item.cart_id = @cart.id

Which one you chose to use comes down to a matter of personal preference. The point of this exercise was to expose you to another choice.

20 Mar 2013, 21:05
Generic-user-small

Adrian Swarzyński (1 post)

Hello!

It seems that:

@line_item = @cart.line_items.build(:product_id => product.id)

and

@line_item = @cart.line_items.new(:product_id => product.id)

does the same thing because “build” is an alias of “new” in Rails 4. Link: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L101 In Rails 3.0 behaviour of “build” and “new” was different - link: http://stackoverflow.com/a/4954542/2074966

20 Mar 2013, 21:23
Samr_small_pragsmall

Sam Ruby (584 posts)

Adrian: that’s a /slightly/ different discussion…

LineItem.new is a class method for classes derived from ActiveRecord.

@cart.line_items.new is an instance method for classes derived from ActiveRecord::Relation.

(I’ll also note that Mr H appears to be using Rails 3.1 or earlier as the instructions provided in the book targeting Rails 3.2 are different.)

21 Mar 2013, 02:42
Generic-user-small

Mr H (8 posts)

@Sam Ruby Thanks mate. I still have long way to fully understand on this logic. Anyway thank you for your help. Also I am using Rails 3.2.12

Cheers

  You must be logged in to comment