NoMethodError for new controller in Rails - ruby-on-rails

Cities#new controller shows error involving cities_path, but I don't have it in any file nor in CitiesController. I checked all files, tried to restart the server but still nothing.
undefined method `cities_path' for #<#<Class:0x007f9e4c1cb348>:0x00000003836140>
Did you mean? city_path
CitiesController
class CitiesController < ApplicationController
def index
#cities = City.all
end
def show
find_city
end
def new
#city = City.new
end
def edit
find_city
end
def update
find_city
if #city.save
redirect_to city_path(#city)
else
render "edit"
end
end
def create
#city = City.new(city_params)
if #city.save
redirect_to index_path
else
render "new"
end
end
private
def find_city
#city = City.find(params[:id])
end
def city_params
params.require(:city).permit(:name, :icon_url)
end
end
Routes
get "/cities/new" => "cities#new", as: "new_city"
post "/index" => "cities#create"
get "/cities/:id" => "cities#show", as: "city"
get "/cities/:id/edit" => "cities#edit", as: "edit_city"
patch "/city/:id" => "cities#update"
Form (error is raised on first line)
<%= form_for #city do |f| %>
<% if #city.errors.any? %>
<div class="errors">
<ul>
<% city.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label "Name:" %>
<%= f.text_field :name, class: "form-control" %>
<%= f.label "Icon:" %>
<%= f.text_field :icon_url, class: "form-control" %>
<%= f.submit "Pošalji" %>
<% end %>

When you use form_for #city, and #city is a new record, form_for will try to find a cities_path to POST the new attributes back to.
You should be using resources :cities in your routes file to automatically define the routes and their names. If you want to define a limited set of routes, you can use :only or :except:
resources :cities, only: %i(new create show edit update)
If you don't use resources, you either need to explicitly specify a path for your form_for call, or you need to provide a route named cities_path manually:
post "/index" => "cities#create", as: :cities
Note that index routes don't typically actually contain the word index, you should really just be posting to /cities, not /index.
post "/cities" => "cities#create", as: :cities

Related

Transmit params with form_tag

In my views I have a form and trying to update quantity for an order line:
<div class="quantity">Quantity</br>
<%= form_tag(order_line_path(line.id), method: "patch") do %>
<%= number_field_tag 'qty', '1', within: 1...line.book.stock %>
<%= submit_tag "Update", class: "btn btn-primary" %>
<% end %>
</div>
The instance variable in the rest of my view is a collection of order lines, so I cannot use it.
Then I have in my controller the update method:
def update
#order = current_order
#order_line = #order.order_lines.find(params[:id])
#order_line.update_attributes(order_line_params)
end
And my strong params definition:
def order_line_params
params.require(:order_line).permit(:qty)
end
I get this error :
param is missing or the value is empty: order_line
Could someone please have a look?
Thanks!
The reason you are getting param is missing or the value is empty: order_line is that you are using form_tag which gives a "flat" params hash.
However this is easily avoidable if you just use form_with/form_for.
# routes.rb
resources :orders do
resources :line_items, shallow: true
end
# app/views/order_items/edit.html.erb
# use `form_with(model: #order_item)` in Rails 5
<%= form_for(#order_item) do |f| %>
<%= f.label :qty, within: 1...f.object.book.stock %>
<%= f.number_field :qty, %>
<%= f.submit %>
<% end %>
class OrderItemsController < ApplicationController
before_action :set_order_item, only: [:show, :edit, :update, :destroy]
# ...
# GET /order_items/:id/edit
def edit
end
# PATCH /order_items/:id
def update
if #order_item.update(order_item_params)
redirect_to #order_item, notice: 'Line updated'
else
render :edit
end
end
private
def set_order_item
#order_item = OrderItem.find(params[:id])
end
def order_item_params
params.require(:order_item).permit(:qty)
end
end
But what you're really looking for unless you are doing the update/creation of nested items with AJAX is most likely a combination of accepts_nested_attributes and fields_for which will let the user mass edit the line items:
class Order < ApplicationRecord
accepts_nested_attributes_for :order_items
end
<%= form_for(#order) do |f| %>
<%= fields_for(:order_items) do |oif| %>
<%= f.label :qty, within: 1...f.object.book.stock %>
<%= f.number_field :qty, %>
<% end %>
<%= f.submit %>
<% end %>
class OrdersController < ApplicationController
# PATCH /orders/:id
def update
if #order.update(order_params)
redirect_to #order, notice: 'Order updated.'
else
render :new
end
end
private
def order_params
params.require(:order).permit(order_items_attributes: [:qty])
end
end

How to get all jobs for current user and view every job

Missing keys required [:id] for child association show path
I have a job model that belongs to a user. In the user show page, I call all child jobs that belong to the user. Here is my code:
<% current_user.jobs.each do |j| %>
<%= j.id %>
<%= j.job_category %>
<%= link_to 'show', job_path(j.id) %> <br> <br>
<% end %>
But it raises an error anytime I click on show jobs page:
No route matches {:action=>"show", :controller=>"jobs", :id=>nil, :user_id=>"1"} missing required keys: [:id]
Please, how do I rectify this error? the routes show jobs resources stands on its own with path: job_path. it works when I manually plug in the URL.
Here are my routes.rb:
resources :users do
resources :jobs
resources :applications
end
resources :jobs do
collection do
match 'search' => 'jobs#search', via: [:get, :post], as: :search
end
end
and my controller code is:
class JobsController < ApplicationController
def index
#q = Job.ransack(params[:q])
#jobs = #q.result(distinct: true)
end
def frontpage
#q = Job.ransack(params[:q])
if params[:q].present?
redirect_to jobs_path(#q)
end
#jobs = Job.all
end
def search
index
render :index
end
def show
#job = Job.find(params[:id])
end
def edit
end
def update
#joblists.update(joblists_params)
redirect_to joblists_path
end
def create
#user = User.find(params[:user_id])
#user_job = #user.jobs.create(joblists_params)
flash[:notice] = "Job has been successfully Created"
redirect_to user_path(#user)
end
def joblists_params
params.require(:job).permit(:job_category, :job_title, :company_name, :location, :job_description,
:monthly_salary, :deadline, :contact, :longitude, :lattitude, :full_time )
end
end
Look after running rails routes it showing like this
user_job GET /users/:user_id/jobs/:id(.:format) jobs#show
so the link path is
user_job_path
on this link, you need to pass the user_id and job id then it will like this
<%= link_to 'show', user_job_path(#user, j.id) %> # or #user.id
Solved after chat
<% current_user.jobs.each do |j| %>
<%= j.id %>
<%= j.job_category %>
<%= link_to 'show', user_job_path(current_user.id, j.id) %> <br><br>
<% end %>
Add user id
user_job_path(current_user.id, j.id)
Thanks for comment

form_for a "belongs_to" model in 'show' of parent model

I have one model "Breads" that has_many "Posts".
I would like to have a form to create a new "Post" on the 'show' page for a given "Bread" that creates the association to the record of 'Bread' which the 'show' page is displaying.
I have tried a few different methods, but all are giving an error. The method that I have shown below gives a "Association cannot be used in forms not associated with an object" error.
/views/breads/show.html.erb:
<p>
<strong>Bread Type:</strong>
<%= #bread.bread_type %>
</p>
<table>
<tr>
<th>Uploaded By</th>
<th>Comment</th>
<th>Picture</th>
</tr>
<% #bread.posts.each do |post| %>
<tr>
<td><%= post.uploader %></td>
<td><%= post.comment %></td>
<td><%= image_tag post.attachment_url.to_s %></td>
</tr>
<% end %>
</table>
<%= #bread.id %>
<%= simple_form_for #bread do |b| %>
<%= simple_fields_for :posts do |p| %>
<%= p.input :uploader %>
<%= p.input :comment %>
<%= p.association :bread, value: #bread.id %>
<%= p.file_field :attachment %><br>
<%= p.button :submit %>
<% end %>
<% end %>
<%= link_to 'Back', breads_path %>
config/routes.rb
Rails.application.routes.draw do
get 'welcome/index'
root 'welcome#index'
resources :breads
resources :posts
end
controllers/breads_controller.rb:
class BreadsController < ApplicationController
def index
#breads = Bread.all
end
def show
#bread = Bread.find(params[:id])
end
def new
#bread = Bread.new
end
def edit
#bread = Bread.find(params[:id])
end
def create
#bread = Bread.new(bread_params)
if #bread.save
redirect_to #bread
else
render 'new'
end
end
def update
#bread = Bread.find(params[:id])
if #bread.update(bread_params)
redirect_to #bread
else
render 'edit'
end
end
def destroy
#bread = Bread.find(params[:id])
#bread.destroy
redirect_to breads_path
end
private
def bread_params
params.require(:bread).permit(:bread_type)
end
end
models/bread.rb:
class Bread < ActiveRecord::Base
has_many :posts
validates :bread_type, presence: true, uniqueness: true
end
models/post.rb:
class Post < ActiveRecord::Base
belongs_to :bread
mount_uploader :attachment, AttachmentUploader
end
Do this -
<%= simple_form_for #bread do |b| %>
<%= b.simple_fields_for(:posts,#bread.posts.build) do |p| %>
<%= p.input :uploader %>
<%= p.input :comment %>
<%= p.file_field :attachment %><br>
<%= p.button :submit %>
<% end %>
<% end %>
and make changes in beard_params
def beard_params
params.require(:bread).permit!
end
Here permit! requires all parameters and for other way you can use #pawan's answer.
Extending #Amit Suroliya answer, you need to add posts_attributes to bread_params
def bread_params
params.require(:bread).permit(:id, :bread_type, posts_attributes: [:id, :uploader, :comment, :bread_id, :attachment])
end
Update:
You also need to add accepts_nested_attributes_for :posts in Bread model.
Iam sorry, but this is not good way at all, try to don't abuse rails and rest routes :)
Here is easy example how to do that:
config/routes.rb
resources :bread do
resources :posts
end
This means there will be routes like:
bin/rake routes
breads - breads#index
bread/:id - breads#show
etc..
and most important
bread/:bread_id/posts/:id
...
That means posts are nested resources for bread...
app/controllers/breads_controller.rb
controller BreadsController < BaseController
before_action :find_bread, except: %i(index create new)
.... action new, update, edit etc..
end
but now its the important part in PostsController..
app/controllers/posts_controller.rb
controller PostsController < BaseController
before_action :find_bread
before_action :find_post, except: %i(index new create)
before_action :build_post, only: %i(new create)
.... action new, update, edit etc..
# Example with :return link
def create
if #post.save
if params[:back] == 'bread_show'
redirect_to bread_path(#bread)
else
redirect_to bread_post_path(#bread, #post)
end
else
render 'new'
end
end
private
def build_post
if params[:post]
#post = #bread.posts.build(post_params)
else
#post = #bread.posts.build
end
end
def find_post
#post = #bread.posts.find(params[:id])
end
def find_bread
#bread = Bread.find(params[:bread_id])
end
... post params ...
end
Now you have rest full routes and you're able to do what you want without such a pain and clean
... output hidden
<%= #bread.id %>
<%= simple_form_for #bread.posts.build do |b| %>
<%= p.input :uploader %>
<%= p.input :comment %>
<%= p.file_field :attachment %><br>
<%# Send back link to return on proper page %>
<%= p.hidden_field :back, 'bread_show' %>
<%= p.button :submit %>
<% end %>
<%= link_to 'Back', breads_path %>
There can be some mistakes, I write this code from memory, can't try that :(

Nested resource parameters not being set properly in form_for

I'm getting a curious error after submitting my form. Been trying to solve this for several hours..
No route matches {:action=>"show", :controller=>"items", :item_id=>"141", :matter_id=>"3"} missing required keys: [:id]
The parameters are:
{"utf8"=>"✓",
"authenticity_token"=>"w0D7XmX2X2/ZMU19T6RlMvWCEClXnCFFOR+4EdIFvWg=",
"comment_item"=>{"item_id"=>"",
"name"=>"kaljdf",
"body"=>"yet another comment test"},
"commit"=>"Post Comment",
"matter_id"=>"3",
"item_id"=>"141"}
I have the following models:
class Matter < ActiveRecord::Base
has many :discoveries
delegate :items, to: :discoveries
end
class Discovery < ActiveRecord::Base
belongs_to :matter
scope :items, -> { where(type: 'Item') }
end
class Item < Discovery
has_many :comment_items
end
class CommentItem < ActiveRecord::Base
belongs_to :item
end
Controllers:
class ItemsController < DiscoveriesController
def show
#item = Item.find(params[:id])
#comment_item = CommentItem.new
end
def edit
#item = Item.find(params[:id])
end
def new
#item = Item.new
end
end
class CommentItemsController < ApplicationController
before_action :set_comment_item, only: [:show, :edit, :update, :destroy]
def new
#item = Item.find(params[:item_id])
#comment_item = #item.comment_item.new
end
def create
#item = Item.find(params[:item_id])
#comment_item = #item.comment_items.new(comment_item_params)
if #comment_item.save
flash[:notice] = 'Comment was successfully created'
redirect_to matter_item_url(matter_id: params[:matter_id])
else
flash[:notice] = "Error creating comment: #{#comment.errors}"
redirect_to matter_item_url(#matter, #item)
end
end
def destroy
#comment_item = CommentItem.find(params[:id])
#comment_item.destroy
redirect_to(#comment_item.item)
end
private
def set_comment_item
#comment_item = CommentItem.find(params[:id])
end
def comment_item_params
params.require(:comment_item).permit(:name, :body, :item_id, :matter_id)
end
end
The show action for the item resource:
<p>
<strong>Matter:</strong>
<%= #item.matter_id %>
</p>
<p>
<strong>Content:</strong>
<%= #item.content %>
</p>
<hr />
<%= form_for #comment_item, url: matter_item_comment_items_path(matter_id: #item.matter, item_id: #item.id) do |f| %>
<% if #comment_item.errors.any? %>
<ul>
<% #comment_item.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<%= f.hidden_field :item_id %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.submit "Post Comment" %>
</p>
<% end %>
<%= render :partial => 'comment_item', :collection => #item.comment_items %>
<%= link_to 'Edit', edit_matter_item_path(id: #item.id) %> |
<%= link_to 'Back', matter_items_path %>
Routes
resources :items do
resources :comment_items
end
resources :matters do
resources :items do
resources :comment_items
end
end
When looking at CommentItems in the console, I see that the comments are in fact being added to the model with their correct ID's, but they don't seem to be passed as parameters.. What am I missing?
I've reviewed Rails 4 form_for double nested comments and Rails 3.2 - Nested Resource Passing ID but I didn't have much luck..
I'd really appreciate your help!
No route matches {:action=>"show", :controller=>"items", :item_id=>"141", :matter_id=>"3"} missing required keys: [:id]
your request is going to ItemsController instead of CommentItemsController
see :controller => "items"

Error: param is missing or the value is empty: thing

I'm using rails 4.0.8. I added a comment section to a model called 'Things', but I keep getting the same error "param is missing or the value is empty: thing" when I press the submit comment button. It says the error is in the Things#Controller. What am I doing wrong?
UPDATE: I removed the url path from the form, but a new error returns "Couldn't find Thing without an ID". The error is in Comments#Controller.
VIEW FOR THING/SHOW
<div id= "thing">
<h1>
<%= #thing.name %>
</h1>
<br>
<div id= "commentsection">
Comments
<div id= "comments">
<br>
<% #thing.comments.each do |c| %>
<%= c.username %>
<br>
<%= c.text %>
<% end %>
<%= form_for #comment, :url => thing_path do |f| %>
<%= f.label :username %>
<%= f.text_field :username %>
<%= f.label :comment %>
<%= f.text_field :text %>
<%= f.submit "Enter", class: "btn btn-small btn-primary" %>
<% end %>
</div>
</div>
</div>
THINGS CONTROLLER
class ThingsController < ApplicationController
def show
#thing = Thing.find(params[:id])
#thing.comments.build
#comment = Comment.new
end
def index
end
def new
#thing = Thing.new
#things = Thing.all
end
def create
#thing = Thing.new(thing_params)
if #thing.save
redirect_to #thing
else
render 'new'
end
end
private
def thing_params
params.require(:thing).permit(:name, :avatar)
end
end
COMMENTS CONTROLLER (I put asterisks around the line where the error is)
class CommentsController < ApplicationController
def show
#comment = Comment.find(params[:id])
end
def new
#comment = Comment.new
#comments = Comment.all
end
def create
****#thing = Thing.find(params[:thing_id])****
#comment = #thing.comments.create(comment_params)
redirect_to thing_path(#thing)
end
end
private
def comment_params
params.require(:comment).permit(:user, :text, :upvotes, :downvotes, :thing_id)
end
end
ROUTES
Website::Application.routes.draw do
get "comments/new"
get "comments/show"
get "things/new"
root 'home_page#home'
get "all/things/new" => 'things#new'
get "all/allthings"
resources :things
resources :good_comments
get "things/show"
get "things/results"
end
You are posting the #comment form to post '/things' path.
<%= form_for #comment, :url => thing_path do |f| %>
It should just be <%= form_for #comment do %> (Rails is smart enough to plug in the comments_path) or if you feel like being more explicit (even though it's not necessary)
<%= form_for #comment, url: :comments_path do %>
Another note though, if you want that Comment to be tied to that specific Thing then in your models it should be
Class Thing
has_many :comments
end
Class Comment
belongs_to :thing
end
Then make sure in your database comment has a thing_id foreign_key field and then your form for comment should actually look like
<%= form_for #thing, #comment do %>
<% end %>

Resources