validating password format in Authlogic - ruby-on-rails

Is there a way to get Authlogic to validate the format of a password, for instance must contain at least one letter and at least one number? The omission of a validates_format_of_password_options method to be used in the acts_as_authentic config block seems to indicate that Authlogic has the opinion that one should not be imposing such a constraint on one's users.
I thought I would simply put in a normal ActiveRecord validates_format_of :password, but this means that a current_user object I build is inherently invalid, as I can't retrieve the plaintext password (and wouldn't be storing it in that object even if I could!). Upon detecting that my current_user is invalid, Rails or Authlogic (not sure which, since I'm fairly new to both) directs me to my 'edit user' page with a validation error for its password.

requires no monkey-patching, but not tied to any future Authlogic changes. Just add this to your User model:
validates_format_of :password, :with => /^(?=.\d)(?=.([a-z]|[A-Z]))([\x20-\x7E]){6,40}$/, :if => :require_password?, :message => "must include one number, one letter and be between 6 and 40 characters"
Of course you can alter the regex to suite your needs.

You can use the configuration options given by acts_as_authentic like so:
# Configuration is easy:
#
# acts_as_authentic do |c|
# c.my_configuration_option = my_value
# end
#
# See the various sub modules for the configuration they provide.
If you go to the modules in the gem you can see additional options they provide. For example if I want to change the default options of the password's length validation:
acts_as_authentic do |c|
c.merge_validates_length_of_password_field_options({:minimum => 3})
end
You can look inside the acts_as_authentic folder in your "(gems || plugins)/authlogic/acts_as_authentic/" directory for more options. Cheers!

Related

Devise: Unable to limit model validation to specific def's

So I'm working on the registration aspect of the site currently. I have a main sign up which is just full name, email and password. (aka new.html.erb)
After you fill in that information I direct you to a new site (setup.html.erb) and ask for more info like city, country etc.
On that you also have the edit profile account.
I am trying to make my app more secure and adding restrictions and presence etc in the model. However how can I limit them.
Currently if I do
validates :email, presence: true,
and I go to a form that doesn't even contain the email for nor permits it I get an error up that I need to add an email.
Also how do I fix this: I make presence true, I input require in html5. But still if I go to my source code and just remove the form and push submit it saves and I can bypass adding info.
Currently if I do validates :email, presence: true,
and I go to a form that doesn't even contain the email for nor permits it I get an error up that I need to add an email.
Fix:
what you need is a conditional validation. If we look at rail guides it says
Sometimes it will make sense to validate an object only when a given predicate is satisfied. You can do that by using the :if and :unless options, which can take a symbol, a string, a Proc or an Array.
So in your model you could do something like:
class Order < ActiveRecord::Base
validates :email, presence: true, if: :need_to_validate?
def need_to_validate?
#your condition to check whether you want email validation or not
end
end
Update:
You can use params[:action] and params[:controller] smartly to check in which action and controller(hence which view) you currently are in so your method would be:
def need_to_validate?
params[:action] == your_view_action && params[:controller] == your_controller_name #your condition to check whether you want email validation or not
end

Is there way to validate emails on signup based on the domain in Rails?

Example:
Accepted extensions: "#blogsllc.org"
A user signs up with the email "joe#blogsllc.org" would be able to create an account.
Wondering what would be the best way to do this in Rails and how others would approach this? I imagined trying to check the format of the email address against a bunch of regular expressions but this could be tedious as the list of supported extensions grow.
The other way to do this would be to have a database of the supported extensions and check the created email address against the database to see if the extension is accepted but I'm not sure what would be the best way to implement this in Rails.
I'm looking to implement something similar to what Facebook did in it's early days.
Any help appreciated.
EDIT for misunderstanding:
If you don't need anything more fancy than a straight-up match of the domain (files have extensions, emails have domains), just splitting on # and matching the second part with a database column is the easiest way.
You can add the following code
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
record.errors[attribute] << (options[:message] || "is not an email")
end
end
end
class Person < ActiveRecord::Base
validates :email, :presence => true, :email => true
end
This Link will be useful

Validation for a certain action in ruby on rails

In my current ROR project I am using devise pluing for validation. In my change password form validation, I am using the following code in the user model
validates_presence_of :password, :password_confirmation
But I wants to validate is only for an action. I have a function in my user controller named update_password. I found the that I can assign the action as follows:
validates_presence_of :password, :password_confirmation, :on => :update_password
But its not working. Even if the password and password confirmation fields are empty, the form is submitted. Can anyone help me to solve how to set the validation only for a particular action. Will be a great help
Thanks a lot
You can use :validatable option implemented in devise.
Just add to your model
devise :validatable
And set validation options in your config/initializers/devise.rb file
# ==> Configuration for :validatable
# Range for password length. Default is 6..128.
config.password_length = 6..128
# Email regex used to validate email formats. It simply asserts that
# an one (and only one) # exists in the given string. This is mainly
# to give user feedback and not to assert the e-mail validity.
config.email_regexp = /\A[^#]+#[^#]+\z/
Another way is to use your own regexp validations. You can add to your model
validates :password, :format => { :with => /\A[a-zA-Z]+\z/, :message => "Only letters allowed" }
After that you can call #user.valid? in your controller to check that your user instance is correct.
There are many different ways to validate your model.
You can read more about validation and ActiveRecord callbacks in guides: http://guides.rubyonrails.org/active_record_validations_callbacks.html
If you're using devise, there's no need to check for that. It's handle for you by default.

How can I put a conditional validation on an ActiveModel attribute that has several validations already?

I'm using Authlogic which by default puts a few validations(length, uniqueness, format, etc) on fields like login, email, and password.
I'd like to be able to skip all validations attached to one of the attributes if, say, another attribute is present.
Is this possible? Something like:
validate :email, :unless => :has_openid?
which will then skip the format, length, and uniqueness validations just on the email attribute.
I'm working with a Rails 3.1.x app and authlogic 3.1.0
Update: I was trying to follow this article, but I couldn't get it to work properly:
http://erikonrails.snowedin.net/?p=242
The way I've done this with authlogic is by passing a block to acts_as_authentic:
acts_as_authentic do |config|
with_options :unless => :has_openid? do
config.merge_validates_format_of_email_field_options
config.merge_validates_length_of_email_field_options
config.merge_validates_uniqueness_of_email_field_options
end
end
I've written a workaround and abstracted it out into a gem:
https://github.com/synth/conditional_attribute_validator
Gemfile:
gem 'conditional_attribute_validator', :git => "git://github.com/synth/conditional_attribute_validator.git"
Example:
class User
include ConditionalAttributeValidator
validate_attributes_with_condition :login, :password, :password_confirmation, :unless => :has_another_form_of_authentication?
end
Source:
def validate_attributes_with_condition(*args)
opts = args.extract_options!
raise "Must have an :if or :unless option" unless opts.has_key?(:if) or opts.has_key?(:unless)
merge_methods = self.methods.grep(/merge_.*_options/)
args.each do |field|
merge_methods.grep(/#{Regexp.quote(field)}/).each do |m|
self.send(m, opts)
end
end
end
Rails automagically creates the merge_attr_options methods based upon whatever validations have been specified in order to merge options into an existing validation. So I lookup these methods and iterate over them and check if that method applies to a particular field. If so, I call the merge_attr_options method and pass in the options.
I'm not too concerned about performance since this is just performed on initialization.

Add a subdomain condition to password reset query in Devise with Rails3?

I've setup Devise (on Rails 3) to use Basecamp-style subdomain authentication. Under this model, a user could be registered twice under different subdomains with the same email address.
For example:
class User < ActiveRecord::Base
belongs_to :account
end
class Account < ActiveRecord::Base
# subdomain attribute stored here
end
User 1 registered on company1.myapp.com with email address bob#acme.com
User 2 registered on company2.myapp.com with email address bob#acme.com
(Both user account are controlled by the same human, but belong to different subdomains.)
Logging in works fine, but the standard Password Reset only looks up by email address, so you can only ever reset the password for User 1. What I'd like to do is take into account the request subdomain, so a password reset from company2.myapp.com/password/new would reset the password for User 2.
The Devise looks up the user using a find_first method, which I don't think accepts joins, so I can't include a :account => {:subodmain => 'comapny2'} condition.
I can reimplement send_reset_password_instructions to manually look up the user record, but it feels hacky and I'll need to do it for send_confirmation_instructions, too.
Is there a better way?
It looks like this may be configurable with devise_for in the routes file.
From my reading of the source (and I haven't actually tried this), you can add a reset_password_keys option. These should include the subdomain. This is passed to find_or_initialize_with_errors from send_reset_password_instructions in lib/devise/models/recoverable.rb. In find_or_initialize_with_errors it's only these keys which are used to find the resource.
You'll probably also want to override Devise::PasswordsController#new template to include the user's subdomain when they submit the reset password request.
UPDATE: to address the fact that the subdomain is stored on Account and User belongs_to :account you can probably use Rails' delegate method.
We experienced this same issue. Mike Mazur's answer worked, but for one difference:
We put :reset_password_keys => [:email, :subdomain] in the call to the devise method in our Users model.
I recently implement this behaviour in a Rails 4 App.
…/config/initializers/devise.rb
(…)
# ==> Configuration for :recoverable
#
# Defines which key will be used when recovering the password for an account
config.reset_password_keys = [:email, :subdomain]
(…)
…/app/views/devise/passwords/new.html.erb
(…)
<%= f.input :subdomain, required: true %>
(…)
…/app/controllers/users/passwords_controller.rb
class Users::PasswordsController < Devise::PasswordsController
def resource_params
params.require(:user).permit(:email, :subdomain, ...)
end
private :resource_params
end

Resources