I am using Rails 4 and have the following error.
Routing Error
No route matches [POST] "/logs/1/meals/13/edit
I’m passing form_for the model object using :meal and the edit page is rendering correctly. However, Rails does not seem to be checking whether or not the meal object has already been saved, so it keeps trying to send the form to the #create action and tries make a POST request instead of sending the form to the update action and making a PUT request when I hit submit.
How do I get the form_for to recognize that I am trying to update an existing object and that PUT is needed instead of POST? Everything else is working and I’ve run all of my migrations. I’m pretty new to Rails, and I’ve spent almost all day trying to figure this out on my own. Please help!
And just to note, when I tried to pass in the model object as @meal.log instead of :meal, Rails was no longer able to recognize :calorie_estimate or :meal_description. Passing the model object as @meal.log left me with a no method error.
meals/edit.html.erb
<h3> EDIT MEAL </h3>
<%= form_for(:meal) do |f| %>
<div id="meal-form">
<%= f.text_field :calorie_estimate, class: 'meal-form-fields', :placeholder => "Calorie Estimate" %>
<%= f.text_field :meal_description, class: 'meal-form-fields', :placeholder => "Food Description" %>
<div class="submit-form" style="width: 75px; height: 15px;">
<%= f.submit 'UPDATE', :class => 'submit-form-text' %>
</div>
</div>
<% end %>
meals_controller.rb
class MealsController < ApplicationController
include MealsHelper
def create
@meal = Meal.new(meal_params)
@meal.log_id = params[:log_id]
@meal.save
redirect_to log_path(@meal.log)
end
def edit
@meal = Meal.find(params[:id])
end
def update
@meal = Meal.find(params[:id])
@meal.update(meal_params)
redirect_to log_path(@log)
end
def meal_params
params.require(:meal).permit(:calorie_estimate, :meal_description)
end
end
possible routes:
Prefix Verb URI Pattern Controller#Action
root GET / logs#index
log_meals GET /logs/:log_id/meals(.:format) meals#index
POST /logs/:log_id/meals(.:format) meals#create
new_log_meal GET /logs/:log_id/meals/new(.:format) meals#new
edit_log_meal GET /logs/:log_id/meals/:id/edit(.:format) meals#edit
log_meal GET /logs/:log_id/meals/:id(.:format) meals#show
PATCH /logs/:log_id/meals/:id(.:format) meals#update
PUT /logs/:log_id/meals/:id(.:format) meals#update
DELETE /logs/:log_id/meals/:id(.:format) meals#destroy
logs GET /logs(.:format) logs#index
POST /logs(.:format) logs#create
new_log GET /logs/new(.:format) logs#new
edit_log GET /logs/:id/edit(.:format) logs#edit
log GET /logs/:id(.:format) logs#show
PATCH /logs/:id(.:format) logs#update
PUT /logs/:id(.:format) logs#update
DELETE /logs/:id(.:format) logs#destroy
routes.rb
Rails.application.routes.draw do
root to: 'logs#index'
resources :logs do
resources :meals
end
end
schema.rb
ActiveRecord::Schema.define(version: 20160128205351) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "logs", force: :cascade do |t|
t.string "entry_date"
t.integer "calorie_goal"
t.string "notes"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "meals", force: :cascade do |t|
t.integer "calorie_estimate"
t.string "meal_description"
t.integer "log_id"
t.datetime "created_at"
t.datetime "updated_at"
end
end
The issue is that you're using nested resources
, hence you're confused about which @objects
to pass to your form_for
.
#app/views/meals/edit.html.erb
<%= form_for [@log, @meal] do |f| %>
As you have it presently, passing :meal
is ambiguous - Rails cannot discern the route / method to send its submission to, as it doesn't have that data available.
If you wanted to update an object, you'll have to pass the appropriate data to the form, including the object's id
:
<%= form_for :meal, url: { controller: "meals", action: "update", id: "5" }, method: :put do |f| %>
Such as Rails is object orientated, you'll be best passing the actual object to your form_for
:
<%= form_for @meal ...
--
The issue you have is that you have a nested resource:
resources :logs do
resources :meals #-> url.com/logs/:log_id/meals/:id
end
This means you need to pass both the Log
and Meal
values to your form
:
#app/controllers/meals_controller.rb
class MealsController < ApplicationController
def edit
@log = Log.find params[:log_id]
@meal = Meal.find params[:id]
end
def update
@log = Log.find params[:log_id]
@meal = Meal.find params[:id]
@meal.update meal_params
end
end
#app/views/meals/edit.html.erb
<%= form_for [@log, @meal] do |f| %>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With