Devise confirmation: No routes matches - ruby-on-rails

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)

Related

ActiveRecord::RecordInvalid in OmniauthCallbacksController#twitter Validation failed: Email can't be blank

Whilst trying to implement Omniauth-twitter into my Rails app I've hit the error stated above.
The error centres on a statement in my controller and I understand it relates to the fact twitter does not provide an email on callback. I'm using devise for authentication. I also intend to install Facebook omniauth but want to get Twitter working first.
What code block can I implement to skip this validation for Twitter? Does it go in my controller or user model?
Here's my code as it stands -
OmniauthCallbacksController -
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def twitter
#details = request.env["omniauth.auth"]
#provider = #details["provider"]
#provider_id = #details["uid"]
#user = User.where(provider: #provider, provider_id: #provider_id).first
if #user.present?
#sign them in
else
# make a new user
#user = User.new
#user.provider = #provider
#user.provider_id = #provider_id
# because of has_secure_password - will this work?
#user.password = "AAAAAA!!"
#user.password_confirmation = "AAAAAA!!"
# let's save the key and secret
#user.key = #details["credentials"]["token"]
#user.secret = #details["credentials"]["secret"]
# lets fill in their details
#user.name = #details["info"]["name"]
#user.email = #details["info"]["email"]
#user.save!
end
session[:uid] = #user.id
flash[:success] = "You've logged in"
redirect_to root_path
end
def password_required?
super && provider.blank?
end
end
routes.rb
Rails.application.routes.draw do
#get "/auth/:provider/callback" => "social_logins#create"
devise_for :users, :controllers => { omniauth_callbacks: "omniauth_callbacks", registrations: 'registrations' }
resources :users
resources :events do
resources :bookings
end
# get 'welcome/index'
authenticated :user do
root 'events#index', as: "authenticated_root"
end
root 'welcome#index'
end
User.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, omniauth_providers: [:twitter]
has_many :events
has_many :bookings
has_many :authentications
end
I found the answer with this line of code in the OmniauthCallbackController
# lets fill in their details
#user.name = #details["info"]["name"]
if #provider == "twitter"? #user.save!(:validate => false) : #user.save!
# the above if statement allows for twitter to skip validation which requires an email
#user.email = #details["info"]["email"]
end
#user.save!

Cannot access "Current user" in rails

