I have the model Agency based on Devise:
class Agency < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :name, :email, :phone, :address, :city, :state, :zip,
:notes, :is_admin, :password, :password_confirmation, :remember_me
protected
def password_required?
!persisted? || password.present? || password_confirmation.present?
end
end
Also I have the AgenciesController based on active_scaffold:
class Admin::AgenciesController < Admin::BaseController
before_filter :authorize_admin!
active_scaffold :agency do |conf|
actions.exclude :show
create.link.page = true
update.link.page = true
list.columns = [
:name, :email, :phone, :address, :city,
:state, :zip, :notes, :events, :is_admin
]
create.columns = [
:name, :email, :phone, :address, :city, :state, :zip,
:is_admin, :password, :password_confirmation
]
update.columns = [
:name, :email, :phone, :address, :city, :state, :zip,
:is_admin, :password, :password_confirmation
]
columns.add :password
columns.add :password_confirmation
columns[:password].form_ui = :password
columns[:password_confirmation].form_ui = :password
end
end
Then here is Agency update form:
I would like to provide an opportunity for user to omit filling in of password and password_confirmation fields. But if user fills in password field the password_confirmation field have to be required.
I almost solved my problem by password_required? method. But javascript required verification on client doesn't allow me solve my problem completely.
How Can I remove JS varification from client for password and password_confirmation fields?
Try:
validates_confirmation_of :password, :if => :password_required?
validates :password_confirmation, :presence => true, :if => '!password.nil?'
Note that the validation is only triggered if password_required? returns true, and password_required? will return false if the password_confirmation field is nil.
So in order to make password_confirmation field to be nil, you simply need to remove the password_confirmation field from the form and that way you will always get it nil thus bypassing the validations.
Alternate Solutions:
1) Skip validation of password field
2) Just save a random secure generated number in the password field ( Better because it's easy and also maintain the consistency ).
self.password = self.password_confirmation = SecureRandom.urlsafe_base64(n=6)
Also if you want that such fields should be identified differently as been left by the user then you can give unique passwords to them so later you impose the condition like:
if(self.password == "something unique" and self.password_confirmation == "something unique")
flash[:notice] = "The user has not password"
end
Then on UI level, you simply display with blank using the above condition.
#Saurabh Jain, thanks a lot for your advices.
But solution was so much simple.
I have found out that active_scaffold adds an required attribute for input tag of password field.
By another words a client gets an html
<input type="password" required="required" size="30" name="record[password_confirmation]" id="record_password_confirmation_4" class="password_confirmation-input text-input" autocomplete="off">
Exactly required attribute was my problem :) To remove it from html simply add line
columns[:password].required = false;
to active_scaffold configuration in Admin::AgenciesController (see it above)
Related
Hi I have a spree model that has the following validations:
with_options presence: true do
validates :firstname, :lastname, :address1, :city, :country
validates :zipcode, if: :require_zipcode?
validates :phone, if: :require_phone?
end
I would like to remove the city and/or country from presence validation. In my address_decorator i wrote this
Spree::Address.class_eval do
with_options presence: true do
validates :firstname, :lastname, :address1
validates :zipcode, if: :require_zipcode?
validates :phone, if: :require_phone?
end
......
But this didnt remove city or country. Both are still demanded in order to create new record.
What am i missing? Please help.
When you add "with_options" you are not removing the previous validations, you are just adding more.
So, there is to remove the validations for :city and :country
Not checked myself, but I´ve seen something similar to:
.class_eval do
_validators.reject{ |key, _| key == :field }
_validate_callbacks.reject do |callback|
callback.raw_filter.attributes == [:field]
end
where :field is :city and :country
I experiencing an issue on the update of a polymorphic association.
Actually, I've several type of users such as Admin, Customer, etc...
But on the update of a customer (for example), it fails because devise ask for a password.
I've the User model which only have devise logic:
class User < ActiveRecord::Base
devise :database_authenticatable,
:registerable,
:recoverable,
:rememberable,
:trackable,
:validatable
belongs_to :role, polymorphic: true
end
customer.rb:
class Customer < ActiveRecord::Base
has_one :user, as: :role, dependent: :destroy
end
And on the controller side, customers_controller.rb:
def update
if #customer.update customer_params
redirect_to dashboard_path, flash: { success: t('validation.update', model: #customer.class.model_name.human.downcase) }
else
render 'edit'
end
end
private
def customer_params
params.require(:customer).permit(:firstname, :lastname, user_attributes: [:email, :password, :password_confirmation])
end
Here is my form view:
= simple_form_for #customer do |f|
.form-inputs
= f.fields_for :user do |u|
= u.input :email, required: true, autofocus: true
= u.input :password, autocomplete: 'off', hint: t('devise.registrations.edit.leave_blank_if_you_don_t_want_to_change_it'), required: false
= u.input :password_confirmation, required: false
= u.input :current_password, hint: t('devise.registrations.edit.we_need_your_current_password_to_confirm_your_changes'), required: true
= f.input :firstname
= f.input :lastname
I see that in the form you have added required: false for password and password_confirmation field.
The required attribute is a boolean attribute. When present, it
specifies that an input field must be filled out before submitting the
form.
BUT that is not going to restrict Devise from asking for password. By default, in Devise its mandatory which will performed every time you update a record.
If you want to update the record without providing password then follow the guidelines mentioned in Devise How To: Allow users to edit their account without providing a password
I have the following devise model (edited for brevity)
class Student < ActiveRecord::Base
devise :database_authenticatable, :token_authenticatable,
:recoverable, :rememberable, :trackable,
:authentication_keys => [:login], :reset_password_keys => [ :login ]
attr_accessor :login
attr_accessible :name, :email, :password, :password_confirmation, :login
validates :name, :presence => true
validates :email, :presence => true
validates_uniqueness_of :email, :case_sensitive => false, :allow_blank => true, :if => :email_changed?, :scope => :id
validates_format_of :email, :with => Devise.email_regexp, :allow_blank => true, :if => :email_changed?
validates_presence_of :password, :on=>:create
validates_confirmation_of :password, :on=>:create
validates_length_of :password, :within => Devise.password_length, :allow_blank => true
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(["name = :value OR lower(email) = :value", { :value => login.downcase }]).first
else
where(conditions).first
end
end
def email_required?
false
end
def email_changed?
false
end
end
And I have followed the guide on this link to enable signin with either name or email.
Here's the problem:
Students with names > 2 words cant sign in, e.g. "Adam Bravo Charlie"
Single names e.g "Adam" or names with <= 2 words e.g "Adam Bravo" can be signed in.
The school requires students to use their full names with accompanying spaces to login. How do I enable my students to sign in with their full names and whitespaces?
On the login form, I would take a string and convert it to a slug. Authenticate with the slug as the username. When creating a new user, use the before_create method and parameterize the full name. This would allow you to have an unlimited number of spaces, including punctuation characters (periods and commas). This would give the feel of the user entering their full name as their username when in turn, it's going to parameterize the user's full name and use this as the username to login.
Ok turns out the solution is simpler than i thought.
config/initializers/devise.rb
config.case_insensitive_keys = [ :name]
config.strip_whitespace_keys = [ :name ]
and voila, login with full name is now possible!
I'm trying to set up my application to use Sorcery. When I add authenticates_with_sorcery! to my user model, my specs start to run really slow (about one per second). Is there some kind of configuration or set up that could cause this with Sorcery?
Here's my user model:
# This model represents a user of the application, disregarding that person's use of the system. For
# instance, a user could be a job hunter, an employer, an administrator, or some other stakeholder.
class User < ActiveRecord::Base
authenticates_with_sorcery!
attr_accessible :email, :password, :password_confirmation
# validations
validates :email,
:presence => true,
:uniqueness => true,
:format => /[^#]+#[^#]+\.[^#]+/
validates :password, :presence => true, :confirmation => true
validates :password_confirmation, :presence => true
# before filters
before_save :sanitize_email
private
# Strips and removes HTML tags from the email parameter.
def sanitize_email
self.email = email.strip
# remove anything that looks like an email
self.email = email.gsub(/<[^<>]+>/, "")
end
end
and my user factory:
require 'factory_girl'
require 'ffaker'
FactoryGirl.define do
sequence :email do |n|
"email#{n}#example.com"
end
factory :user do |f|
email
password "password"
password_confirmation "password"
end
end
My first guess is slow password encryption. For instance in devise we have config.stretches configuration variable which in the test env could be set to a small number.
check What does the "stretches" of database_authenticatable of devise mean?
FINAL SOLUTION:
I have a Rails 3 app that uses Devise to handle authentication. In the signup form i have the following fields:
<p><%= f.label :first_name %><br />
<%= f.text_field :first_name %></p>
<p><%= f.label :last_name %><br />
<%= f.text_field :last_name %></p>
I need to capitalize first and last names and combine them in the User model in a database field called 'login' (e.g. Lastname, Firstname). Here is the complete user model:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation, :remember_me, :login
validates :first_name, :last_name, :email, :password, :password_confirmation, :presence => true
before_create :create_login
def create_login
self.login = "#{last_name.capitalize}, #{first_name.capitalize}"
end
end
Thanks.
I genuinely, honestly, and truly applaud your use of the power of Ruby, but since this is such a straightforward and static concatenation of two strings, I'd go with:
def create_login
login = "#{last_name.capitalize}, #{first_name.capitalize}"
end
As for the nil:NilClass issue, are you adding first_name and last_name columns to your users table in your associated migration?
before_create :create_login
validates :first_name, :presence => true
validates :last_name, :presence => true
def create_login
login = [last_name, first_name].map(&:capitalize).join(", ")
end
Short explanation
I think it is good to get first_name and last_name on registration: so we will ad validation to it. Also it is good idea to validate length and match it with some regexp.
Then, as far as login is creates only once, we will add before_create callback, which will be executed only when object is creating (not updating). before_create callback will be run only if validation is passed, so if first_name or last_name is blank - validation won't be passed and callback won't be executed till first_name and last_name is filled.
UPD
Ok, as far as you get your error:
def create_login
login = [last_name, first_name].compact.map(&:capitalize).join(", ")
end