Remove email field in devise gem? - ruby-on-rails

I would like to NOT require email for signing only mobile number to register user and login in using devise gem. I removed email from config/initializers/devise.rb:

This is the link to the validate.rb file of devise. You can see a method email_required? in the model. So I guess
def email_required?
false
end
You need to put above method in your model.rb file.
You'll also need to make a slight modification to your users table. By default, Devise does not allow the email field to be null. Create and run change a migration that allows email to be null
# in console
rails g migration AddChangeColumnNullToUserEmail
# migration file
class AddChangeColumnNullToUserEmail < ActiveRecord::Migration
def self.up
change_column :users, :email, :string, :null => true
end
def self.down
change_column :users, :email, :string, :null => false
end
end

You can use this guide, except use mobile instead of username. e.g.
In devise.rb:
config.authentication_keys = [:mobile]
In your controller:
.permit(:mobile)
Change the email field to your mobile field in app/views/devise/sessions/new.html.erb and app/views/devise/registrations/new.html.erb
In devise.en.yml:
invalid: 'Invalid mobile number or password.'
not_found_in_database: 'Invalid mobile number or password.'

As a complement of #divyang's answers. You should also remove de email's index on users table...
remove_index "users", name: "index_users_on_email"

Related

BCrypt::Errors::InvalidHash in SessionsController#create

I've tried looking at previous questions and answers regarding this error, but the solutions didn't seem to work for me. The error is thrown on the line:
if customer && customer.authenticate(params[:session][:password_digest])
I am able to Sign Up a user (under a company) and sign up a company, but I get this BCrypt error whenever I try to log a user in. I only started using the has_secure_password stuff etc once my user model and company model etc. were in place, I just realised later that it was silly to not protect passwords.
Even if I create a new user now, I still get this error logging on.
I think this might be due to my relationships of my Users? (maybe completely not, I am very new to Ruby!) My users belong to a company (many to one), and when they sign up they choose a company from a list in order to be listed under it in the database. Here is my code relating to this error:
class SessionsController < ApplicationController
def new
end
def create
customer = Customer.find_by_email(params[:session][:email])
if customer && customer.authenticate(params[:session][:password_digest])
log_in customer #see sessions helper
remember customer #see sessions helper
redirect_to '/main'
else
redirect_to '/login'
end
end
def destroy
#session[:user_id] = nil
forget(current_customer)
session.delete(:customer_id)
#current_customer = nil
redirect_to '/'
end
end
class CreateCustomers < ActiveRecord::Migration
def change
create_table :customers do |t|
t.timestamps
t.references :business, foreign_key: true
t.timestamps
t.string :first_name
t.string :last_name
t.string :email
t.string :password_digest
t.string :remember_digest
t.string :role
end
end
end
class CustomersController < ApplicationController
def new
#customer = Customer.new
#businesses = Business.all
end
def create
#customer = Customer.create(customer_params)
#customer.save!
session[:customer_id] = #customer.id
redirect_to '/'
rescue ActiveRecord::RecordInvalid => ex
render action: 'new', alert: ex.message
end
private
def customer_params
params.require(:customer).permit(:first_name, :last_name, :business_no, :email, :password_digest, :business_id) #replace company with company ID
end
end
Please help me, I'm tearing my hair out :(
The error you're getting probably means that the password_digest stored for that user is invalid for some reason (empty perhaps).
Enter a rails console: rails console
and execute the following:
u = User.find_by(email: "your_user_email")
puts u.password_digest
and see what the output is.
(also as mentioned in a comment on your question, you should use the plain text password when you use the authenticate method)
Update
You shouldn't use the password_digest attribute directly, instead there are two attributes you should be using: password and password_confirmation (these attributes become available to you automatically when you use has_secure_password, so you don't need to define them).
So in your controller, instead of this:
params.require(:customer).permit(:first_name, :last_name, :business_no, :email, :password_digest, :business_id) #replace company with company ID
You should have:
params.require(:customer).permit(:first_name, :last_name, :business_no, :email, :password, :password_confirmation :business_id) #replace company with company ID
and edit your form accordingly to provide inputs for password and password_confirmation.
Now when you create your object using these params, it will automatically assign the password digest into password_digest by encrypting the clear text contained in password and password_confirmation.

How to modify Devise's message on a specific step of its workflow?

