Why am I getting a NoMethodError in Ruby? - ruby-on-rails

I am currently working on an recipe box application, using ruby on rails. When I want to create a new recipe It says
undefined method `title'
for
= f.input :title, input_html: { class: 'form-control' }
This is my form.html.haml
= simple_form_for #recipe, html: { multipart: true } do |f|
- if #recipe.errors.any?
#errors
%p
= #recipe.errors.count
Prevented this recipe from saving
%ul
- #recipe.errors.full_messages.each do |msg|
%li= msg
.panel-body
= f.input :title, input_html: { class: 'form-control' }
= f.input :description, input_html: { class: 'form-control' }
= f.button :submit, class: "btn btn-primary"
And this my recipes_controller.rb
class RecipesController < ApplicationController
before_action :find_recipe, only: [:show, :edit, :update, :destroy]
def index
end
def show
end
def new
#recipe = Recipe.new
end
def create
#recipe = Recipe.new(recipe_params)
if #recipe.save
redirect_to #recipe, notice: "Toll! Neues Rezept erfolgreich erstellt."
else
render 'new'
end
end
private
def recipe_params
params.require(:recipe).permit(:title, :description)
end
def find_recipe
#recipe = Recipe.find(params[:id])
end
end

You have to render form in 'new' view
You have to have column 'title' in your DB
Show us what 'debug #recipe' prints, is there 'title' attribute?

Related

Ruby 2.7.0 on Rails 6.1, 2 separate post forms one view

hope your having a wonderful day drinking some coffee and responding to some forms.
Problem:
As my title states, I am trying to create 2 forms on one view. I am new to ruby on rails.
My controller functions:
Controller name is border_rotation:
def create
if params[:export_submit]
#border_rotation_export = BorderRotationExport.new(border_rotation_export_params)
respond_to do |format|
if #border_rotation_export.save
flash[:success] = "Export successfully created"
format.html { render :new }
else
flash[:error] = "Export was not created."
end
end
else
#border_rotation_import = BorderRotationImport.new(border_rotation_import_params)
respond_to do |format|
if #border_rotation_import.save
flash[:success] = "Export successfully created"
format.html { render :new }
else
flash[:error] = "Export was not created."
end
end
end
end
def new
#border_rotation_export = BorderRotationExport.new
#border_rotation_import = BorderRotationImport.new
end
private
def border_rotation_export_params
params.require(:border_rotation_export).permit(:exporter_name,:vehicle_color,:rot_num,:current_date,:current_time,:goods_description,:license_num,:entry)
end
def border_rotation_import_params
params.require(:border_rotation_import).permit(:importer_name,:vehicle_color,:rot_num,:current_date,:current_time,:goods_description,:license_num,:entry)
end
My new View form:
It has 2 forms and is enclosed in bootstrap tabs
<%= form_for #border_rotation_export, url: rotation_create_path, method: :post do |f|%>
<lable>Importer Name: </lable><%= f.text_field :importer_name, class: "form-control", placeholder: "Importer Name"%>
<lable>Vehicle Color: </lable><%= f.text_field :vehicle_color, class: "form-control", placeholder: "Vehicle Color"%>
**its fields**
<% end %>
and
<%= form_for #border_rotation_import, url: rotation_create_path, method: :post do |f|%>
<lable>Exporter Name: </lable><%= f.text_field :exporter_name, class: "form-control", placeholder: "Exporter Name"%>
<lable>Vehicle Color: </lable><%= f.text_field :vehicle_color, class: "form-control", placeholder: "Vehicle Color"%>
**its fields**
<% end %>
The error in my new.html.rb
First argument in form cannot contain nil or be empty
Displays this in red highlighted
<%= form_for #border_rotation_export, url: rotation_create_path, method: :post do |f|%>
My guess is that it submits both forms but only has the parameters for one form with the input data. Once I submit, it saves to the database but it gives me the error
**Routes **
get 'rotation/create', to: 'border_rotation#create'
post 'rotation/create', to: 'border_rotation#create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"Cu52CIDgrY0b7Yk6edkd7+RTl5yR4qSEqPPrqWtM0nIQVDvw7eYDF36zduJPLjI+vVNqCfgtLcMDUEkW6qDOdQ==",
"border_rotation_import"=>
{"importer_name"=>"john",
"vehicle_color"=>"red",
"rot_num"=>"11sssfeeea",
"current_date"=>"2021-09-22",
"current_time"=>"09:37",
"goods_description"=>"yogurt",
"license_num"=>"c-11223",
"entry"=>"c1223"},
"import_submit"=>"Submit"}
Thank you in advance
You can setup the controller with a lot less redundancy:
# config/routes.rb
resources :rotations, only: [:new, :create]
class BorderRotationsController < ApplicationController
# GET /rotations/new
def new
populate_forms
end
# POST /rotations
def create
resource = model_class.new(create_params)
set_ivar(resource) # sets #border_rotation_export or #border_rotation_import
if resource.save
flash[:success] = "#{humanized} successfully created"
redirect_to action: :new
else
populate_forms
flash[:error] = "#{humanized} could not be created - please try again."
render :new
end
end
private
# gets the model class via params[:subtype]
def model_class
#model_class ||= begin do
if params[:border_rotation_export].present?
BorderRotationExport
else
BorderRotationImport
end
end
end
def humanized
model_class == BorderRotationExport ? 'Export' : 'Import'
end
def set_ivar(value)
instance_variable_set(
"##{param_key}",
value
) ​
​end
# just sets up the instance variables for the form
def populate_forms
#border_rotation_export ||= BorderRotationExport.new
#border_rotation_import ||= BorderRotationImport.new
end
# border_rotation_export or border_rotation_import
def param_key
model_class.model_name.param_key
end
def create_params
require(param_key).permit(
:exporter_name, :vehicle_color, :rot_num,
:current_date,:current_time, :goods_description,
:license_num, :entry
)
end
And then use partials so that you can resuse the same form:
# app/views/border_rotations/new.html.erb
<%= render partial: 'form',
locals: { border_rotation: #border_rotation_export } %>
<%= render partial: 'form',
locals: { border_rotation: #border_rotation_import } %>
# app/views/border_rotations/new.html.erb
<%= form_with model: border_rotation, url: rotations_path do |f| %>
<div class="field">
<%= f.label :importer_name %>
<%= f.text_field :importer_name, class: "form-control" %>
</div>
<div class="field">
<%= f.label :importer_name %>
<%= f.text_field :importer_name, class: "form-control" %>
</div>
# ...
<% end %>
If the requirements diverge use two separate routes/controllers and inheritance instead of blooming out in tons of new code paths.

Rails - When assigning attributes, you must pass a hash as an argument 2

In my Rails 5 app, I have this error:
when I use this table to list the tags of a related object (in this case an Annotation)
<tbody>
<% object.tags.each do |tag| %>
<% unless tag.content.blank? %>
<tr>
<td style="word-wrap: break-word;" class="displaytagedit"><%= link_to tag.content, **[object, tag]**, method: :patch %></td>
It tries to open this link
http://localhost:3000/annotations/6/tags/24 (which appears correct)
and throws this error:
When assigning attributes, you must pass a hash as an argument.
On this part of my controller (below)
tagable = detect_tagable
#tag = tagable.tags.update(params[:id])
#tags = Tag.all
render '_tag_update'
end
It should call this form:
<%= simple_form_for #tag, html: { class: 'form-vertical', multipart: true },
wrapper: :horizontal_form,
wrapper_mappings: {
check_boxes: :horizontal_radio_and_checkboxes,
radio_buttons: :horizontal_radio_and_checkboxes,
file: :horizontal_file_input,
boolean: :horizontal_boolean
} do |f| %>
<%= f.error_notification %>
<%= f.input :content, placeholder: 'Tagged content', label: false %>
<%= f.association :tagtype, prompt: 'Select tag type', label: false, :collection => Tagtype.active.order(:name).where(:documenttype => object.documenttype_id) %>
<%= f.input :location, :as => :hidden, :input_html => { :value => 'x=0, y=0' }, label: false %>
<%= f.button :submit %>
<% end -%>
Tags are a reusable model on (for now) 2 objects.
This is the routes.rb
Rails.application.routes.draw do
root 'dashboard#index'
devise_for :users
resources :users, :documenttypes, :tagtypes, :business_partners
resources :documents do
resources :comments, :tags
get "pdf", on: :member
end
resources :annotations do
resources :comments, :tags
get "pdf", on: :member
end
Update
this is the tag controller:
class TagsController < ApplicationController
def create
tagable = detect_tagable
tagable.tags.create(tag_params)
redirect_to tagable_path(tagable)
end
def update
tagable = detect_tagable
#tag = tagable.tags.find(params[:id])
#tags = Tag.all
render '_tag_update'
end
def destroy
tagable = detect_tagable
#tag = tagable.tags.find(params[:id])
#tag.destroy
redirect_to tagable_path(tagable)
end
private
def tagable_path(tagable)
case tagable
when Document
document_path(tagable)
when Annotation
annotate_path(tagable)
else
fail 'Unknown tagable'
end
end
def detect_tagable
if params[:annotation_id]
Annotation.find(params[:annotation_id])
elsif params[:document_id]
Document.find(params[:document_id])
else
fail 'Tagable not found'
end
end
def tag_params
params.require(:tag).permit(:content, :location, :tagtype_id, annotation_attributes: { annotation_ids:[] }, document_attributes: { document_ids:[] })
end
end
Where is my error/mistake?
Can you show us your controller? probably it's a typo in object which really would be #object as this comment says
Anyway, send your controller code to confirm this
EDIT:
In your TagsController file you must set the update method like this:
def update
tagable = detect_tagable
#tag = tagable.tags.find(params[:id])
#tags = Tag.all #Or whatever query you want if you want to select more specific Tags
render '_tag_update'
end

Why my form don't work?

Here is my tournaments_controller file:
class TournamentsController < ApplicationController
before_action :authenticate_user!, only: [:new, :create, :destroy]
def index
end
def show
end
def new
render action: 'new'
end
def create
self.tournament = Tournament.new(tournament_params)
if tournament.save
flash[:info] = "Tournament created successfully!"
redirect_to root_url
else
render action: 'new'
end
end
def destroy
Tournament.find(params[:id]).destroy
flash[:success] = "Tournament deleted!"
redirect_to root_url
end
private
def tournament_params
params.require(:tournament).permit(:name, :maxplayers)
end
end
This is my form file:
= form_for tournament do |f|
- if tournament.errors.any?
#error_explanation
%h2= "#{pluralize(tournament.errors.count, "error")} prohibited this tournament from being saved:"
%ul
- tournament.errors.full_messages.each do |msg|
%li= msg
.form-group
= f.label :name
= f.text_field :name, class: 'form-control'
= f.submit 'Save', class: 'btn btn-primary'
When my app runs, console display this error:
undefined local variable or method `tournament' for #<#<Class:0x007f0e414fa2d0>:0x007f0e418d9a90>
I'm using simple-form and Haml if it's important.
Can anyone explain to me why I am getting this error?
You have to use an instance variable:
def new
#tournament = Tournament.new
render action: 'new'
end
def create
#tournament = Tournament.new(tournament_params)
if #tournament.save
flash[:info] = "Tournament created successfully!"
redirect_to root_url
else
render action: 'new'
end
end
and
= form_for #tournament do |f|
- if #tournament.errors.any?
#error_explanation
%h2= "#{pluralize(#tournament.errors.count, "error")} prohibited this tournament from being saved:"
%ul
- #tournament.errors.full_messages.each do |msg|
%li= msg
.form-group
= f.label :name
= f.text_field :name, class: 'form-control'
= f.submit 'Save', class: 'btn btn-primary'
= link_to 'Back', categories_path, class: 'btn btn-default'

