I'm using devise and cancan as an authentication solution.
For devise I have added a role attribute, and created a constant ROLES:
#Migration for adding roles
class AddRoleToUsers < ActiveRecord::Migration
def change
add_column :users, :role, :string
end
end
#Users.rb
ROLES = %w[user staff]
I want to add a function to the signup page, such that for a person to create a user with the role "staff" he has to enter a secret key as well (probably like a secret code like "staffsecretkey" in a input text box)
Anyone know of a way?
Thanks in advance.
You'll have to do two things:
1) Override devise controllers
2) Customise your views
Check devise wiki in github. You should be able to find all the info you need right there. I'm answering you from my BlackBerry so I could no give you more details right now. But if you can't solve this with the answer I gave you. I'll give you a hand later.
Related
My app has 3 roles for users: member, handicapper, admin
I'm trying to set the role by the route, example:
get '/members/sign_up' => 'devise/registrations#create', :role => 'member'
Then in my controller, which I use to override devise, I do something like this:
def create
super do
resource.role = params[:role]
resource.save
end
end
Please give some direction as to what I'm doing wrong, or what I else I need to be doing.
Also, I currently don't have a way of checking whether that parameter is even being passed to the action, so if you could suggest ways to do that, it would be greatly appreciated.
Note: I have gone through several tutorials and documentation pages, as well as dozens of SO questions, but have yet to find anything this specific.
Thanks in advance.
EDIT: I should add I have already added the field to the migration file, and ran rake db:migrate.
EDIT 2: User.last in rails console shows role: nil
For the role column in the users table I would suggest using enum.
add_column :users, :role, :integer, default: 0
Then in your user model add:
enum role: {member: 0, handicapper:1, admin: 2}
Now by default a user will always have a role of member. Don't set a users role via a route - that sounds like a security hole.
If your letting users self register, let them do that and they will be automatically set to member, and then in an admin area you can set their role to something else if need be.
I am creating a rails employee dashboard app where I am able to view a list of employees. For this application, I am the only user that should be able to view the administrative dashboard page. I've implemented my admin functionality by using the nifty administrate gem. An example app that showcases the dashboard can be found by viewing clicking this url Administrate example. My dashboard is identical and is nothing special. However, I will run into the occasion where I need to create other users/amins (Human Resources) to log in and to be able to edit, remove employee listings.
For authentication, I am using the awesome devise gem and am successfully able to login, signup, signout, etc. Here is the catch though. I need to be able to create new users through the administrate dashboard. I have the dashboard set up to display the user fields but I am currently unable to create a user. Here is a picture of my user dashboard for reference
The problem I am facing is that when I enter a password for Encrypted password I am unable to do so because of the Password can't be blank validation.
Viewing my logs, I am able to see that when I go to devise's signup page, it goes to a Devise::RegistrationsController while creation of my User with the administrate gem goes through Admin::UsersController. Surely, someone in the community has used a combination of creating users through an admin dashboard with devise. Does anyone have any recommendations of how to customize this functionality?
This seems like a problem with strong params. You have to sanitize those parameters. Cleanest solution, at least for me, is to override the RegistrationsController like so:
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation) # list every parameter you'd like to register with
end
end
and map this controller in routes.rb like so:
devise_for :users, :controllers => { registrations: 'registrations' }
You can get inspired in this article.
Also I've noticed that you are trying to manipulate with encrypted_password field. That's not a good idea. Devise will handle that for you. You can render the input for password instead (that might as well be the issue all along).
The parameters seems to be the issue. You are trying to set protected parameters. Try sending only the following parameters.
[:name, :email, :password, :password_confirmation, :mobile ]
Make sure you have permitted above parameters in Admin::UsersController
After adding the user you have to confirm the user, if you have :confirmable in your user model. You can do so in Admin::UsersController after creation of user object.
user.confirm
I'm looking for a solution to allow a user on my app to have more than 1 email. This should work similar to Facebook, LinkedIn and Quora. Where an account can have multiple emails, 1 as the primary.
Is there a turn-key solution for devise avaialble? I'm hoping to not have to write this from scratch given it's so common.
Ideas? Thanks
Hm...I'll suggest to create new model, You'll do something like this:
For example model would beUserEmail.
class UserEmail < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :user_emails
end
and override devise's method to find record in User model:
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if email = conditions.delete(:email)
User.includes(:user_emails).where('user_emails.email = ?', email).first
else
super(warden_conditions)
end
Read more about override here: https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address
Bob's answer is close but it has a potentially dangerous bug. The find_first_by_auth_conditions method should look like this:
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if email = conditions.delete(:email)
User.includes(:user_emails).where('user_emails.email = ?', email).first
else
super(warden_conditions)
end
end
The email check and call to super is important, because Devise also uses this method to look up Users by confirmation_token, unlock_token, and reset_token. Without the else branch, any calls to this method that don't have an email parameter will either fail, or load up a User with a nil email.
I would suggest you to create a new model SecondaryEmail.
A User can has_many :secondary_emails, and each SecondaryEmail belongs_to :user.
You will have to add the validation of uniqueness for each email in SecondaryEmail, and further, will have to make sure that no new SecondaryEmail is already a primary email of any User.
Provide the interface, so that a User can add his secondary_emails, with those validations.
Next step will be overriding the SessionController of Devise.
Upon any login procedure, set up your login procedure for SecondaryEmail.where(:email => params[:email]) whenever an email is not found in User's primary emails. If it exists, authenticate with that user's password, else, user doesn't exist.
This is what I came up with so far. I would really love to know the experts' view and approach in this. :)
I came across this problem awhile ago - and have outlined the solution in my blog .
The steps are summarized below:
Email information has to be stored in a additional model, say Email. So a User has many related Email instances.
We would most likely want to designate one email as the default email which we can use for communication with the user.
The class method of the User class find_first_by_auth_conditions is used to find the user for provided credentials - so we will have to override that method to search using the Email model.
We will have to change the default views because they implicitly assume the presence of email method of user. Rather than rewriting the views entirely we can use add a proxy accessor for email that delegates to the default email for the user.
If a user is allowed to have multiple emails - we would also like to provide the user facility to add/remove emails in the account edit page.
If you need omniauth integration - then the stock implementation of User.from_omniauth outlined in the devise wiki will have to be modified to support multiple emails.
My implementation is available on Github.
The answers given here is pretty good, and should solve your problem. To answer your last question, i don't think you will find a gem for this, as it's too simple even though it's pretty common. Just make it from scratch as suggested, it should not be to much work :)
Bob's answer threw a SQL error for me in rails 4.1.5- the below change got it working, per http://guides.rubyonrails.org/active_record_querying.html#specifying-conditions-on-eager-loaded-associations:
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if email = conditions.delete(:email)
User.includes(:user_emails).where(user_emails: {email: email}).first
else
super(warden_conditions)
end
end
You can use the devise-multi_email gem: https://github.com/allenwq/devise-multi_email
Replace devise :authenticatable with devise :multi_email_authenticatable, so that your models might look like:
class User < ActiveRecord::Base
has_many :emails
# Replace :database_authenticatable, with :multi_email_authenticatable
devise :multi_email_authenticatable, :registerable
end
class Email < ActiveRecord::Base
belongs_to :user
end
And if you want all the emails to be confirmable and recover your password from anyone of your emails, just
devise :multi_email_authenticatable, :multi_email_confirmable, :confirmable
I am creating a website in Ruby and I would like to have the option to sign up as an admin or a user. I have created the sign up system using devise and I would like to be able to give different permissions to different users, i.e Admins and Users. Thanks guys.
There's a comprehensive guide here.
Here's a post about using Devise and CanCan to accomplish what you are looking for.
You can add boolean fields admin and users into your User model. So while creating you can assign admin or user role.
This question is answered here:
how to define user roles
you can use devise + cancan and define roles like user and admin to separate common user and application admin.
class User < AB
has_many :roles
def is_admin?
roles.include?(:admin)
end
end
class Role < AB
end
and then check it in cancan's definition file like this
can :update, Model do |model|
user.admin?
end
this video give you detail about it http://railscasts.com/episodes/192-authorization-with-cancan
While trying to add roles-based authentication (using CanCan and Devise) to my project I found that there are two ways to save roles: the first one is "Has and Belongs_to" way and the second one is just saving role in new field in users table.
So, the question is, how can I define deafult user role in the first way and which way should I choose to define deafult role in the second one (setting default role in migration or editing Devise's user controller?)
Also, should I use this method or is it better to use gem instead?
P.S. I've already read Tony Amoyal's tutorial but didn't found an answer there.
If I understood the question correctly, here is what worked for me: Ruby on rails, cancan and default role assignment
Simply add the following into /models/user.rb to assign default role on signup:
after_create :default_role
private
def default_role
self.roles << Role.where(:name => 'User').first
end
This situation described in Rails AntiPatterns book: http://railsantipatterns.com/
Short answer is: use field in users table, set default role using migrations. This way is much simpler. You should not use complex solution just because it can possibly better suit your future needs.
You can do the following in user.rb:
after_initialize :set_default_role
private
def set_default_role
self.role ||= :user
end
A very easy users role solution can be implemented using this gem: https://github.com/platform45/easy_roles