After Sign Up a new user I get redirected to a Sign In page with the following flash[:alert] message:
"You need to sign in or sign up before
continuing."
My User model uses Devise's :confirmable module so it would be nice if after Sign Up a user would see a modified message instead:
"Thanks for signing up. We have sent you a confirmational email. Please check your email"
Is there a way to achieve it?
Notes about Devise workflow:
Currently a user has no idea that a confirmational email was sent to him. He will see Devise's failure message only when he tries to Log In using unconfirmed email address:
"You have to confirm your email address before continuing."
Here's solution:
https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-up-(registration)
I just followed first 2 steps:
1) Create RegistrationsController:
class RegistrationsController < Devise::RegistrationsController
protected
# TODO: will this method be triggered one day?
def after_sign_up_path_for(resource)
# '/an/example/path'
new_user_session_path
end
def after_inactive_sign_up_path_for(resource)
new_user_session_path
end
end
2) Change routes to:
devise_for :users, :controllers => {:registrations => 'registrations'}
First, add devise :confirmable to your models/user.rb
devise :confirmable
Then, do the migration as:
rails g migration add_confirmable_to_devise
Will generate db/migrate/YYYYMMDDxxx_add_confirmable_to_devise.rb. Add the following to it in order to do the migration.
class AddConfirmableToDevise < ActiveRecord::Migration
# Note: You can't use change, as User.update_all will fail in the down migration
def up
add_column :users, :confirmation_token, :string
add_column :users, :confirmed_at, :datetime
add_column :users, :confirmation_sent_at, :datetime
# add_column :users, :unconfirmed_email, :string # Only if using reconfirmable
add_index :users, :confirmation_token, unique: true
# User.reset_column_information # Need for some types of updates, but not for update_all.
# To avoid a short time window between running the migration and updating all existing
# users as confirmed, do the following
User.all.update_all confirmed_at: Time.now
# All existing user accounts should be able to log in after this.
# Remind: Rails using SQLite as default. And SQLite has no such function :NOW.
# Use :date('now') instead of :NOW when using SQLite.
# => execute("UPDATE users SET confirmed_at = date('now')")
# Or => User.all.update_all confirmed_at: Time.now
end
def down
remove_columns :users, :confirmation_token, :confirmed_at, :confirmation_sent_at
# remove_columns :users, :unconfirmed_email # Only if using reconfirmable
end
end
Do the migration rake db:migrate
If not using reconfirmable, update the configuration in config/initializers/devise.rb
config.reconfirmable = false
Hope this will help you.
You need to add it to devise.en.yml file which is in /config/locales/ directory. Under devise > registrations, add signed_up_but_unconfirmed and set a value
devise:
registrations:
signed_up_but_unconfirmed: "Thanks for signing up. We have sent you a confirmational email. Please check your email."
Hope this helps!

implement devise recoverable and confirmable on non devise user login setup

I have custom functionalities developed for user's login and oauth login and now i wanted to add options for Forgotten Password (reset user's password) and confirm email (including send confirmation email).
Is it possible to add those devise features without rebuilding my whole user model and sessions controller?
Short answer: Yes it's possible.
Longer answer:
Here's how you can introduce confirmable to users while also marking existing users as confirmed.
add this to your users model.
devise :registerable, **:confirmable**
Then, do the migration as:
( in your terminal)
rails g migration add_confirmable_to_devise
Your new migration:
class AddConfirmableToDevise < ActiveRecord::Migration
# Note: You can't use change, as User.update_all with fail in the down migration
def self.up
add_column :users, :confirmation_token, :string
add_column :users, :confirmed_at, :datetime
add_column :users, :confirmation_sent_at, :datetime
# add_column :users, :unconfirmed_email, :string # Only if using reconfirmable
add_index :users, :confirmation_token, :unique => true
# User.reset_column_information # Need for some types of updates, but not for update_all.
# To avoid a short time window between running the migration and updating all existing
# users as confirmed, do the following
User.update_all(:confirmed_at => Time.now)
# All existing user accounts should be able to log in after this.
end
def self.down
remove_columns :users, :confirmation_token, :confirmed_at, :confirmation_sent_at
# remove_columns :users, :unconfirmed_email # Only if using reconfirmable
end
end
If not using reconfirmable, update the configuration in config/initializers/devise.rb
config.reconfirmable = false
In your Terminal:
rails generate devise:views confirmable
rake db:migrate
Notes:
I had the same issue and did it the same way. I'm just copy pasting from the source.
If you got any further issues your first source should be the devise How to page with over 9000 tutorials