How to validate a child object attributes when self-reference association?

I have a one model 'Task' and have two entities - 'tasks' and 'subtasks' with self-reference association.
class Task < ActiveRecord::Base
has_many :subtasks, class_name: 'Task', foreign_key: 'parent_id', dependent: :destroy
belongs_to :parent, class_name: 'Task'
accepts_nested_attributes_for :subtasks, allow_destroy: true
validates :title, presence: true, length: { minimum: 3 }
validates :priority, presence: true, numericality: { only_integer: true }, length: { is: 1 }
validates_associated :subtasks
end
And i use one controller - TasksController.
class TasksController < ApplicationController
before_action :find_task, only: [:show, :edit, :update, :destroy, :run, :complete]
rescue_from ActiveRecord::RecordNotFound, with: :invalid_task
def run
#task.run!
redirect_to :back
end
def complete
#task.complete!
redirect_to :back
end
def index
#tasks = Task.all
end
def show
end
def new
#task = Task.new
end
def edit
end
def create
#task = Task.create(task_params)
if #task.errors.empty?
redirect_to tasks_path, notice: "Task created!"
else
render 'new', notice: "Invalid input!"
end
end
def update
#task.update_attributes(task_params)
if #task.errors.empty? || :subtasks_attributes?
redirect_to #task
else
render 'edit'
end
end
def destroy
#task.destroy
if #task.parent_id?
redirect_to #task.parent
else
redirect_to tasks_path
end
end
private
def task_params
params.require(:task).permit(:title, :description, :scheduled, :deadline, :priority, :project, subtasks_attributes: [:title, :priority])
end
def find_task
#task = Task.find(params[:id])
end
def invalid_task
redirect_to tasks_path, notice: "Invalid task!"
end
end
I wanna create subtasks on task show page:
- #task.subtasks.each do |subtask|
- if subtask.in_work?
=> link_to 'Complete', complete_task_path(subtask), method: :put
- else
=> link_to 'Run', run_task_path(subtask), method: :put
=> subtask.title
=> link_to 'Edit', edit_task_path(subtask)
= link_to 'Delete', [subtask], method: :delete, data: { confirm: 'Are you sure?' }
= simple_form_for #task do |t|
= t.simple_fields_for :subtasks, #task.subtasks.build do |f|
.form-inputs
= f.input :title
= f.hidden_field :priority, value: #task.priority
.form-actions
= f.button :submit, "Add a subtask"
Now on the task show page i can create a subtask with valid attributes and can't create a subtask with invalid attributes, but i do not get validation message.
How can i fix it?
Ty and sorry for my English.
PS:
i don't know why, but errors exist inside controller and doesn't exist inside view
#project.update_attributes(project_params)
puts #project.errors.full_messages
if #project.errors.empty? || :tasks_attributes?
redirect_to #project
puts #project.errors.full_messages
(0.0ms) begin transaction
(0.0ms) rollback transaction
Tasks title can't be blank
Tasks title is too short (minimum is 3 characters)
Redirected to http://localhost:3000/projects/3
Tasks title can't be blank
Tasks title is too short (minimum is 3 characters)
Completed 302 Found in 6ms (ActiveRecord: 0.2ms)
You should add the errors messages to the view too:
= simple_form_for #task do |t|
= t.simple_fields_for :subtasks, #task.subtasks.build do |f|
#error message added here
- if #task.subtasks.errors.any?
%ul.errors
- #task.subtasks.errors.full_messages.each do |msg|
%li= msg
.form-inputs
= f.input :title
= f.hidden_field :priority, value: #task.priority
.form-actions
= f.button :submit, "Add a subtask"
EDIT
You have a _form partial in you application, change that code to this
= simple_form_for #task do |f|
- if #task.errors.any?
ul.errors
- #task.errors.full_messages.each do |msg|
=> msg
= f.input :title
= f.input :description
= f.input :scheduled
= f.input :deadline
= f.input :priority, collection: [["None", 0], ["High", 3], ["Medium", 2], ["Low", 1]], selected: ["None"]
= f.button :submit

