I have an age check for my users in which if they want to sign up for my app, they have to be a certain age. I am using the devise gem, but created a method in my user model to check the age....I get an error stating that whatever I want to do they can't due to a nil class. Basically i have a user, but the birth_date on the user is not saving.
Which tells me that where I am putting this logic is in the wrong place. However I'm not sure where. I have a registration controller, and a user controller. I also have user model. I don't have a registration model, i'm wondering if either my method needs to be in a different model that I don't have? Or if i'm building it incorrectly.
My user model
class User < ActiveRecord::Base
before_create :age_restriction
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
def age_restriction
if (self.birth_date&.to_date + 18.years) < Date.today # assuming dob format is mm/dd/yy
errors.add :birth_date, 'must be older than 18'
end
end
end
My registration model
Cass RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: :create
before_action :configure_account_update_params, only: :update
protected
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:bith_date, :first_name, :last_name])
binding.pry
end
def configure_account_update_params
devise_parameter_sanitizer.permit(:account_update, keys: [:birth_date, :first_name, :last_name])
end
end
The breakpoint I have in there, when I type in devise_parameter_sanitizer I get
#permitted=
{:sign_in=>[:email, :password, :remember_me],
:sign_up=>
[:email, :password, :password_confirmation, :bith_date, :first_name, :last_name],
:account_update=>[:email, :password, :password_confirmation, :current_password]},
#resource_name=:user>
Typo. It's currently, :bith_date. Fix that to birth_date and the model should be able to read the proper attribute.
It was nil, since you're checking for self.birth_date, while the param you permitted is :bith_date
Allow :birth_date in the sign_up_params.
Related
I am trying to add multiple user role functionality in devise. I am using enum for different roles, but somehow user role always remains nil after a new user signs up.
here is my implementation
user model
class User < ApplicationRecord
rolify
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
enum role: { student: 0, assistant: 1, teacher: 2}
end
I also added role in strong params of registration controller
registration_controller
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:username, :email, :password, :password_confirmation, keys: [:role])
end
def account_update_params
params.require(:user).permit(:username, :email, :password, :password_confirmation, :current_password, keys: [:role])
end
end
view
<%= f.select :role, User.roles %>
What I want is that role of new user should be whatever he/she selects from dropdown while registering
But its role is always set to nil after registering. Can someone please explain how to fix this
I have read many answers and added key: [:role] in strong params but still its not working
Thanks
If you intend on using Rolify you should remove that enum column.
class User < ApplicationRecord
rolify
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
end
Rolify uses two tables (roles and users_roles) to store the roles of a user. This allows a user to have many roles while a role can have many users.
While you can create your own primitive role system based on an enum column having both in tandem will certainly confusion as Rolify's methods such as .has_role? will not take your enum column into account.
If you want to let users select roles with rolify you would do:
<%= f.collection_select :role_ids,
Role.where(name: ['student', 'assistant', 'teacher']), :id, :name %>
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:username, :email, :password, :password_confirmation, role_ids: [])
end
def account_update_params
params.require(:user).permit(:username, :email, :password, :password_confirmation, :current_password, role_ids: [])
end
end
Everything was set up fine and seemed to be working. Suddenly I have an issue where if I log out and then log back in again with a different username it just logs me back in always as the first user.
Example:
user one - first#domain.com / password1
user two - second#domain.com / password2
Even if I log out and then log back in again as user two (verified as signed up correctly) it will log me in as user one.
Here is my user.rb file
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
acts_as_voter
has_many :links
has_many :comments
# Virtual attribute for authenticating by either username or email
# This is in addition to a real persisted field like 'username'
attr_accessor :login
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions.to_h).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
elsif conditions.has_key?(:username) || conditions.has_key?(:email)
where(conditions.to_h).first
end
conditions[:email].downcase! if conditions[:email]
where(conditions.to_h).first
end
validates :username, presence: :true, uniqueness: { case_sensitive: false }
validates_format_of :username, with: /^[a-zA-Z0-9_\.]*$/, :multiline => true
validate :validate_username
def validate_username
if User.where(email: username).exists?
errors.add(:username, :invalid)
end
end
end
Application Controller
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
added_attrs = [:username, :email, :password, :password_confirmation, :remember_me]
devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
devise_parameter_sanitizer.permit :account_update, keys: added_attrs
end
end
You might want to check your controllers. If you're determining the logged in user by using anything other than current_user, you may have used the wrong query or perhaps were using a specific user for testing purposes.
Check your User model. You're using :rememberable and might be passing a session cookie without realizing.
I am new to Rails and I've started building an authentication feature in a sample rails app using "Devise" gem.
I've added a migration to add a new column named username in my devise model named User.
I've also added some validations regarding the username column that I had created, so my user.rb looks like this:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable
validates_presence_of :username
validates_uniqueness_of :username
validates_length_of :username, :minimum => 5, :maximum => 10
end
Now every time during sign up of a new user, I get the validations for username even though it shouldn't.
For example, it tells me username shouldn't be blank even though username is filled.
Username should be minimum 5 characters, even though it is.
What am I doing wrong?
In the console, I can see the username being passed in the params during form submit and also : Unpermitted parameter :username.
Secondly, I want to create multiple signups using same email address but different username.
How can I do that?
I'm using ruby 2.4.1 and rails 5.1.4. Thanks.
You have to do at least four things to get this to work:
1. Setup the proper validations
Since you are not using the authenticable module you should make sure you validate the user properly:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable
validates_presence_of :email # optional
validates_presence_of :username # required
validates_uniqueness_of :username # required
validates_presence_of :password, if: :password_required? # recommended
validates_confirmation_of :password, if: :password_required? # recommended
validates_length_of :password, within: password_length, allow_blank: true # recommended
end
2. Configure devise to use :username instead of :email as the authentication column:
# config/initializers/devise.rb
# ...
config.authentication_keys = [ :username ]
config.reset_password_keys = [ :username ]
config.confirmation_keys = [ :username ]
You might want to search config/initializers/devise.rb for :email to find additional options.
3. Remove the database uniqueness constraint for email:
Generate a new migration and place this in the change block:
remove_index "users", name: "index_users_on_email"
add_index "users", "email", unique: false
If you have not already make sure you have a unique index on users.username.
4. Whitelist the params.
Params whitelisting in Devise is a bit more complicated than for your average rails resource due to the amount of configurability.
You need to whitelist the username param both for sign_up and sign_in:
class ApplicationController < ActionController::Base
# ...
before_action :configure_devise_parameters, if: :devise_controller?
# ...
private
def configure_devise_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
devise_parameter_sanitizer.permit(:sign_in, keys: [:username], except: [:email])
end
end
The best refence is by reading the source which is very well commented.
You need to permit username in strong parameters.
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
end
end
Please follow https://github.com/plataformatec/devise#strong-parameters
For youre second question :
you need to overwrite devise validation for Email
https://github.com/plataformatec/devise/wiki/How-to:-Use-a-custom-email-validator-with-Devise Will help you,
Follow Skip email validation in Devise
I'm trying to set up an age restriction when a user registers so that if they are too young they cannot register on an app i'm building.
I had to over-ride devise to allow me to pass through other values to the user (like :birth_date). However I also want to check the age of the user so that if they are too young, they cannot use the app.
What I have right here, in a rudimentary way it works, but it is not quite what I would like.
<%= f.input :birth_date, required: true, start_year:1999 %>
In my user model I created some methods that address the problem, however ultimately my problem is that none of this code is getting hit during the registration process, and that is what I need some help with. If someone could take a look at point me in the right direction, I would greatly appreciate it!
class User < ApplicationRecord
validate :age_restriction
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :cafes
def age_restriction
if (birth_date.to_date + 18.years) < Date.today # assuming dob format is mm/dd/yy
errors.add :birth_date, 'must be older than 18'
end
end
end
The controller I used to over-ride devise I called registration_controller and it is like so
class RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: :create
before_action :configure_account_update_params, only: :update
protected
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:birth_date])
end
def configure_account_update_params
devise_parameter_sanitizer.permit(:account_update, keys: [:bith_date])
end
end
My initial controller was my user_controller. Initially I was hoping this would solve my issue, but after some more work realized I needed to over-ride devise (hence the other registrations_controller). I'll admit this may be what is causing me my issue, not sure though.
class UsersController < ActiveRecord::Base
def show
#user = User.find(params[:id])
end
def create
#user = current_user.build(user_params)
#user.save
end
private
def user_params
params.require(:user).permit(:birth_date)
end
end
Use validations.
There is a gem which adds some useful date validators:
https://github.com/adzap/validates_timeliness/
validates_date :date_of_birth, :before => lambda { 18.years.ago },
:before_message => "must be at least 18 years old"
You can use model validations to prevent a user instance from being created if the user does not meet the age restriction you have set:
User.rb
validate :age_restriction
def age_restriction
if (birth_date.to_date + 18.years) < Date.today # assuming dob format is mm/dd/yy
errors.add :birth_date, 'must be older than 18'
end
end
I'm working on creating an application with role based authorization.So,In i have created a migration to devise users to add a new column "role"
And I have the following code block in my applications controller to permit the new parameter(role).But still when i try to sign up as a new user.I get the error that the parameter role is unpermitted.Please help me to solve this issue.
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit( :email, :password, :password_confirmation, roles: [] ) }
end
end
This is what i've got in my user model
class User < ApplicationRecord
belongs_to :role
# has_many :Product
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
ROLES = %i[admin manager customer]
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation, :role)
end
end
migration is as follows
class AddRoleToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :role, :string
end
end
Please help me to solve this issue.Thank you.
Your user model doesn't have access to params, so you can remove the user_params method from there. Unless you're nesting attributes, you won't need to pass in the array for the role attribute, so change
devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit( :email, :password, :password_confirmation, roles: [] ) }
to
devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit( :email, :password, :password_confirmation, :role ) }
#
And you should be good to go.