I began coding in Rails several weeks ago, and I can't figure out why I have this error. I'm using Devise for log-ins and Formtastic for forms. The app was working correctly until I added the Acts_like_tags_on and reset the database.
The error message:
NoMethodError in UsersController#show
undefined method `username' for nil:NilClass
app/controllers/users_controller.rb:19:in `show'
Request
Parameters:
{"id"=>"sign_in"}
This is what I have in the Users Controller:
def show
#user = User.find_by_username(params[:id])
#title = #user.username
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
Any input would be helpful. Thanks!
After editing #user = User.find_by_username(params[:id]) to:
#user = User.find_by_user(params[:id])
The error becomes:
undefined method `find_by_user' for #
The username column does exist in the User table.
#user = User.find_by_username(params[:id])
That line above may be returning nil. If you do User.find_by_username("Superman-is-awesome") and that username does not exist in your database, it's going to return nil.
Then it is trying to do:
#title = #user.username
Which is essentially:
#title = nil.username
Which of course won't work. So could be something wrong with the parameter you are passing in.
Also, make sure your User table have a column called 'username'? Make sure you've run:
rake db:migrate
As well.
If you configured the routes correctly, you should have devise routes BEFORE user resource, like this:
devise_for :users
resources :users, except: "create"
This is actually a routing problem
The problem is that devise expects you to have a route that will turn:
"/users/sign_in" into sessions#new
but your routes file is missing that route, and so the dispatcher is matching against the:
"users/:id" route which then goes to:
users#show with :id => 'sign_in'
(and hence throws an error when it tries to find a user with the id of "sign_in")
You need to read the README doc for devise (google if you don't have it locally) - especially the part that describes how to add the standard set of routes to config/routes.rb Then do whatever it says. :)
Should be right after that.
I found that the user_id was being given the value of 'users'. After commenting the following line out in my routes.rb, the id was no longer given that value.
match '/:id' => 'users#show', :as => :user
I also needed the users_controllers #show to have the following line, since my user path uses the username. removing '_by_username' caused an error on pages that called for the username:
#user = User.find_by_username(params[:id])
Related
When I try to load the user's show view, it get the error Couldn't find User with 'id'=
it specifically points to the second line in the UsersController:
def show
#user = User.find(params[:id]) ## shows the error in this line
end
The funny thing is, it USED to load, up until I changed the routes to this:
Rails.application.routes.draw do
devise_for :users
get 'users/show'
root 'users#show'
get 'welcome/index'
resources :users
end
Why am I getting this error after changing the routes?(which I changed, because my objective is to go straight to the users profile after devise log in)How can it be fixed?
Oh, and the following is my user show view in case the error is in there:
<h1>This is the user show view </h1>
<p>Your email is: <%= #user.email %></p>
<p>Your name is: <%= #user.name %></p>
Thank you.
This does not work:
root 'users#show'
It tells rails to use your users#show page as startpage
But rails does not know which user it should show then. There is no user id given then. That is why you see in the error message id= without something behind the equal sign.
If you want to go to show action after login, instead of
#user = User.find(params[:id])
you can do:
#user = current_user
Devise by default redirects you to the root path.
The default root path 'welcome/index' is a collection action. That is, it does not need an id to be passed in.
Now you have changed that to a member action 'users/show/:id'. So you need to pass in the id.
The simplest way is to override devise in application controller like this:
def after_sign_in_path_for(resource)
redirect_to root_path(current_user.id)
end
I am following Michael Hartl's tutorial. I get the following error:
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User with 'id'=1
Extracted source (around line #155)
record = s.execute([id], self, connection).first
unless record
raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
end
record
rescue RangeError
Already have tried bundle install and restarted the server because the initial error related to the bcrypt Gemfile (using v 3.1.7).
Running rails console and inputing User.find(1) yields no user. However, User.all in rails c does reveal that I have one user but it has an id: 2 (the very first user I made was likely deleted during prior test runs).
app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
end
end
app/config/routes.rb
Rails.application.routes.draw do
get 'users/new'
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
resources :users
end
Currently URL/users/2 displays as expected
with the debug showing:
--- !ruby/hash:ActionController::Parameters
controller: users
action: show
id: '2'
However, this is not the case for id: 1 since it has previously been destoryed.
Is it possible to even reassign an id in the database after it has been created (i.e. to a prior id like 1 or any other arbitrary assignment)?
Thanks!
There's no need to care about the data you have deleted from the database. And you'll never need to visit a "show" view by type urls in your browser. For example, you may want to create an index view, showing all the users.
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
end
end
<% # "app/views/users/index.html.erb" %>
<% #users.each do |user| %>
<%= link_to "user.name", users_path(user) %>
<% end %>
When you click the links in the index page, Rails will automatically find the user's id and redirect you to the right page.
If you do want to type some url like "yourlocalhost/users/1" in your browser, it's reasonable to get the error you mentioned. Instead of trying to make that url working as you expected, you'd better add some error handling. For example, rescue that error to redirect your users to some page, then show them a notice: "Sorry man, that page is not exist, please visit other page. :P"
Generally, it's not a good idea to reuse ids in database which you have freed by deleting record. Because it's very easy to cause problems. For example, if you have other tables in your database, with a "user_id" column. It may have conflicts.
It's possible to assign a new value to the id of a record and save it.
But this is a very bad practice.
First, it will pretty much ruin your record associations which are all based on your record's primary key.
Second, it can lead to duplicate primary keys, either by assigning an id that will be used at a later point or by assigning an id already in use. Your DB will therefore disallow saving the record, either now or later.
The point of a primary key is that it has NO inherent meaning or significance other than being a unique identifer to the record... so you should never care about the value or characteristics of the primary key and so you should never have any need to change it.
In my oppinion, you have to ovoid your nil value by passing condition to redirect into your user index page. This way is usual way.
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find_by(id: params[:id])
if #user.nil?
redirect_to users_path
end
end
def new
end
end
Try to get user know to get right data because when passing into another id it will get unexpected data that user wanted
I'm using Rails 4 with strong parameters to try to find a user by a parameter called "provider_id".
The hope is that I'll be able to make a call with my API to a URL such as:
url.com/api/v1/user?provider=facebook?provider_id=12345
My routes are as follows: routes.rb
namespace :api do
namespace :v1 do
resources :users
match '/:provider/:provider_id', to: 'users#find_by_provider', via: 'get'
end
end
My Strong parameters are:
def user_params
params.require(:user).permit(:name, :age, :location, :provider, :provider_id) if params[:user]
end
My Function is:
def find_by_provider
#user = User.find(params[:provider_id])
respond_to do |format|
format.json { render json: #user }
end
end
Currently, I'm testing with:
url.com/api/v1/facebook/12345
and it is returning:
"{"provider"=>"facebook",
"provider_id"=>"12345"}"
which is good! But I now get the error: "Couldn't find User with id=12345"
Also, somewhat related: occasionally I receive an error that says "param not found: user".
Any suggestions? Thanks!
Change:
#user = User.find(params[:provider_id])
To:
#user = User.find_by(:provider_id => params[:provider_id])
find method will alyways search objects with the id column. Use the where method to search by other criterias/columns
Use:
#user = User.where(provider_id: params[:provider_id]).take
Take a look at http://guides.rubyonrails.org/active_record_querying.html if you want to learn more about the active record query interface.
This is a perfect example where to use find_by! (note the !).
#user = User.find_by!(:provider_id => params[:provider_id])
It works like find_by and returns one User. But if the user is not found it raises an ActiveRecord::RecordNotFound error. That exception is handled by Rails automatically and is turned into a 404 error page.
I have a really hard time understanding routes and I hope someone can help me.
Here's my custom controller
class SettingsController < ApplicationController
before_filter :authenticate_user!
def edit
#user = current_user
end
def update
#user = User.find(current_user.id)
if #user.update_attributes(params[:user])
# Sign in the user bypassing validation in case his password changed
sign_in #user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
end
and I have the file settings/edit.html.erb and my link
<li><%= link_to('Settings', edit_settings_path) %></li>
The route
get "settings/edit"
doesn't work for this, because then I get
undefined local variable or method `edit_settings_path' for #<#<Class:0x00000001814ad8>:0x00000002b40a80>
What route do I have to give this? I can't figure it out. If I put "/settings/edit" instead of a path it messes up as soon as I'm on a other resource page because the resource name is put BEFORE settings/edit
Thx
Following should do:
get 'settings/edit' => 'settings#edit', :as => :edit_settings
# you can change put to post as you see fit
put 'settings/edit' => 'settings#update'
If you use /settings/edit directly in link, you shouldn't have problem with other resource name being prepended in path. However, without the leading slash, i.e. settings/edit it might have that issue.
Reason why edit_settings_path is not working might be because you didn't declare a named route. You have to use :as option to define by which method you will be generating this path/url.
If you want to explicitly define the route, you would use something like
get 'settings/edit' => 'settings#edit', :as => edit_settings
This statement defines that when a GET request is received for setting/edit, call the SettingsController#edit method, and that views can reference this link using 'edit_settings_path'.
Take some time to read the Rails guide on routing. It explains routing better than any other reference out there.
Also keep in mind the rake routes task, that lists the details of all the routes defined in your application.
I'd like to create a rails route for editing a user's profile.
Instead of having to use /users/:id/edit, I'd like to have a url like /edit_profile
Is it possible to create a dynamic route that turns /edit_profile into /users/{user's id}/edit, or should I do thing in a controller or?
You might want to create a separate controller for this task but you could also continue using users_controller and just check whether there is a params[:id] set:
def edit
if params[:id]
#user = User.find(params[:id])
else
#user = current_user
end
end
But you should note that /users normally routes to the index action and not show if you still have the map.resources :users route. But you could set up a differently called singular route for that:
map.resources :users
map.resource :profile, :controller => "users"
This way /users would list all the users, /users/:id would show any user and /profile would show the show the currently logged in users page. To edit you own profile you would call '/profile/edit'.
Since a route and controller serve two different purposes, you will need both.
For the controller, assuming you're storing the user id in a session, you could just have your edit method do something like:
def edit
#user = User.find(session[:user_id])
end
Then have a route that looks something like:
map.edit_profile "edit_profile", :controller => "users", :action => "edit"
This route would give you a named route called edit_profile_path
Tomas Markauskas's answer could work, but here's the answer to your question from the Rails Guide:
get 'edit_profile', to: 'users#edit'
So, when someone goes to www.yoursite.com/edit_profile, it will route to www.yoursite.com/users/edit.
Then, in your controller you can access the user with
#user = User.find(session[:current_user_id])
Assuming you set that session variable when someone logs in. Also, don't forget to check if they're logged in. This will work if your using Resourceful Routing (the Rails default) or not.
Source: http://guides.rubyonrails.org/routing.html
make the route as
get '/users/:id/edit', to: 'users#edit', as: 'edit_profile'
As explained in this link section 'The hard way' :
http://augustl.com/blog/2009/styling_rails_urls/
The url will be
/users/edit_profile
Because the ID is no longer in the URL, we have to change the code a bit.
class User < ActiveRecord::Base
before_create :create_slug
def to_param
slug
end
def create_slug
self.slug = self.title.parameterize
end
end
When a user is created, the URL friendly version of the title is stored in the database, in the slug column.
For better understanding read the link below
http://blog.teamtreehouse.com/creating-vanity-urls-in-rails
write it in any home controler.
def set_roots
if current_user
redirect_to dashboard_home_index_path
else
redirect_to home_index_path
end
end
in routes.rb file
root :to => 'home#set_roots'
match "/find_roots" => "home#set_roots"