Rails 4 - Nested Routes and Form Parameters

When I'm trying to create a new "participation" in my Rails4 application and it seems like there is something wrong with my parameters. Actually this is not causing any problems in application (or I didn't notice it) but still I would like to fix it. You can see 2 "examination_id" parameters one of them is null and the other one is equal to 1.
REQUEST PARAMETERS:
{"utf8"=>"✓",
"authenticity_token"=>"XZ71eV0zxrnTBilzvEtLlHLwoAb+qKdDfxOHjrAHUPg=",
"participation"=>
{
"language_preference"=>"Türkçe",
"exam_center_preference"=>"1",
"disability"=>"1",
"user_id"=>"1",
"examination_id"=>""
},
"commit"=>"Sınava Başvur",
"examination_id"=>"1"
}
routes.rb:
resources :examinations do
resources :participations do
member do
get :update_profile_information
end
end
end
participation.rb:
class Participation < ActiveRecord::Base
belongs_to :user
belongs_to :examination
before_save :verification_key_generator
end
participations_controller.rb:
class ParticipationsController < ApplicationController
before_filter :authenticate_user!
before_action :set_participation, only: [:show, :edit, :update, :destroy]
before_filter :get_examination
def get_examination
#examination = Examination.find(params[:examination_id])
end
def index
#participations = #examination.participations
end
def show
#participation = #examination.participations.find(params[:id])
end
def new
#participation = Participation.new
end
def create
#participation = #examination.participations.new(participation_params)
#participation.user = current_user
respond_to do |format|
if #participation.save
format.html { redirect_to [#examination, #participation], notice: 'Başvuru işlemi başarıyla tamamlandı!' }
format.json { render action: 'show', status: :created, location: [#examination, #participation] }
else
render 'new'
format.html { render action: 'new' }
format.json { render json: #participation.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #participation.update(participation_params)
format.html { redirect_to [#examination, #participation], notice: 'Başvurunuz Başarıyla Güncellendi!' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: participation.errors, status: :unprocessable_entity }
end
end
end
private
def set_participation
#participation = Participation.find(params[:id])
end
def participation_params
params.require(:participation).permit(:user_id, :examination_id, :payment_status, :language_preference, :exam_center_preference, :disability)
end
end
app/views/participations/_form.html.erb:
<%= simple_form_for([#examination, #participation], html:{class: "well"}) do |f| %>
<%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %>
<%= f.input :examination_id, as: :hidden %>
<%= f.input :language_preference, collection: ["Türkçe", "İngilizce", "Rusça"], label: 'Sınav Dili Tercihi' %>
<%= f.input :exam_center_preference, collection:ExamCenter.all, label: 'Sınav Merkezi Seçiniz', label_method: :city %>
<%= f.input :disability, inline_label: 'Yardımcı İstiyorum', label: false %>
<%= f.button :submit, "Sınava Başvur" %>
<% end %>
app/views/participations/new.html.erb:
<%= simple_form_for([#examination, #participation]) do |f| %>
<%= f.error_notification %>
<%= f.input :language_preference, collection: ["Türkçe", "İngilizce", "Rusça"], label: 'Sınav Dili Tercihi' %>
<%= f.input :exam_center_preference, collection:ExamCenter.all, label: 'Sınav Merkezi Seçiniz', label_method: :city %>
<%= f.input :disability, inline_label: 'Yardımcı İstiyorum', label: false %>
<%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %>
<%= f.input :examination_id, as: :hidden %>
<%= f.button :submit, "Sınava Başvur" %>
<% end %>
sa
When you're using
<%= simple_form_for([#examination, #participation], html:{class: "well"}) do |f| %>
to generate the form, it will set the action to be /examinations/[examination_id]/participations so the routes/action will know the examination_id from the url itself.
So, you don't need to pass examination_id separately as hidden field that you're setting as
<%= f.input :examination_id, as: :hidden %>
Once you remove this hidden field the request parameters will look like:
{"utf8"=>"✓",
"authenticity_token"=>"XZ71eV0zxrnTBilzvEtLlHLwoAb+qKdDfxOHjrAHUPg=",
"participation"=>
{
"language_preference"=>"Türkçe",
"exam_center_preference"=>"1",
"disability"=>"1",
"user_id"=>"1"
},
"commit"=>"Sınava Başvur",
"examination_id"=>"1"
}

Resources