NoMethodError in Rails - ruby-on-rails

I am getting
NoMethodError in ProjectsController#edit
undefined method `projects' for
#<User:0x28356d8>`app/controllers/projects_controller.rb:154:in `correct_user'
The params are: {"user_id"=>"1", "id"=>"1"}
The offending line in the projects_controller is:#project = current_user.projects.find_by_id(params[:id]) as part of
def correct_user
#project = current_user.projects.find_by_id(params[:id])
redirect_to show_user_path if #project.nil?
end
My projects_controller#edit method is:
def edit
#project = Project.find(params[:id])
#project.current_step = #project.first_step
#user = current_user
end
This is being triggered by a button,
<%= link_to image_tag('img_blank.png'), edit_user_project_path(current_user), :class => "btn_edit_project" %>
with the HTML output as:
<a class="btn_edit_project" href="/users/1/projects/1/edit"><img src="/assets/img_blank.png" alt="Img_blank"></a>
My routes file contains the following:
resources :users do
resources :projects
end
and rake routes shows:
edit_user_project GET /users/:user_id/projects/:id/edit(.:format) projects#edit
This problem keeps surfacing in different forms, but never quit gets resolved. Any ideas?

Thanks to #jvnill for the answer...
The association between the user and the project is a 1 to 1. The user has_one :project and the project belongs_to :user. As #jvnill pointed out, there is no need to qualify the lookup with .find_by_id(params[:id]) because the user_id will only be in the projects table once and Rails can find it.

Related

Following Rails tutorial, undefined method 'create' for nil:NilClass, with nested resource

I'm following the Rails tutorial and making changes where appropriate, with the intention that my tutorial project will become a full-fledged production app after the completion of the tutorial.
I've run into a snag with the second model portion of the tutorial. Here is how I've written my second model.
In my policy.rb:
class Policy < ApplicationRecord
has_one :insured
end
In my insured.rb:
class Insured < ApplicationRecord
belongs_to :policy
end
In my routes.rb:
resources :policies do
resource :insured
end
In my insureds_controller.rb:
def create
#policy = Policy.find(params[:policy_id])
# next line is raising the error
#insured = #policy.insured.create(insured_params)
redirect_to #insured
end
private
def insured_params
params.permit(:name, :address, :phone, :email)
end
I've inspected the #policy object with render plain: #policy.inspect and can confirm that ActiveRecord is retrieving the policy correctly. When I inspect the attributes of #policy, using render plain: #policy.attribute_names.inspect, I don't see an insured attribute, which I thought Rails was supposed to automatically manage for me. In the tutorial, an article has_many :comments, and a comment is supposedly easily created and associated with the parent article with this call: #article.comments.create(comment_params). I also noticed that the tutorial uses params.require(:comment).permit(...) while I have to use params.permit(...), after inspecting the params hash I saw that the :insured attributes existed in the top-level of the hash, instead of being tied to an :insured key within the hash.
I tried manually saving and assigning the #insured object like so:
def create
#policy = Policy.find(params[:policy_id])
#insured = Insured.new(insured_params)
if #insured.save
#policy.insured = #insured
redirect_to #insured
end
end
Only to run into the following error in my .../insureds/new.html.erb:
<h1>New Insured</h1>
<h1><%= #policy.policy_number %></h2>
<%= render 'form' %>
<%= link_to 'Cancel', policy_path(#policy) %>
Which derives from my partial form .../insureds/_form.html.erb:
# the following line raises the error
<%= form_with model: #insured, local: true do |form| %>
# html omitted for brevity
<% end %>
Error: 'undefined method insureds_path'. This is weird because when I inspect the HTML I can see the form action for this view is /policies/[:id]/insured.
Sorry for the massive wall of text, I wanted to show you guys that I did try to figure out what is going wrong.
There is an error in your config/routes.rb file:
resources :policies do
# change it for:
collection do
get 'insured', to: 'policies#show_insured', as: 'show_policy_insured'
# maybe unnecessary to be here
# get 'insured/new', to: 'insureds#new', as: 'new_policy_insured'
# post 'insured/create', to: 'insureds#create', as: 'create_policy_insured'
# delete 'insured/delete', to: 'insureds#delete', as: 'delete_policy_insured'
end
end
# add resources here
resources :insureds
In policy_controller.rb:
def show_insured # 'policy/:id/insureds/
end
In insureds_controller.rb:
def show # '/insureds/:id'
end
def create
...
redirect_to show_policy_insured && return if #insured_policy
end
# before_filter or before_action
#policy = Policy.find(params[:id])
#insured_policy = #policy.insured
Check it and run this to see your routes:
$ bundle exec rake routes
get /policies/:id/insured => 'policies_controller#show_insured'
get /insureds/:id => 'insureds_controller#show'
get /insured/new => 'insureds_controller#new'
post /insureds/create => 'insureds_controller#create'
delete /insureds/:id/delete => 'insureds_controller#delete'
#maguri, that's not all necessary. The stumbling block I was running into was that Rails couldn't automatically determine the correct routes. When I provided my own urls in the form_with declarations, everything went smoothly.
Observe the following change in my _form.html.erb for the Insured model, which belongs_to Policy, which has_one Insured.
<%= form_with model: #insured, url: policy_insured_path(#policy) local: true do |form| %>
In my updated insureds_controller.rb file, using #Phlip's suggestion:
def create
#policy = Policy.find(params[:policy_id])
#insured = #policy.create_insured(insured_params)
if #policy.insured.save
redirect_to policy_insured_path(params[:policy_id])
else
render 'new'
end
end
This allows me to keep routes.rb clean and simple:
resources :policies do
resource: insured
end
Thank you for your answer, it helped me discover the problem was with my routes.

Undefined method with “_path” while using simple_form_for

I am having problem with routing when using simple_form_for. I understand it is something to do with pluralizing but the same form is working perfectly for edit/update method.
undefined method `companies_path'
Did you mean? companys_path
company_path
companys_controller
def new
#company = Company.new
end
def create
#company = Company.new(company_params)
if #company.save
redirect_to #company
else
render 'new'
end
end
_form.html.haml
= simple_form_for #company do |f|
= f.input :name
= f.input :description
= f.input :website
= f.button :submit
rake routes
companys GET /companys(.:format) companys#index
POST /companys(.:format) companys#create
new_company GET /companys/new(.:format) companys#new
edit_company GET /companys/:id/edit(.:format) companys#edit
company GET /companys/:id(.:format) companys#show
PATCH /companys/:id(.:format) companys#update
PUT /companys/:id(.:format) companys#update
DELETE /companys/:id(.:format) companys#destroy
I guess the problem is, Edit/update is going for 'companys_path' and new/create is going for 'companies_path'. Any help is appreciated.
Controller name should be plural so in your case it should be companies_controller
Follow these steps to change it
Rename controller to companies_controller.rb
Change controller class name to
class CompaniesController < ActionController::Base
# controller code
end
Change in routes.rb
resources :companies
Edit
Controller naming conventions
link in comments by Greg
First thing, you should follow rails naming convention and rename your controller from companys_controller.rb to companies_controller.rb.
Your issue will be fixed after renaming.
Simple form taking assumption that you have followed rails naming convention and making request at companies_path which is not present in your routes.

