Rails Tutorial case sensitive not working - ruby-on-rails

I am following Rails tutorial and after signing up for my site, I am trying to sign in. I recently noticed in my app that if I capitalize my email address, I get the invalid username/password message. I tested the regex on Rubular and it works with capitalization so that can't be it.
Maybe this deals with sessions?
email_regex = /\A[\w+\-.]+#[csupomona\d\-.]+[edu]+\z/i
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
Here's the code for sessions/create
def create
user = User.authenticate(params[:session][:email],
params[:session][:password])
if user.nil?
flash.now[:error] = "Invalid email/password combination."
#title = "Sign in"
render 'new'
else
sign_in user
redirect_to root_path
end
end

This is nothing to do with validation.
It is to do with
How email addresses are stored in the database (assumedly some upper case, some lower case)
How the User.authenticate works (I assume it does a User.find_by_email)
Looking at the question, I've never actually had this be a problem.
But to solve it there are a couple of ways to go about this.
Store all emails lowercase, and make User.authenticate do the same
Ensure that User.authenticate is case insensitive.
But I've got a feeling that User.authenticate is coming from Devise or something similar. So 1. may be the best solution
class User
# all email writes get lowercased
def email=(value)
self[:email] = value && value.downcase
end
end
user = User.authenticate(params[:session][:email].try(:downcase), ...)

You're a little confused about what that regex is for. Let us have a look at this:
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
Where is the regex being used? It is being used for the :format so the regex is only used to see if an incoming email address looks like a valid email address and that has nothing to do with uniqueness. The :uniqueness parameter to validates specifies that case shouldn't be considered when ensuring that email addresses are unique. So you can't have two users whose email addresses differ only by case.
Nothing in the code you've shown talks about how email addresses are compared when you're trying to sign someone in and that's where you're have trouble. You'll have to update your User.authenticate class method to do a case insensitive search for the email address.

Related

Validating all attributes except one in Rails

