Kelly
Kelly

Reputation: 469

creating has_one association error Rails 4

I'm trying to create and order that is associated with an item.

An Order has one item:

class Order < ActiveRecord::Base
    has_one :item
end

An Item belongs to an order:

class Item < ActiveRecord::Base
  belongs_to :user 
end 

According to the guide this should work:

build_association(attributes = {})
create_association(attributes = {})

I have this in my controller:

def create
    @order = @current_item.build_order(order_params)
    @order.save
    redirect_to @order
end 

And this is the error I'm getting:

undefined method `build_order' for nil:NilClass

I know this has to do with how I've defined current_items but I've tried many different things and all lead to this same error message.

I have this in my application helper:

def current_item
   Item.find(params[:id])
end

Can anyone point me in a better direction for how to define this or what I'm doing wrong here. Thanks for your help!

Upvotes: 2

Views: 599

Answers (3)

mmartinson
mmartinson

Reputation: 240

The error you're getting is being caused by trying to run Item.find(params[:id]) but not passing it a valid value. It seems that params[:id] is maybe nil? Can you confirm this using a debugger or by temporarily adding raise "Params[:id] is set to #{params[:id]} to the first line of the method, running the code and seeing what it says in the terminal output?

All you need to do make this work is have a parameter value for the item come from the form that is being submitted. Normally rails uses the route/url to populate the value of params[:id]. For example, when the request is GET /items/1, params[:id] is 1.

In this case though, unless you've done some custom routing that you haven't shown in your question, creating a new order would usually be a POST to /orders and since there is no id in the url, params[:id] is nil.

It's up to you to add the item id from the order form. It would make sense that it would be sent with the rest of the order params as item_id, rather than just id, since id is usually used to reference the current object, which is a new order and therefore doesn't get have an id.

You'll need to make sure that item_id is whitelisted in your strong params with the rest of the values in the order_params method (I assume you defined this in the same controller but did not show it in the code), and then the code would look something like this.

def create
  @order = current_item.build_order(order_params)
  @order.save
  redirect_to @order
end 

#note the changes the the argument
def current_item
  Item.find(order_params[:item_id])
end

def order_params
  params.require(:order).permit(:item_id, :other_values_that_you_send)
end

Upvotes: 0

Mihail Petkov
Mihail Petkov

Reputation: 1545

1) You don't have access to a helper method from the controller. You can include the helper class in your controller but it's a really bad practice. You must use helper methods only in the views.

2) You can move current_item method from the helper to the controller. Then there will be another problem. In your create method, you are trying to access instance variable @current_item which is not initialized at the moment, not the method. You can do it this way:

@order = @current_item.build_order(order_params)

to

@order = current_item.build_order(order_params)

Then current_item will return you Item object.

3) I am not sure what are your params, but you can implement it this way:

def create
  @order = Order.new(params[:order])
  @order.save
  redirect_to @order
end

where params[:order] is for example:

{name: "order 1", item_id: 1}

Upvotes: 3

Paweł Dawczak
Paweł Dawczak

Reputation: 9649

You should change your create to use a method, rather a variable, so modify it as follows:

def create
  @order = current_item.build_order(order_params)
  @order.save
  redirect_to @order
end 

# rest of code

def current_item
  Item.find(params[:id])
end

This should help.

Good luck!

Upvotes: 0

Related Questions