simple_form undefined method model_name 3 classes error

So I just Nested some resources that weren't Nested before and since I have been trying to fix all of the path references. The biggest issue I have been having is with the fact that there are 2 nested resources within a larger nested resource like so:
Users->Photos->Comments
On my form, it keeps giving me the following error
undefined method `model_name' for "/users/2/photos/2/comments/new":String
The error page says that the source is around line #1 of the following (my comments/_form partial):
= simple_form_for ([#comment, new_user_photo_comment_path(#user,#photos,#comment)]) do |f|
= f.input :content, label: "Reply to thread"
=f.button :submit, class: "button"
This is my Comments controller:
class CommentsController < ApplicationController
before_action :authenticate_user!
def new
#photo=Photo.find(params[:photo_id])
end
def create
#photo =Photo.find(params[:photo_id])
#comment=Comment.create(params[:comment].permit(:content, :id, :photo_id))
#comment.user_id= current_user.id
#comment.photo_id= #photo.id
#user= User.find_by(params[:id])
if #comment.save
redirect_to user_photo_path(#photo, #user)
else
render 'comments/new'
end
end
end
At first, it is not preferably to nest resources deeper than two times.
You should consider to nest comments within only photos. It`s ok to do like so in routes.rb:
resources :users do
resources :photos
end
resources :photos do
resources :comments
end
And you errors is because
= simple_form_for ([#comment, new_user_photo_comment_path(#user,#photos,#comment)]) do |f|
gives for method simple_form_for as parameters:
1 - model Comment
2 - String /users/2/photos/2/comments/new
to set proper path (form action) form builders need models as all arguments.
Maybe something like
= simple_form_for ([#user,#photos,#comment]) do |f|
should work

Rails 4: 'redirect_to current_thing' undefined error

I have a model “Thing,” each of which has_many “Comments,” each of which in turn has_many “Votes.” I want to be able to vote on comments on the Thing show page. This is what I have so far:
Comments Controller:
def votecomment
#comment = Comment.find(params[:id])
Vote.create!(voteable_id: params[:id], voteable_type: 'Comment')
redirect_to current_thing
end
Things View:
<%= link_to “Vote”, vote_comment_path(:id => comment.id), method: :post %>
Routes:
post 'comments/:id/vote' => 'comments#vote', as: 'vote_comment'
But I'm getting back this error:
NameError in CommentsController#votecomment
undefined local variable or method `current_thing' for #<CommentsController:0x007f98efa69c00>
I tried moving the method to the Things controller, but I got the exact same type of error.
What am I doing wrong?
Assuming you have the following relation in comment.rb
belongs_to :thing
You can access the thing object of a comment using #comment.thing. Since redirect_to accepts objects, you can do
redirect_to #comment.thing
You have to understand that nothing is called current_thing if you are familiar with devise and you see ex current_user this is a method in the gem not a populated method with each model you create.
So if you want something like that add method to your application_controller or even application helper to get current_thing
def current_thing
Thing.find() --> or whatever the way you get that current thing.
end

undefined method ..._index_path Ruby on Rails

I am trying to get a basic form to work and am struggling because I keep getting the error
undefined method `profiles_index_path' for #<#<Class:0x4fe1ba8>:0x4fccda0>
I have checked through and can't seem to work out where I am going wrong.
In my view (new.html.erb) I have:
<%= form_for #profile do |f| %>
<%= f.text_field :name %>
<%= f.text_field :city %>
<%= f.text_field :country %>
<%= f.text_field :about %>
<%= f.submit "Create Profile" %>
<% end %>
In my profiles controller I have:
class ProfilesController < ApplicationController
def new
#title = "New Profile"
#profile = Profiles.new
end
def create
#user = current_user
#profile = #user.profiles.new(params[:profile])
if #profile.save
redirect_to profile_path, :notice => "Welcome to your new profile!"
else
render "profiles#new"
end
end
def edit
#user = current_user
#profile = #user.profiles.find(params[:id])
end
def update
#title = "Update Profile"
#user = current_user
#profile = #user.profiles.find(params[:id])
if #profile.update_attributes(params[:profile])
redirect_to profile_path
else
render action: "edit"
end
end
def index
#user = current_user
#profile = #user.profiles.all
#title = "Profile"
end
end
And finally in my profiles model I have
class Profiles < ActiveRecord::Base
belongs_to :user
end
Any help people can offer really would be much appreciated because I am stumped. :)
Sorry forgot to include routes:
controller :profiles do
get "newprofile" => "profiles#new"
get "updateprofile" => "profiles#update"
get "profile" => "profiles#home"
end
resources :profiles, :controller => 'profiles'
The problem is indeed the way you've pluralized your model name. Don't do that. It should be a Profile, not a Profiles. There my be some work around to allow you to use a plural model name, but the answer is to stick to Rails convention rather than fighting the framework. Rename your model to Profile and the url_for helpers will understand how to correctly turn a new Profile object into a /profiles URL.
If you run "rake routes" command, do "profiles_index" appear in your routes? Usually for the index page of a model, the work 'index' is left out so the route is profiles_path
You error probably comes from a view where you've used profiles_index_path instead of profiles_path
I think it's failing due to the convention not being followed with your model name.
So I think you're problem is mostly around that you aren't following the convention on the model name, which would classically be singular, since each instance represents one profile. I think the form_for helper is trying to figure out what to do with it and failing as a result. So you have two options to try and resolve. Refactor the model name to singular (I'm not clear exacly how difficult that would be) or pass the :url paramater to form_for so it knows where to post to.
<% form_for #profile, :url => path_to_create_action do |f| %>
more information here:
I'm working with Rails 5 and I got the same error and it was specific using the word Media as my model and RoR used Medium as the plural so I got different routes when executing rake routes.
What I did to fix it was:
Delete the model I just have created.
rails d scaffold Media
Edit config/initializers/inflections.rb with:
ActiveSupport::Inflector.inflections(:en) do |inflect|
# Here you can put the singular and plural form you expect
inflect.irregular 'media', 'medias'
end
Now execute the scaffold again:
rails g scaffold Media
Now you must have everything in the way you expected. Because you have overwritten the Pluralizations and Singularizations (Inflections) in Ruby on Rails.
I hope it could be useful.
Have you tried to replace your form_for tag with the following?
<%= form_for #profile, :as => :post do |f| %>
It looks like it's trying to treat it as a GET request to "/profile". And, since it is not finding the index action, it craps out. I think forcing it to do a POST will fix this issue.

Resources