I am using devise and devise_ldap for my rails authentication. I am trying to use the built in helper, current user to display the users email on the welcome page of my application.
This is the code that I have tried to use to:
<% if user_signed_in? %>
<div>Signed in as... <%= current_user.email %></div>
<% end %>
when I sign in to the application, I get the error;
undefined method `email' for nil:NilClass
Here is my routes.rb
Rails.application.routes.draw do
devise_for :users
resources :users
resources :systems do
member do
get :targets, :sources
end
root 'systems#index'
end
and my users controller:
class UsersController < ApplicationController
authorize_resource
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
def index
#users = User.all.order("display_name asc")
end
# GET /users/1
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /stories/1/edit
def edit
respond_to do |format|
format.html
format.js
end
end
# POST /stories
def create
#user = User.new(user_params)
respond_to do |format|
puts 'user controller'
if #user.save!
format.html { redirect_to user_path(#user), notice: 'User was successfully created.' }
else
format.html { render :new }
end
end
end
# PATCH/PUT /stories/1
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to user_path(#user), notice: 'User was successfully updated.' }
else
format.html { render :edit }
end
end
end
# DELETE /stories/1
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_path notice: 'User was successfully destroyed.' }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:display_name, :email, :username)
end
end
my users model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
before_create :rememberable_value
before_save :get_ldap_values
devise :ldap_authenticatable, :rememberable, :trackable, :validatable
def get_ldap_values
if self.username
self.email = Devise::LDAP::Adapter.get_ldap_param(self.username,"mail").first if Devise::LDAP::Adapter.get_ldap_param(self.username,"mail")
self.display_name = Devise::LDAP::Adapter.get_ldap_param(self.username,"displayName").first if Devise::LDAP::Adapter.get_ldap_param(self.username,"displayName")
end
end
# def role?(role)
# return !!self.roles.find_by_name(role.to_s.camelize)
# end
def email_required?
false
end
def email_changed?
false
end
def rememberable_value
self.remember_token ||= Devise.friendly_token
end
def name_to_display
if self.display_name
self.display_name
else
self.username
end
end
def password_required?
false
end
def password_match?
self.errors[:password] << "can't be blank" if password.blank?
self.errors[:password_confirmation] << "can't be blank" if password_confirmation.blank?
self.errors[:password_confirmation] << "does not match password" if password != password_confirmation
password == password_confirmation && !password.blank?
end
end
I am not sure what I am missing to be able to access the current users information after a successful sign in.
Update
Here is the new routes file:
Rails.application.routes.draw do
devise_scope :user do
get '/users/sign_out' => 'devise/sessions#destroy'
get "/users/sign_in" => "devise/sessions#new"
# delete "/logout" => "devise/sessions#destroy"
end
devise_for :users
authenticate(:user) do
resources :users
resources :reports
resources :change_logs, only: [:index, :show]
resources :systems do
member do
get :targets, :sources
end
resources :change_logs, module: :systems
resources :components do
resources :change_logs, module: :components
end
resources :c_relations
end
resources :integrations
get '/static_pages/home' # => 'static_pages#home', as: 'home'
root 'systems#index'
end
In routes.rb you should enclose the rows following
devise_for :users
in a block
authenticate(:user) do
resources :users
[...]
end
The problem was that I had overridden the devise mapping and current_user. I removed them and was able to access current user in my views.
Do you have before_action :authenticate_user! in your controller chain at all?
Current_user could be nil after signin is if you aren't asking devise to authenticate the action.

Rails call controller action on successful object save

I have a user sign up form generated by devise. When the form is submitted and the user object is saved to the database I would like to create and save another object, generated in a separate controller (leads_controller.rb) and pass the user object that was just saved. The sign up form is collecting email, password and password confirmation.
Once the user is saved, I need to pass that user object to the leads_controller to call the new and create actions.
leads_controller.rb
class LeadsController < ApplicationController
include Databasedotcom::Rails::Controller
def new
#lead = Lead.new
end
def create
lead = Lead.new(params[:lead])
lead.Email = #user.email
end
end
routes.rb
# User route
devise_for :users
devise_for :lenders, skip: :sessions, :controllers => {:registrations => "lenders/registrations"}
devise_for :businesses, skip: :sessions
root :to => 'business_account#dashboard', :constraints => lambda { |request| request.env['warden'].user.class.name == 'Business' }, :as => "business_root"
root :to => 'lender_account#dashboard', :constraints => lambda { |request| request.env['warden'].user.class.name == 'Lender' }, :as => "lender_root"
# Leads route
resources :leads
registrations_controller.rb
class Lenders::RegistrationsController < Devise::RegistrationsController
before_filter :update_sanitized_params
def new
super
end
def create
super
end
def update
super
end
private
def update_sanitized_params
devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:email, :password, :password_confirmation, :type)}
end
end
Is there an action I can put in my registrations_controller.rb to pass the user object to leads_controller.rb?
Copy the content from
https://github.com/plataformatec/devise/blob/master/app/controllers/devise/registrations_controller.rb
and paste into registrations_controller.rb
Change routes.rb
# User route
devise_for :users, :controllers => { :registrations => "registrations" }
devise_for :businesses, skip: :sessions
root :to => 'business_account#dashboard', :constraints => lambda { |request| request.env['warden'].user.class.name == 'Business' }, :as => "business_root"
root :to => 'lender_account#dashboard', :constraints => lambda { |request| request.env['warden'].user.class.name == 'Lender' }, :as => "lender_root"
# Leads route
resources :leads
In registration_controller.rb change the create action as
NOTE:- see also the change in create action
def create
build_resource(sign_up_params)
resource_saved = resource.save
yield resource if block_given?
if resource_saved
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_flashing_format?
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
respond_with resource
end
end
In registration_controller.rb
def after_sign_up_path_for(resource)
redirect_to new_lead_path
#after_sign_in_path_for(resource)
end
Devise provide a helper method current_user by which you can know user object in leads_controller.rb and also in views
class LeadsController < ApplicationController
include Databasedotcom::Rails::Controller
def new
#lead = Lead.new
end
def create
lead = Lead.new(params[:lead])
lead.email = current_user.email
end
end

Reset Password Issue with Devise

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.

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

Resources