Reset Password Issue with Devise - ruby-on-rails

I'm using Devise in my Rails app and am running into an issue resetting passwords.
When I attempt to reset my password, I'm sent an email with a link to reset the password. After filling out the form with the new password, I get the error "The webpage has a redirect loop" in Chrome, and I get the following error in my logs:
Started GET "/users/password/edit?reset_password_token=[FILTERED]" for 127.0.0.1 at 2013-12-19 14:22:05 -0500
Processing by Devise::PasswordsController#edit as HTML
Parameters: {"reset_password_token"=>"[FILTERED]"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Redirected to http://localhost:3000/users/password/edit?reset_password_token=JatMT1fE-fQwsCWsEdy6
Filter chain halted as :require_no_authentication rendered or redirected
Completed 302 Found in 1.8ms (ActiveRecord: 0.4ms)
I can't seem to find any information on how to fix this problem.
user.rb
class User < ActiveRecord::Base
...
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:token_authenticatable, :confirmable, :lockable
...
end
devise.rb
Devise.setup do |config|
...
config.reset_password_within = 6.hours
...
end
routes.rb
Build::Application.routes.draw do
devise_for :users, :controllers => {:registrations => :registrations}
devise_scope :user do
post 'registrations' => 'registrations#create', :as => 'register'
post 'sessions' => 'sessions#create', :as => 'login'
delete 'sessions' => 'sessions#destroy', :as => 'logout'
end
resources :users do
match 'users/:id' => 'users#username'
get 'validate_username', on: :collection
get 'validate_email', on: :collection
get 'edit_profile', on: :member
get :projects, on: :member
get :favorites, on: :member
get :collections, on: :member
member do
get :follow
get :unfollow
get :following
get :followers
end
end
end
registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
skip_before_filter :verify_authenticity_token,
:if => Proc.new { |c| c.request.format == 'application/json' }
respond_to :json
def create
user = User.new(params[:user])
Rails.logger.info(user.inspect)
# comment out following line to re-enable confirmation
# resource.skip_confirmation!
if user.save
sign_in user
render :status => 200,
:json => { :success => true,
:info => "Registered",
:data => { :user => user,
:auth_token => current_user.authentication_token } }
else
redirect_to new_user_registration_path, notice: user.errors.full_messages[0]
Rails.logger.info(user.errors.inspect)
# render :status => :unprocessable_entity,
# :json => { :success => false,
# :info => resource.errors,
# :data => {} }
end
end
def update
#user = User.find(current_user.id)
successfully_updated = if needs_password?(#user, params)
#user.update_with_password(params[:user])
else
# remove the virtual current_password attribute
params[:user].delete(:current_password)
#user.update_without_password(params[:user])
end
if successfully_updated
if params[:update_email]
set_flash_message :alert, :signed_up_but_unconfirmed
redirect_to after_update_path_for(#user)
else
set_flash_message :notice, :updated
sign_in #user, :bypass => true
redirect_to after_update_path_for(#user)
end
else
redirect_to :back, alert: resource.errors.full_messages[0]
end
end
private
# check if we need password to update user data
def needs_password?(user,params)
!params[:profile]
end
protected
def after_update_path_for(resource)
user_path(resource)
end
end

Check your after_sign_in_path_for in ApplicationController and add redirect to root_url (not :back or request.env['HTTP_REFERER']) if it is password edit request.

I had exactly the same problem, except that I noticed that there was a repeated redirect to the password reset URL.
I think #Sergey Sokolov has the right answer, although I modified my after_sign_in_path:
def after_sign_in_path_for(resource_or_scope)
if request.referer.include? "reset_password"
root_path
else
request.referer
end
end
so that in cases other than the password reset the user will return to the page that he or she signed in from. This avoids an issue of a user following a password reset link in an email.
I was also doing something very stupid while troubleshooting and remained logged in as a different user when I was resetting the password for a different user while testing. This causes very strange behavior.

Related

Rails Devise methods & helpers don't work

I have inherited an application built with Rails (v. 4.2.0) + AngularJS. Most of it works reasonably well, but I have hit a wall with Devise (v .3.5.1) that I am unable to overcome.
The application is structured this way: Angular.js handles the client side and is served from the back by the Rails app through an API. (The structure is very similar to the one from this tutorial: https://thinkster.io/angular-rails).
The problem if that for some reason, the app does not recognize helper methods of devise such as: current_user or user_signin? among others. Currently, anyone could make a request to /api/users and get a JSON with the information.
For instance, if we add this code to the /controllers/api/employees_controller.rb and you make a request in your browser to /api/employees/:id you get the JSON despite nos being logged
def show
#employee = Employee.find(params[:id])
respond_to do |format|
format.json{
if user_signed_in? then
render text: #employee.to_json, status: 200
else
render :json => nil, status: 422
end
}
end
end
Note: in this application the entity "Employee" is a type of "User"
I have tried solutions named in this post Rails devise: user_signed_in? not working but it didn't work for me
Here are all the parts of the code that I think could offer some light to this issue
/controllers/api/users/sessions_controller.rb
module Api
class Users::SessionsController < Devise::SessionsController
before_filter :configure_sign_in_params, only: [:create]
#Devise couldn't find "users_url" so just defining it here (500 error)
def users_url
:root_path
end
# GET /resource/sign_in
def new
super
end
# POST /resource/sign_in
def create
user = User.new
if ( params[:user][:email] == "" || params[:user][:password] == "") then
render json: {errors: "Insufficient data provided (user and/or password)"}.to_json, status: :bad_request
elsif User.find_by_email(params[:user][:email]).present?
user = User.find_by_email(params[:user][:email])
if user.valid_password?(params[:user][:password]) then
sign_in :user, user
render json: user.to_json(only: [:id, :email, :name, :last_name, :type, :company_id,:configuration,:phone]), status: :created
else
render json: {errors: "Wrong password."}.to_json, status: :unauthorized
end
else
render json: {errors: "Could not find user with that email."}.to_json, status: :unauthorized
end
end
# DELETE /resource/sign_out
def destroy
puts "HEEEEY"
end
# protected
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_in_params
devise_parameter_sanitizer.for(:sign_in) << :attribute
end
end
end
models/user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable#, :confirmable
scope :admins, -> { where(admin: true) }
validates :email, presence: true
validates :name, presence: true, length: { in: 1..50 }
end
config/routes.rb
Rails.application.routes.draw do
namespace :api, defaults: {format: :json} do
resources :contacts
resources :job_application
# devise_for :admins, controllers: {sessions: 'admins/sessions'}
# devise_for :employees, controllers: {sessions: 'employees/sessions'}
devise_for :users, controllers: {
sessions: 'api/users/sessions',
registrations: 'api/users/registrations',
}
devise_for :employees, controllers: {
sessions: 'api/employees/sessions',
registrations: 'api/employees/registrations',
}
If you need any other part of the code, please just let me know.
Thank you very much!

Devise confirmation: No routes matches

User signed up
User received confirmation email
User click on user_confirmation_url(#resource, :confirmation_token => #token)
User goes to /users/confirmation.39?confirmation_token=V-UwSF5qzCt8mBVAFuwK
It get this error
If i manually change the url to: users/confirmation/39?confirmation_token=V-UwSF5qzCt8mBVAFuwK
I get this error: The action 'confirmation' could not be found for UsersController
Routes.rb
App::Application.routes.draw do
get "pages/quickstart"
get "pages/configuration"
get "pages/invoices"
get "/reports" => "reports#index"
get "/reports/historical_data" => "reports#historical_data", as: :historical_data
#get "statements/document/month/:date" => "statements#month", :document => true, as: :monthly_statements_document
#get "statements/month/:date/" => "statements#month", as: :monthly_statements
resources :reminders
resources :reminder_users
resources :forecasts
resources :statements
resources :monthly_statements
resources :fuel_cards
resources :accounts_payables
resources :accounts_receivables
resources :customers
resources :invoices
resources :suppliers
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
devise_for :users, :controllers => { :registrations => "registrations"}
# You can have the root of your site routed with "root"
root 'pages#quickstart', as: :home
get "/home" => "home#welcome"
get "/registrations", to: redirect('/users/edit')
get "/user", to: redirect('/users/edit')
get "/user/change_password", as: :change_password
match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
end
(I use this to allow user to edit their profile)
user_confirmation POST /users/confirmation(.:format) devise/confirmations#create
new_user_confirmation GET /users/confirmation/new(.:format) devise/confirmations#new
GET /users/confirmation(.:format) devise/confirmations#show
Model
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
UserController
class UsersController < ApplicationController
before_filter :authenticate_user!
def edit_password
#user = current_user
end
def update_password
#user = User.find(current_user.id)
if #user.update(user_params)
# Sign in the user by passing validation in case his password changed
sign_in #user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
private
def user_params
# NOTE: Using `strong_parameters` gem
params.required(:user).permit(:password, :password_confirmation)
end
end
RegistrationController
class RegistrationsController < Devise::RegistrationsController
def update
#user = User.find(current_user.id)
successfully_updated = if needs_password?(#user, params)
#user.update_with_password(devise_parameter_sanitizer.sanitize(:account_update))
else
# remove the virtual current_password attribute
# update_without_password doesn't know how to ignore it
params[:user].delete(:current_password)
#user.update_without_password(devise_parameter_sanitizer.sanitize(:account_update))
end
if successfully_updated
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case his password changed
sign_in #user, :bypass => true
#redirect_to after_update_path_for(#user)
redirect_to edit_user_registration_path
else
render "edit"
end
end
private
# check if we need password to update user data
# ie if password or email was changed
# extend this as needed
def needs_password?(user, params)
user.email != params[:user][:email] ||
params[:user][:password].present?
end
end
devise (3.4.1)
The issue here is with the view generators.
Do you see, in your path, you are getting users/confirmation.39 for your confirmation route...that 39 is being interpreted as a format by your controller. Its not expecting a user id (#resource) if you have a look at rake routes
the answer here is to remove #resource from your url_helper in the email/view, and if needed, pass ID in as a parameter with the token
user_confirmation_url(confirmation_token: #token, id: #resource)

Ruby on Rails: not authorized to access sign up page?

I have devise and CanCan set up, but I'm trying to get into sign up page in my rails application, but its redirecting me to home page saying that I'm not authorized to access this page.
I have a custom registration controller:
class Devise::RegistrationsController < DeviseController
before_filter :check_permissions, :only => [:new, :create, :cancel]
skip_before_filter :require_no_authentication
def check_permissions
authorize! :create, resource
end
def edit
#user = User.find(current_user.id)
#profile = Profile.new
end
def update
# required for settings form to submit when password is left blank
if params[:user][:password].blank? && params[:user][:password_confirmation].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
#user = User.find(current_user.id)
if #user.update_attributes(params[:user])
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case his password changed
sign_in #user, :bypass => true
redirect_to after_update_path_for(#user)
else
render "edit"
end
end
protected
def after_update_path_for(resource)
user_path(resource)
end
private
end
It has something to do with before_filter :check_permissions,... because when I delete this line, I get an error saying
undefined method `user_registration_path'
from my registration form in my `devise/registrations#new:
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
How do I fix my registration form?
Also, this is my routes:
devise_for :user, :controllers => { :registrations => "registrations" }, :skip => [:registrations, :sessions] do
get 'signup' => 'devise/registrations#new', :as => :new_user_registration
end
Okay from what it looks like you've done is used CanCans authorize! method to handle the authorization in a controller action which will raise the cancan exception error. Can you not try and do
check_authorization :unless => :devise_controller?
I back this up with a change made a cancan commit seen here adding :if and :unless options to check_authorization - closes #284. Comments can be seen in the following issue: GitHub issue 284. Where Ryan states:
It would be nice if the check_authorization method allowed a block to dynamically customize the behavior. If it returned true it would perform the authorization.
Correct me if I am wrong but is this not what you are trying to do. Hopefully this sheds some light.
Another thing with regards to your routes.rb where you have done:
devise_for :user, :controllers => { :registrations => "registrations" }, :skip => [:registrations, :sessions] do
get 'signup' => 'devise/registrations#new', :as => :new_user_registration
end
This all looks a bit mis-match to me. Do you have by any chance a devise folder containing all devise controllers in your controller directory. If so could you not try and make your devise route block look like the following:
devise_for :users, :controllers => {:sessions => 'devise/sessions', :registrations => 'devise/registrations', :passwords => 'devise/passwords'}, :skip => [:sessions] do
get '/login' => 'devise/sessions#new', :as => :new_user_session
get '/register' => 'devise/registrations#new', :as => :registrations
post '/login' => 'devise/sessions#create', :as => :user_session
get '/logout' => 'devise/sessions#destroy', :as => :destroy_user_session
end
update
From the link GitHub - CheckAuthorizationI pasted in my comment I believe you can the method check_authorization as the example shows you can do:
class ApplicationController < ActionController::Base
check_authorization
end
The controller then shows that you can:
Supply the name of a controller method to be called. The authorization check only takes place if this returns false.
check_authorization :unless => :devise_controller?

Rails - Email confirmation link giving 'Unknown Action' error

I need a bit of help. I am trying to:
Send am email with a link.
Have the link set the user.email_activation_token = true
Then redirect to the home page.
Currently I have a link that goes to the email but it gives me this error.
(I'm using HAML btw.)
Edit: There is no view currently.
Unknown action
The action 'show' could not be found for UsersController
user_mailer/registration_confirmation
Confirm your email address please!
= accept_invitation_users_url({:token=>#user.email_activation_token})
users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
UserMailer.registration_confirmation(#user).deliver
redirect_to root_url, :notice => "Signed up!"
else
render "new"
end
def accept_invitation
#user = User.find_by_email_activation_token!(params[:token])
#user.email_activation_token = true
redirect_to root_url, :notice => "Email has been verified."
end
end
end
email_activations_controller.rb
class EmailActivationsController < ApplicationController
def edit
#user = User.find_by_email_activation_token!(params[:id])
#user.email_activation_token = true
save!
redirect_to root_url, :notice => "Email has been verified."
end
def new
#user = User.find_by_email_activation_token!(params[:id])
end
def edit
end
end
user.rb (user model)
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
before_save { |user| user.email = email.downcase }
before_create { generate_token(:auth_token) }
# before_create { generate_token(:email_activation_token) }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
VALID_PASSWORD_REGEX = /^(?=.*[a-zA-Z])(?=.*[0-9]).{6,}$/
validates_confirmation_of :password
validates :password, :on => :create, presence: true, format: { with: VALID_PASSWORD_REGEX }
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
end
routes.rb
LootApp::Application.routes.draw do
get "password_resets/new"
get "sessions/new"
resources :users
resources :sessions
resources :password_resets
resources :email_activations
resources :users do
collection do
get :accept_invitation
end
end
# get "users/new"
get "static_pages/home"
get "static_pages/help"
root to: 'static_pages#home'
match "sign_up", to: "users#new"
match '/help', to: 'static_pages#help'
match '/log_in', to: 'sessions#new'
match '/log_out', to: 'sessions#destroy'
end
Why are you passing, activation token instead of id in the accept_invitation_users_url? When you have this code:
resources :users do
member do
get :accept_invitation
end
end
in the routes, we are assuming that, accept_invitation is a Restful route and will give id in its url. See http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
So, I think you should be doing something like this:
routes.rb
# resources :users ### Remove this as it is reduntant
resources :users do
member do
get :accept_invitation
end
end
user_mailer/registration_confirmation
Confirm your email address please!
= accept_invitation_users_url(#user)
users_controller.rb
def accept_invitation
#user = User.find(params[:id])
#user.email_activation_token = true
redirect_to root_url, :notice => "Email has been verified."
end
After reading comments
Yes, as #Frederick Cheung said in the comments, passing id instead of token would defeat the point of sending the email confrmation and would make it easy for people to confirm an email address without actually receiving the email.
So, please refer to #PriteshJ's answer. Apparently, you just added an extra line resources :users, in routes.rb and I made a fuss out of it :). Just remove the line and you will be ok.
Try by changing the routes like this ..
resources :users do
collection do
get :accept_invitation
end
end
resources :users
resources :sessions
resources :password_resets
resources :email_activations
You have called resources :users twice.
Remove the first call
there are two routes for users in routes.rb
remove resources :users
the first one resources users overrides the next users resource
so the application does not know there is a collection route for accept_invitation and
treats it as a id for show actions as the url genreated for the action will be
/users/accept_invitation
which matches the signature of show /users/:id
removing the first resources :users should do the trick
also I don't see any use of email_activations_controller.rb
may be you can safely remove it

Finding and using the id of a permalink page for non logged in users with ruby on rails

I'm modifying a micro post ruby on rails tutorial app and am running into the following problem that has me stumped:
A user has a permalink url, http://localhost:3000/users/exampleuser. Visitors can come to this url and answer a survey poll. The following code works if exampleuser (current_user) is logged in to their own account. However if you come as a Visitor, who is not required to log in, I receive what looks like a Null User ID error. All my attempts at trying to assign the correct user id have been unsuccessful even though it looks to me that the user id is not null anymore.
Here is the error I receive:
Started POST "/polls" for 127.0.0.1 at 2012-02-24 20:28:56 -0500
Processing by PollsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ZE/KXWCnBfE8PAn1CyAM51rnQI6z2Ut1UvHavEqSkZY=", "poll"=>{"overall_grade"=>"strong", "relevance"=>"strong", "personalization"=>"strong", "design"=>"strong", "value_proposition"=>"strong", "responder_name"=>"test", "responder_email"=>"test#test.com", "comments"=>"test"}, "commit"=>"Submit Grade"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT 1
Completed 500 Internal Server Error in 47ms
RuntimeError (Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id):
app/controllers/polls_controller.rb:5:in `create'
Using the console I can see that the first user (exampleuser) is ok.
ruby-1.9.2-p290 :001 > User.find(1)
User Load (13.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1
[["id", 1]] => #<User id: 1, name: "Example User", email: "example#railstutorial.org",
created_at: "2012-02-23 17:27:45", updated_at: "2012-02-23 17:27:45",
encrypted_password: "418b54481fffe05051621c500d69e44fd25573145c0b12e1860...", salt:
"57d9f6da0f6554e92c4180a469d5a1807c4a9dd46ce47c30b45...", admin: true, username:
"exampleuser", permalink: "exampleuser">
But this logic doesn't work in my Polls controller for some reason. Specifically I believe that the following lines in Polls Controller are the issue:
user_to_grade = User.find_by_id(#user.id)
#poll = user_to_grade.polls.build(params[:poll])
Any insights would be most appreciated.
John
Polls Controller
class PollsController < ApplicationController
def create
if current_user.blank?
user_to_grade = User.find_by_id(#user.id)
#poll = user_to_grade.polls.build(params[:poll])
else
#poll = current_user.polls.build(params[:poll])
end
if #poll.save
flash[:success] = "Pitch graded successfully!"
redirect_to root_path
else
render 'pages/home'
end
end
end
Polls Model
class Poll < ActiveRecord::Base
attr_accessible :overall_grade, :personalization, :relevance, :value_proposition, :design, :other, :responder_name, :responder_email, :comments, :next_steps
belongs_to :user
validates :user_id, :presence => true
validates :overall_grade, :presence => true
default_scope :order => 'polls.created_at DESC'
end
Users Model
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :username, :email, :password, :password_confirmation
has_many :polls, :dependent => :destroy
username_regex = /\A[\w\-]+\z/i
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :username, :presence => true,
:length => { :maximum => 50 },
:format => { :with => username_regex },
:uniqueness => { :case_sensitive => false }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password, :create_permalink
#Returns true if the user's password matches the submitted password
def has_password?(submitted_password)
#Compare stored to submitted encrypted versions
encrypted_password == encrypt(submitted_password)
end
def self.authenticate(email, submitted_password)
#handles 2 scenarios: invalid email and a successful email, password mismatch implicitly since returns nil at end of method
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
def self.authenticate_with_salt(id, cookie_salt)
user = find_by_id(id)
(user && user.salt == cookie_salt) ? user : nil
end
def to_param
permalink
end
private
def encrypt_password
self.salt = make_salt unless has_password?(password)
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
def create_permalink
self.permalink = username.downcase
end
end
Users Controller
class UsersController < ApplicationController
before_filter :authenticate, :only => [:index, :edit, :update, :destroy]
before_filter :correct_user, :only => [:edit, :update]
before_filter :admin_user, :only => [:index, :destroy]
def show
#user = User.find_by_permalink(params[:id])
#polls = #user.polls.paginate(:page => params[:page])
#title = #user.name
#poll = Poll.new
end
def new
#user = User.new
#title = "Sign up"
end
def create
#user = User.new(params[:user])
if #user.save
#Handle a successful save.
sign_in #user
flash[:success] = "Signup Success welcome to Grademypitch!"
redirect_to #user
else
#title = "Sign up"
#user.password = ""
render 'new'
end
end
def edit
#title = "Edit user"
end
def update
#user = User.find_by_permalink(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated."
redirect_to #user
else
#title = "Edit user"
render 'edit'
end
end
def index
#title = "All users"
#users = User.paginate(:page => params[:page])
end
def destroy
User.find_by_permalink(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_path
end
private
def authenticate
deny_access unless signed_in?
end
def correct_user
#user = User.find_by_permalink(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
Pages Controller
class PagesController < ApplicationController
def home
#title = "Home"
#poll = Poll.new
end
def contact
#title = "Contact"
end
def about
#title = "About"
end
def help
#title = "Help"
end
end
Routes
SampleApp::Application.routes.draw do
# removed when added session new/create/destroy.... get "sessions/new"
#get "users/new" , can remove now that resources :users added cause it automatically adds all routes for users!
resources :users
resources :sessions, :only => [:new, :create, :destroy]
resources :polls, :only => [:new, :create]
match '/signup', :to => 'users#new'
match '/signin', :to => 'sessions#new'
match '/signout', :to => 'sessions#destroy'
root :to => 'pages#home'
match '/contact', :to => 'pages#contact'
match '/about', :to => 'pages#about'
match '/help', :to => 'pages#help'
end
Yes, line 5 of your PollsController is the problem:
user_to_grade = User.find_by_id(#user.id)
And it doesn't look like you've defined #user anywhere in your PollsController.
Here is the relevant part:
if current_user.blank?
user_to_grade = User.find_by_id(#user.id)
#poll = user_to_grade.polls.build(params[:poll])
else
#poll = current_user.polls.build(params[:poll])
end
When the user is logged in, you're building a poll on the current user. When the user isn't logged in, you're first trying to find a user with the same id as #user (nil) which fails, and then trying to build a poll on that user.
What exactly is your desired behavior for users that aren't logged in? Should they be able to hit the create action at all?
So I figured this out.
Step 1 - I installed ruby-debug which helped me determine that the #user.id was nil when it reached the polls controller. So between the users controller and the polls controller the #user.id was being forgotten.
Step 2 - I researched that the session function as a possible solution so I modified the following areas to:
Users Controller
def show
#user = User.find_by_permalink(params[:id])
#polls = #user.polls.paginate(:page => params[:page])
#title = #user.name
#poll = Poll.new
if current_user.blank?
session[:remember_token] = #user.id
end
end
Here I added a session token to remember the user id from the user page with the permalink - i.e. users/exampleuser. So when I now goto the Polls controller it can call upon the session token and find out what user id we were coming from with the following code...
Polls Controller
def create
if current_user.blank?
user_to_grade = User.find_by_id(session[:remember_token])
#poll = user_to_grade.polls.build(params[:poll])
else
#poll = current_user.polls.build(params[:poll])
end
.
.
.
The key line is the User.find_by_id(session[:remember_token]). This now uses the user id from the user controller and is not nil anymore which solves the issue of how to remember the user id from controller to controller!

Resources