devise customization in ruby on rails - ruby-on-rails

I am implementing devise for user registration but some customizations and it is below.
When user registers with username,email and password, an email will go to user
In email user will get a secret code which is required to complete sign up process.
When user clicks "Go to App" button, It will redirect user to App and here user has to use that secret code to complete sign up process.
Once user completes sign up process, there would be one to one relationship between user and that secret code.
I searched a lot on internet but could not find answer.
Problem: I do not know how to create secret code in rails and then send it to user thourgh email and then match it with code that user got.
Note: Secret code and password are two different things in my application.

Devise has an internal module called Confirmable that does exactly this.
In order to use it, all you need to do is:
Make sure your devise model is :confirmable and :registerable
class User
# ...
devise :confirmable, :registerable ...
# ...
end
Run a migration that creates confirmation_token fields
class AddConfirmableToUsers < ActiveRecord::Migration
def self.up
change_table(:users) do |t|
t.confirmable
end
add_index :users, :confirmation_token, :unique => true
end
def self.down
remove_column :users, :confirmable
end
end
If you already have users, and don't want them to follow this confirmation process, than you need to make them confirmed. You can do that doing
User.update_all ["confirmed_at = ?", Time.now]
on the console.
More references: Confirable Module, Adding confirmable to Users in Devise

Related

How can I use devise to send a reset password link?

I currently have an app that allows users to invite other users to their organization. How can I make it so that devise will send a reset password link to the users that have been invited?
Add recoverable and use the send_reset_password_instructions method.
class User < ActiveRecord::Base
devise :recoverable
...
end
User.find(1).send_reset_password_instructions

send password change confirmation with devise

I want to configure devise to send a confirmation email when the user has changed their password as a security measure. I'd prefer to re-use my devise mailers if possible. Any ideas how to do this?
Untested, but I'd try to do this within your User model with a simple after_update callback:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable # whatever
after_update :send_password_changed_notification
# attr_accessible, validations, ...
private
def send_password_changed_notification
# Send email with the mailer of your choice,
# e. g. your existing custom Devise mailer:
YourDeviseMailer.password_changed_notification(self).deliver if password_changed?
end
end
I would configure the update user action, you can read on how to do that in their documentation. Check how devise handles confirmations of new registered users in registration action and re-use that code in your new reset password action.

Disable Devise confirmable mails

Recently I added the confirmable module to my User class. I already have a quite nice mailing system (Sidekiq, Sendgrid...) in my app, so I created my own "confirm account" mail. The problem now is to disable Devise from sending its default email. Is there any way to completely disable the Devise mailing system?
Added:
I want to maintain the confirmable module, as I am using its attributes and routes.
I can't use skip_confirmation! because I want the users to confirm their account.
I just want to disable Devise mails.
Use the source, Luke:
# lib/devise/models/confirmable.rb
# A callback method used to deliver confirmation
# instructions on creation. This can be overriden
# in models to map to a nice sign up e-mail.
def send_on_create_confirmation_instructions
send_devise_notification(:confirmation_instructions)
end
So override this method in your model to do nothing.
Try overriding the following devise method in your model:
def confirmation_required?
!confirmed?
end
or use skip_confirmation!:
user = User.new(params)
user.skip_confirmation!
user.save!
Use skip_confirmation! method before saving any object.
def create
#user = User.new(params[:user])
#user.skip_confirmation!
#user.save!
end
I think just removing
:confirmable
from the user model should do it
or have you tried disabling
config/environments/development.rb
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
I recommend you
User.skip_reconfirmation!
That is skip confirm mail and update email not to use "confirm!"
remove (:confirmable) from devise model
ex:- here my devise model is User
here I used like this.
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,:omniauthable
end

Remove an argument from a Ruby method call at the root of a class. On-the-fly

