crystal
crystal

Reputation: 3

undefined method `map' for nil:NilClass when submitting the selection tag

I am new to Rails. And now I have a question when submitted the form. When submitted the form, it will shows

NoMethodError in Foods#new, Showing ..../new.html.erb where line #16 raised:
undefined method `map' for nil:NilClass

while the line 16 is:

<%= select_tag(:category_id, options_for_select(@categories), :prompt => "Please select") %>

I am a little confused with the method map, do I need to add it into create action?

here is my new action

def new
@food = Food.new    
@categories = Category.all.map{|c| [ c.name, c.id ] }
end

And here is my create action

def create
@food = Food.new(food_params)
@food.category_id = params[:category_id]

if @food.save
  flash[:success] = "Adding Successful!"
  redirect_to @food
else
  render 'new'
end
end

def food_params
params.require(:food).permit(:name, :price, :category_id, :description, :picture)
end

Would anyone could help me solve the problem?

Upvotes: 0

Views: 912

Answers (3)

Mohammad AbuShady
Mohammad AbuShady

Reputation: 42899

You probably don't have any categories in your database, a more safe method would be using collection_select, it should handle empty collections gracefully.

First here's the controller

def new
  @food = Food.new    
  @categories = Category.all
end

Then the view

collection_select(:food, :category_id, @categories, :id, :name)

The other problem is the absense of the @categories in the creation action when the @food isn't saved, and that fails when the form is building the dropdown, If you want to simplify this you could add a method that prepares this

def prepare_form_data
  @categories = Category.all
end

def new
  @food = Food.new
  prepare_form_data
end
def create
  @food = Food.new(food_params)
  if @food.save
    # do stuff
  else
    prepare_form_data # prepare the data for the second form
    render :new
  end
end

Upvotes: 1

Stephen
Stephen

Reputation: 357

I see one issue in your create method.

In the event @food.save == false, you're not building

@categories = Category.all.map{|c| [ c.name, c.id ] }

before

render 'new'

So likely your form isn't getting the @categories info it needs to build the select statement.

Upvotes: 1

kddeisz
kddeisz

Reputation: 5192

When you do render 'new', it copies over instance variables into that ERB rendering. In your new action you make an instance variable @categories = Category.all.map{|c| [ c.name, c.id ] } and then reference it. You need to define that in the create action as well in the else. Preferably with a shared method.

As in:

before_action ->{ @categories = Category.all.map { |c| [c.name, c.id] } }, only: %i[new create]

def new
  @food = Food.new
end

def create
  @food = Food.new(food_params)
  @food.category_id = params[:category_id]

  if @food.save
    flash[:success] = 'Adding successful!'
    redirect_to @food
  else
    render 'new'
  end
end

Upvotes: 0

Related Questions