How to make an admin user using sign up with google gem in rails 3

I am making an app that I want to only use google to log in (because I am using other google api and i want to sync account.) I also want admin to be able to make other user admin too.
I want to make some user admin, but if they are log in with google, how can i make this exception in controller?
Is it best to save specific user in database?
I'm so confuse! please help.
right now this is what i have for admin
omniauth for checking google login
class OmniauthCallbacksController < ApplicationController
def google_oauth2
if auth_details.info['email'].split("#")[1] == "company_name.net"
user = User.from_omniauth(request.env["omniauth.auth"])
if user.persisted?
flash.notice = "Signed in Through Google!"
sign_in_and_redirect user
else
session["devise.user_attributes"] = user.attributes
flash.notice = "Please provide a password"
redirect_to new_user_registration_url
end
else
render :text => "Sorry this site is for company_name employees only"
end
end
end
migration for admin to user
class AddAdminToUser < ActiveRecord::Migration
def change
add_column :users, :admin, :boolean, :default => true
end
end
table for user roles
class CreateRoles < ActiveRecord::Migration
def change
create_table :roles do |t|
t.string :name
t.timestamps
end
end
end
HaveAndBelongToMany migration
class UsersHaveAndBelongToManyRoles < ActiveRecord::Migration
def self.up
create_table :roles_users, :id => false do |t|
t.references :role, :user
end
end
def self.down
drop_table :roles_users
end
end
First, I think you probably want to make new users default to NOT being admins, and only set that admin boolean to true if a current admin later makes them an admin.
To authenticate people, I suggest using the omniauth gem with one of the Google strategies. It will help validate their credentials against the user's Google account. Then you can store any information about that user relevant to your app, including whether they're an admin, in your own database, and use that information for authorization within your app. Hope that helps.

Adding additional field and validation to Devise view/model in Rails app

I generated the default devise views with:
rails generate devise:views
Then I added a username field to the views/devise/registrations/new.html.erb form.
Currently, only email and password validation occurs. How do I validate presence and uniqueness of the username field? Do I need to add something to the User model?
I used both the of the tutorials mentioned in the other answers, Railscast #210 and the Devise Wiki. However, so far as I could tell they do not explicitly say how to validate the presence and/or uniqueness of the username field.
If you added username with a simple migration -
rails generate migration addUsernameToUser username:string
Then devise doesn't do anything special with that field, so you need to add checks for validation and uniqueness yourself in the User model.
class User < ActiveRecord::Base
...
validates_presence_of :username
validates_uniqueness_of :username
However, If you look at the RailsCast #209 there is an example of the migration used to create the User model.
class DeviseCreateUsers < ActiveRecord::Migration
def self.up
create_table(:users) do |t|
t.database_authenticatable :null => false
# t.confirmable
t.recoverable
t.rememberable
t.trackable
# t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
t.timestamps
end
add_index :users, :email, :unique => true
# add_index :users, :confirmation_token, :unique => true
add_index :users, :reset_password_token, :unique => true
# add_index :users, :unlock_token, :unique => true
end
def self.down
drop_table :users
end
end
Notice here that the users email is defined as being unique. Perhaps if username was added using this same syntax then devise magic would take care of presence and uniqueness.
Rails 4 and Strong Parameters
On top of the above I had to generate the views with:
$ rails g devise:views
then in devise.rb add:
config.scoped_views = true
and finally configure the permitted parameters as below for sign_up as below:
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit :username, :email, :password, :password_confirmation
end
end
end
This is described in Devise Doc
Also, my validation for username is the following:
validates :username, presence: true
validates :username, uniqueness: true, if: -> { self.username.present? }
I use two lines, so if username is blank I get only one error.
If anybody is wondering how to get the login to check for username if its blank
or to make sure to users cannot have the same username. I spent quite a few
hours trying to figure this out and in the ned I only had to add :
validates_uniqueness_of :username, case_sensitive: false
validates_presence_of :username
to your user.rb file in app/models/
Here are the docs...
https://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html
This now throws the errors I need.
I feel like an idiot because I found uniquness_of first , then went back to and spent hours trying to figure out how to check for a blank field then found it is in the same documentation as the other...I am a noob.
Now onto figure out how to change the error messages since they are not in the devise.en.yml
Just add a username field to your User model and on the Devise wiki:
http://github.com/plataformatec/devise/wiki/Sign-in-using-login-or-mail
Hope it helps.

Resources