I'm trying to do a custom validation in my model using valid? method. I need to run all validations of this model, except the password.
Something like this:
#resource = SalesPartner.new(permitted_params.merge(parent: current_sales_partner))
respond_to do |format|
if #resource.valid?(except: :password)
#resource.generate_authentication_token
SalesPartnerMailer.mail_new_sales_partner(#resource.email,
{ auth_token: #resource.authentication_token, id: #resource.id, level: #resource.level }
).deliver
flash[:success] = "#{#resource.level} criado com sucesso."
format.html { render "#{#path}/index" }
else
logger.log_and_alert_save_error(#resource, flash, "Ocorreu um erro ao salvar.")
format.html { render "#{#path}/new" }
end
end
Is that possible?
Thanks everyone!
Any way here is a way that you can do with the help of context. Say you have a User model and you want to validates some fields.
validates_presence_of :name,: email, on: :special_context
validates_presence_of :name,:email, :password
With the above 2 lines, you can now do like below
#user.valid?(:special_context)
The above will validates name and email fields. And if you write now,
#user.valid?
This will perform the presence validations on the name, email and password fields as you wrote.
Read valid?(context = nil) to understand the context.
Runs all the validations within the specified context. If the argument is false (default is nil), the context is set to :create if new_record? is true, and to :update if it is not.
Validations with no :on option will run no matter the context. Validations with some :on option will only run in the specified context.
Check this documentation also as an official example.
Context could really help you, but following maybe not.
validates_presence_of :name,: email, on: :special_context
validates_presence_of :name,:email, :password
This is because when you use validates_presence_of without specifying its context, it will be applied to all context(nil). Please see ref here So, maybe you could try as follow code:
validates_presence_of :name, :email, on: :special_context
validates_presence_of :name, :email, :password, on: [ :create, :update]
Just found one more mechanism to skip some validation on specified context, because specify all other context is not always suitable:
validates_presence_of :name, :email, on: :special_context
validates_presence_of :name, :email, :password, if: -> {Array(validation_context).exclude?(:special_context)}
note: validation_context can be array.

Rails Password Change

I'll start by telling you how I want my settings page set up.
I want users to be able to change their settings without requiring a password, and that's how it is set up now with this as the user model
validates :password, presence: true, length: { minimum: 6 }, :on => :create
validates :password_confirmation, presence: true, :on => :update, :unless => lambda{ |user| user.password.blank? }
This makes it so user's can change all of their settings without requiring a password (I know some might frown on this). But i want users to be able to change their passwords on the page like so...User clicks Change Password, a modal pops up, and users have to give their current password and then the new password and a confirmation of the new one. (I know how to do modal, i just want to know how do password reset).
Does this make sense?? I believe the way Pinterest does it is a good example (although they use Python I think)
My suggestion is to use a form object:
app/forms/change_password_form.rb
class ChangePasswordForm
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations
# Add all validations you need
validates_presence_of :old_password, :password, :password_confirmation
validates_confirmation_of :password
validate :verify_old_password
attr_accessor :old_password, :password, :password_confirmation
def initialize(user)
#user = user
end
def submit(params)
self.old_password = params[:old_pasword]
self.password = params[:password]
self.password_confirmation = params[:password_confirmation]
if valid?
#user.password = password
#user.password_confirmation = password_confirmation
#user.save!
true
else
false
end
end
def verify_old_password
self.errors << "Not valid" if #user.password != password
end
# This method is required
def persisted?
false
end
end
In controller initialize the form object #pass_form = ChangePasswordForm.new(current_user) and use the object in your modal: form_for #pass_form... and add the old_password, password and password_confirmation fields.
And finally, for example, in the update action:
#pass_form = ChangePasswordForm.new(current_user)
if #pass_form.submit(params[:change_password_form])
redirect_to some_path
else
render 'new'
end
I haven't tested this code, but you get the idea. Take a look to this Railscasts.

Rails 4.0 email addrese issues

Well I decided to try a different approach. Right now I have pages that are only accessible by number ids instead of usernames or emails. I would like it to be accessible by email addreses instead. I tried to override them but it failed in rails 4.0 and I tried the find_by_email command which also failed. This is the error message that I get: ActiveRecord::RecordNotFound in AccountsController#show.
The only method that did work is find(params[:id]) which only works for accounts that have id's attached them and fails completly if it is null.
Is there any other method to solve this?
Rails Controller
def show
#puts "****************************************"
#puts params
if #account.nil?
render "shared/404"
else
#if !current_account.nil?
respond_with #account
#else
# render "shared/403"
#end
end
def load_findaccount
#params[:id] remains fixed but find_by_id changes to username
#account = Account.find(params[:id])
#user_path(user)
Account.rb
class Account < ActiveRecord::Base
#def to_param # overridden
# email
#end
validates :first_name, :presence => true
validates :last_name, :presence => true
validates :email, :presence => true, :uniqueness =>{:case_sensitive => false}
end
You can use this Account.where(:email => "example#pop.com"). This will retrieve the records for that email id which I think will be at max one record in your code as email id is unique in your model.
I decided to resolve this on my own and use just Rails 3.2. So this will end it for this issue.

Rails, Alphanumeric validation in the controller

In my app I let users select a username, just like the twitter signup page: https://twitter.com/signup
When the user starts typing a username, I want in real-time to let the user know if the username is available & valid.
The regex I've been using to validate the username is alphanumeric is:
/^[a-z0-9]+[-a-z0-9]*[a-z0-9]+$/i
Given params[:username]
In the controller, how can I validate if the username is alphanumeric or not. Note, I'm not saving the record here just validation. so a model validation wouldn't work.
Ideas? Thanks
You'd still want to use model validations.
Something like this perhaps:
class User
validates :username, :format => { :with => /your regex/ }, :uniqueness => true
end
# then in some controller action or rack app
def test_username
user = User.new(:username => params[:username])
# Call user.valid? to trigger the validations, then test to see if there are
# any on username, which is all you're concerned about here.
#
# If there are errors, they'd be returned so you can use them in the view,
# if not, just return success or something.
#
if !user.valid? && user.errors[:username].any?
render :json => { :success => false, :errors => user.errors[:username] }
else
render :json => { :success => true }
end
end
r = /^[a-z0-9]+[-a-z0-9]*[a-z0-9]+$/i
unless your_string.match(r).nil?
# validation succeeded
end
I think your regex is a little overly verbose. I'd actually try the following regex for the alphanumeric validation:
/\A[A-Z0-9]+\z/i

validates_confirmation_of in Rails preventing me from saving a new object

In my User.rb model, I have this line:
validates_confirmation_of :password, :message => "Your passwords should match."
Then when the user signs up, the passwords match, everything is great... until I want to add more information to the user object, then save again. But running #user.save returns the error that my passwords don't match. In my signup controller method, I have these lines:
#user = User.new(params[:user])
if request.post?
if !#user.save
#errors = #user.errors
else
# crucial user details:
#user.salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
#user.password = encrypted_password(#user.password, #user.salt) #hash this
if !#user.save
puts "error for some reason in signup"
puts #user.errors.inspect
end
And upon inspection, #users.errors.inspect prints out: #["Your passwords should match."]}. They did, otherwise, it would never have passed the first .save call. Any advice on what I'm doing wrong here?
Thanks for your help.
This fixed it:
validates_confirmation_of :password, :on => :create, :message => "Your passwords should match."

Resources