Here is a Ruby class:
class User
devise :trackable, :confirmable
end
For most instances I want :confirmable to be present, but for some instances, I would like to remove :confirmable before instantiation.
QUESTION: How to remove :confirmable on-the-fly?
I would rather avoid creating a separate class.
devise :confirmable adds a number of methods to your model, one of which is skip_confirmation!:
If you don’t want confirmation to be sent on create, neither a code to
be generated, call skip_confirmation!
Example:
user = User.new
user.skip_confirmation!
You will need the migrations for both :trackable and :confirmable in any case for your DB.
Wouldn't it be easier to just have :confirmable defined for both cases, but in the case you don't want it, you can automatically confirm the user account from within the controller, after the user is created?
see:
https://github.com/plataformatec/devise/blob/master/lib/devise/models/confirmable.rb
lines 27..30 contain the before_create and after_create hooks
you'll need to do this modification:
you'll need to override :confirmation_required? , so that it returns true
only in the cases where you want a confirmation token to be generated and a confirmation email to be sent.
In the case you don't need the confirmation email, you can do a user.confirm! after creating the user account.
You could put this in as an additional after_create action.
e.g.
module Devise
module Models
module Confirmable
after_create :confirm! , :if => :confirmation_not_required? # you'll need to define that method
private
def confirmation_required? # overriding the default behavior
your_special_conditions && !confirmed?
end
def confirmation_not_required?
! confirmation_required?
end
end
end
end
Note:
Instead of user.confirm! you could also use user.skip_confirmation!

Authenticate custom strategy without creating Devise user

My setup: Rails 3.0.9, Ruby 1.9.2, Devise 1.3.4, Warden 1.0.4
I'm trying to figure out if it possible to authenticate a custom strategy and not have to create a devise user in the process upon successful authentication. In my config.warden block, the authentication works fine but if I don't create a Devise user, I won't be authenticated. My ideal scenario requires me to either successfully authenticate against a 3rd party provider and sign into my app (using Devise without a corresponding Devise user record) or if I fail to authenticate, then try Devise standard login path.
Here is the devise.rb code snippet I got working but I have to create a devise user for the authentication to work, this is something I wish to avoid
config.warden do |manager|
manager.strategies.add(:custom_strategy) do
def valid?
params[:user] && params[:user][:email] && params[:user][:password]
end
def authenticate!
...perform authentication against 3rd party provider...
if successful_authentication
u = User.find_or_initialize_by_email(params[:user][:email])
if u.new_record?
u.app = 'blah'
u.save
end
success!(u)
end
end
end
manager.default_strategies(:scope => :user).unshift :custom_strategy
end
I realized the question is old but I saw it a couple of time when I was searching for a solution to similar thing so I decided to post the answer in case anyone in the future stumbles upon similar issue. Hope this will help!
I recently had to do similar thing -> had users in my database that were authenticated with some devise/warden strategies but had created another app that has to have access to some of the endpoints to my application. Basically I wanted to do a HMAC authentication.
But I didn't want to involve any user objects in that process and here is what I had to do (provided that you already have you custom strategy that authenticates incoming request without using user object)
create a fake user model that is used so that devise wont blow op. You dont have to create any database table for that
mine looked similar to below:
class Worker # no need to create a table for him
extend ActiveModel::Callbacks
extend Devise::Models
include ActiveModel::Validations
include Concerns::ObjectlessAuthenticatable
define_model_callbacks :validation
attr_accessor :id
def persisted
false
end
def initialize(id)
#id = id
end
def self.serialize_from_session(id)
self.new(id: id)
end
def self.serialize_into_session(record)
[record.id]
end
def self.http_authenticatable
false
end
end
then in devise initializer (/initializers/devise.rb) I've added separate authentication strategy like below:
...
config.warden do |manager|
manager.scope_defaults :user, :strategies => [
...strategies i was using for users
]
manager.scope_defaults :worker, :strategies => [:worker_authentication], store: false, action: 'unautenticated_worker'
manager.failure_app = CustomFailingApp
end
...
then in routes.rb I had to create a mapping for devise to use like so
devise_for :worker # you can pass some custom options here
then wherever I needed to authenticate the worker, not the user I just had to call (in the controller) authenticate_worker!
I would expect that this is against the design of devise where all actions are done using restful routes for a resource. That said, the comments in Warden's success! method say:
# Parameters:
# user - The user object to login. This object can be anything you have setup to serialize in and out of the session
So could you not change the object u to some other object that represents the user, like a plain old Hash?

Resources