Rails form_for causes POST instead of PUT when trying to edit

I am using Rails 4 and have the following error.

Routing error
No route matches [POST] "/ logs / 1 / meal / 13 / edit

Im passing form_ to the model object using: the food and the edit page are displayed correctly. However, Rails doesn't seem to check if the food object is saved or not, so it tries to submit the form to the #create action and tries to make a POST request instead of submitting the form to the update action and the PUT request when I hit submit.

How do I get form_for to recognize that I am trying to update an existing object and that PUT is needed instead of POST? Everything else works, and Ive triggered all my migrations. Im pretty new to Rails, and Ive spent almost all day trying to figure it out on my own. Please help!

And just to mention, when I tried to pass the model object as @ meal.log instead of: meal, Rails could no longer recognize: calorie_estimate or: meal_description. Passing the model object as @ meal.log left me without a method error.

nutrition / 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 
+5
source share
3 answers

The problem is that you are using nested resources , so you are confused about which @objects to switch to your form_for .

 #app/views/meals/edit.html.erb <%= form_for [@log, @meal] do |f| %> 

How you do it, transmission :meal mixed . Rails cannot recognize the route / method for submitting its application because it does not have data available.

If you want to update the object, you need to submit the corresponding data to the form, including the id object:

 <%= form_for :meal, url: { controller: "meals", action: "update", id: "5" }, method: :put do |f| %> 

For example, Rails is a oriented object , you better pass the actual object to your form_for :

 <%= form_for @meal ... 

-

The problem 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 the Log and Meal values to the 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| %> 
+3
source

You will get the error:

  Routing Error No route matches [POST] "/logs/1/meals/13/edit 

indicates that your form is performing POST instead of PUT.

To make this work, simply add method: :put to the form_for declaration:

 <%= form_for(:meal, method: :put) do |f| %> 
0
source

If your controller creates an instance variable named @meal , you should use this instead of a character. Therefore write:

 form_for @meal do |f| 

and then the rails can query the instance variable to see if it is new_record? (in this case it will be POST data) or an existing record (in which it will most likely be PATCH).

To build a nested route, you will need to set the @log instance @log (I don't see this in your code, but you probably already did), and then you can write:

 form_for [@log, @meal] do |f| 

which will calculate the correct path.

0
source

Source: https://habr.com/ru/post/1242254/


All Articles