Reputation: 3
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
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
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
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