Guilherme Luiz
Guilherme Luiz

Reputation: 127

How to properly pass params to an object using form_for?

I'm trying to make an API which passes the filled form symbols, new.html.erb, to an object in another view, using form_for and params[], show.html.erb, that shows a post with the filled form, but I can't find the right way, or the best way to do it, something goes wrong when I try to pass the params to the other view

views/recipes/new.html.erb

 <%= form_for :recipe, url: recipes_show_path do |r| %>
 Título: <%= r.text_field :title%><br />
 Tipo da Receita: <%= r.text_field :recipe_type%><br />
 Cozinha: <%= r.text_field :cuisine %><br />
 Dificuldade: <%= r.text_field :dificulty %><br />
 Tempo de Preparo: <%= r.text_field :cook_time_min %><br />
 Ingredientes: <%= r.text_field :ingredients %><br />
 Como Preparar: <%= r.text_field :cook_method %><br />
 Enviar: <%= r.submit %>
 <% end %>

views/recipes/show.html.erb

<h3>Detalhes</h3>
<p><%= @recipe.recipe_type %></p>
<p><%= @recipe.cuisine %></p>
<p><%= @recipe.difficulty %></p>
<p><%= @recipe.cook_time_min %></p>
<h3>Ingredientes</h3>
<p><%= @recipe.ingredients %></p>
<h3>Como Preparar</h3>
<p><%= @recipe.cook_method %></p>

<%= link_to 'Voltar', root_path %>

recipes_controller.rb

 class RecipesController < ApplicationController
  def index
    @recipes = Recipe.all
  end
  def new
  recipe = Recipe.new
  recipe.title = [:title]
  recipe.recipe_type = [:recipe_type]
  recipe.cuisine = [:cuisine]
  recipe.difficulty = [:difficult]
  recipe.cook_time_min = [:cook_time_min]
  recipe.ingredients = [:ingredients]
  recipe.cook_method = [:cook_method]
  recipe.save
  
  redirect recipes/show
  end
  def show
    @recipe = Recipe.find(params[:id])
  end
end

routes.rb

Rails.application.routes.draw do

  get 'recipes/show'
  get 'recipes/new'
  root to: 'recipes#index'
  resources :recipes
end

Upvotes: 0

Views: 872

Answers (2)

max
max

Reputation: 101811

Do not use symbols with form_for. This feature has repeatedly been flagged for depreciation and is not recommended, instead pass an actual variable.

<%= form_for(@recipe) do |f| %>
   # ...
<% end %>

Avoid explicitly adding a URL to the form - if you embrace convention over configuration you can reuse the same form for the edit/update action.

If what you want is to actually persist the object to the database you would set it up like so:

# config/routes.rb
resources :recipies, only: [:new, :create, :show]
# get rid of that other junk
class RecipesController < ApplicationController
  # GET /recipies/:id
  def show
    @recipe = Recipe.find(params[:id])
  end

  # GET /recipies
  def index
    @recipes = Recipe.all
  end

  # this action just displays a form
  # GET /recipies/new
  def new
    @recipe = Recipe.new
  end

  # this action handles the form submission and saves the record in the db
  # POST /recipies
  def create
    @recipe = Recipe.new(recipe_params)
    # don't just assume the input is valid!
    if @recipe.save
      redirect_to @recipe # redirects to recipes/:id
    else
      render :new # just renders the view - does not redirect 
    end
  end

  private 
  # this method whitelists the parameters we want to assign
  # if you are copying a hash key by key you're doing it wrong
  def recipe_params
    params.require(:recipe).permit(
     :title, :recipe_type, :cuisine, :difficult, 
     :cook_time_min, :ingredients, :cook_method
    )
  end
end

What you want to do is really strange. If you really wanted to pass an unpersisted object through a redirect you would have to place all the parameters in the query string:

# recipes/show?recipe[title]="Foo"&recipe[recipe_type]="Bar"...
redirect_to(recipe_path(recipe: recipe.attributes))

And then extract out all the parameters again on the other end:

@recipe = Recipe.new(recipe_params)

That's why you render instead of redirecting when a record is invalid. And when you redirect to the new record you just use the id of the record instead of trying to pass all the attributes.

Upvotes: 2

Rockwell Rice
Rockwell Rice

Reputation: 3002

Here is what you have to do

First adjust your new method

def new
  @recipe = Recipe.new
end

Now build out a create method to handle saving the data.

def create
  recipe = Recipe.new <-- I think you will need this with this set up
  recipe.title = params[:recipe][:title]
  recipe.recipe_type = params[:recipe][:recipe_type]
  recipe.cuisine = params[:recipe][:cuisine]
  recipe.difficulty = params[:recipe][:difficult]
  recipe.cook_time_min = params[:recipe][:cook_time_min]
  recipe.ingredients = params[:recipe][:ingredients]
  recipe.cook_method = params[:recipe][:cook_method]
  if recipe.save
    redirect_to recipe
  else
    # Probably some error handling?
  end
end

Change where the form submits to (the variable has to match what is set in the new method so it submits to the create method, saves the data and then redirects to the show method.

<%= form_for(@recipe) do |r| %>

Upvotes: 1

Related Questions