validates_acceptance_of terms checkbox and Facebook connect - ruby-on-rails

How can you force terms and condition acceptance whith facebook connect ?
In my OmniauthCallbacksController i tried
#user_ipad.terms = true
Validation of the User still fails and the user gets redirected to the sign_up form with an error message.
/app/controllers/OmniauthCallbacksController
#user_ipad = UserIpad.new(:password => Devise.friendly_token[0,20])
#user_ipad.update_with_facebook_infos(omniauth)
#user_ipad.authentication_ways.build(:provider => omniauth['provider'], :uid => omniauth['uid'])
#user_ipad.terms = true
if #user_ipad.save()
sign_in_and_redirect #user_ipad, :event => :authentication
else
session["devise.facebook_data"] = omniauth
render :action=>'new', :controller=>'user_ipads', :layout => 'empty_layout'
end
/app/models/User
attr_accessible :terms
...
validates_acceptance_of :terms, :allow_nil => false, :message => "Vous devez accepter les conditions générales d'utilisation", :on => :create
Thanks for your help,
Vincent

validates_acceptance_of has an "accept" option. Rails doc says :
:accept - Specifies value that is considered accepted. The default
value is a string “1”, which makes it easy to relate to an HTML
checkbox. This should be set to true if you are validating a database
column, since the attribute is typecast from “1” to true before
validation.
So in your case, you should replace
#user_ipad.terms = true
with :
#user_ipad.terms = "1"

Related

Devise+OmniAuth for Facebook Sign Up on Remote Server

I am using Devise + Omniauth to enable Facebook signup in my application. When I was developing it, I encountered no problems. Same with deploying it to my remote server. The problem is, other people keep encountering the same error:
TypeError (no implicit conversion of Symbol into Integer):
app/models/user.rb:67:in `find_for_facebook_oauth'
app/controllers/users/omniauth_callbacks_controller.rb:4:in `facebook'
I have the following code for the User model user.rb:
def self.find_for_facebook_oauth( data, signed_in_resource=nil)
user = User.where(:email => data.info.email).first
unless user
params =
{
:user =>
{
:username => data.uid,
:email => data.info.email,
:password => Devise.friendly_token[0,20],
:user_profile_attributes =>
{
:first_name => data.extra.raw_info.first_name,
:last_name => data.extra.raw_info.last_name,
:remote_image_url => data.extra.raw_info.image,
},
:user_auths_attributes =>
{
:uid => data.uid,
:provider => data.provider
}
}
}
user = User.create!(params[:user])
end
return user
end
Where line 67 is the user = User.create!(params[:user])
And omniauth_callbacks_controller.rb:
def facebook
# You need to implement the method below in your model (e.g. app/models/user.rb)
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"])
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
Where line 4 is #user = User.find_for_facebook_oauth(request.env["omniauth.auth"])
The server logs also show the GET parameters:
Parameters: {"code"=>"[some long string of number and letters]", "state"=>"[another string of numbers and letters]"}
Update:
The logger outputs the following for request.env["omniauth.auth"]:
#<OmniAuth::AuthHash credentials=#<OmniAuth::AuthHash expires=true expires_at=1401992074 token="*"> extra=#<OmniAuth::AuthHash raw_info=#<OmniAuth::AuthHash email="*" first_name="*" gender="male" id="*" last_name="*" link="https://www.facebook.com/*" locale="en_US" name="*" timezone=8 updated_time="2014-04-05T09:29:22+0000" username="*" verified=true>> info=#<OmniAuth::AuthHash::InfoHash email="*" first_name="*" image="http://graph.facebook.com/*/picture?type=square" last_name="*" name="*" nickname="*" urls=#<OmniAuth::AuthHash Facebook="https://www.facebook.com/*"> verified=true> provider="facebook" uid="*">
Update 2:
Logging the params[:user] provides the following values:
Params: {:username=>"*", :email=>"*", :password=>"iePVLt7XEWk4YwPjja6n", :user_profile_attributes=>{:first_name=>"*", :last_name=>"*", :remote_image_url=>"http://graph.facebook.com/*/picture?type=square"}, :user_auths_attributes=>{:uid=>"*", :provider=>"facebook"}}
Update your params hash as below:
params =
{
:user =>
{
:username => data.uid,
:email => data.info.email,
:password => Devise.friendly_token[0,20],
:user_profile_attributes =>
{
:first_name => data.extra.raw_info.first_name,
:last_name => data.extra.raw_info.last_name,
:remote_image_url => data.info.image ## Removed comma and updated the method
},
:user_auths_attributes =>
[{
:uid => data.uid,
:provider => data.provider
}] ## Enclosed within array [] brackets
}
}
Looking at the params hash given by you, I can tell that a User and Profile have a 1-1 Relationship whereas User and Auths has a 1-M Relationship. In that case, user_auths_attributes must be passed as an Array.
TypeError (no implicit conversion of Symbol into Integer)
You were getting the above error because user_auths_attributes was being interpreted as an array and not a hash. So when Ruby saw params[:user][:user_auths_attributes][:uid] it was trying to take the last key and turn it into params[:user][:user_auths_attributes][0] or at least find some integer value it could be converted to index the Array.
I found only this issue:
:remote_image_url => data.extra.raw_info.image # In data I see only data.info.image
replace with
:remote_image_url => data.info.image
But it is not a solution for your question.
Try to debug data from params[:user]. From exception it looks like that you use some Hash on property which is Integer.

Devise Login Validation: Include Current URL in Validation

I was wondering if there is a way to include checking the current URL during login with devise.
Say that I have a user model with field :url, and that along with :email and :password, you also check if the current url matches with the user's :url field.
I was thinking I should do this in devise's self.find_for_database_authentication method and I currently have this:
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login).downcase
where(conditions).where('$or' => [{:username => /^#{Regexp.escape(login)}$/i}, {:email => /^#{Regexp.escape(login)}$/i}]).first
else
where(conditions).first
end
end
but what should I add to it so that it checks the current URL?
Note: I am using mongoid
Thanks in advance!
You should simply add the url to the query, something like this:
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
login = conditions.delete(:login).downcase
url = conditions.delete(:url ).downcase
if login && url
where(conditions).where(
:url => {"$eq" => url},
'$or' => [
{:username => /^#{Regexp.escape(login)}$/i},
{:email => /^#{Regexp.escape(login)}$/i}
]
).first
else
where(conditions).first
end
end
Where the hash it is sort of an implicit "and"

Ruby on Rails Change Order of Custom Model Validations

I have a form that has model validations which works properly in my local system however when i check it on live site the order of the model validations order gets changed although the code is same in both.
this is the block of code in model:
def validate
#email validation
if !email.blank?
#errors.add(:email,I18n.t(:ismissing))
#else
if email != email_confirmation
errors.add(:email,I18n.t(:ErrorMessageConfirmEmailNotmatch))
else
if email.length <=200 then
if email.match(/^[^#][\w.-]*#[\w.-]+[.][a-z]{2,4}$/i).nil?
errors.add(:email,I18n.t(:ErrorMessageInvalid))
else
if #new_record==true
if User.find(:all, :conditions => ['lower(email) = ?', email.downcase]).count>0
#errors.add(:email," ID already exists. Provide another Email ID")
errors.add(:email,I18n.t(:ErrorMessageAlreadyExists))
end
else
if #changed_attributes["email"]!=nil
if User.User.find(:all, :conditions => ['lower(email) = ?', email.downcase]).count>0
#errors.add(:email," ID already exists. Provide another Email ID")
errors.add(:email,I18n.t(:ErrorMessageAlreadyExists))
end
end
end
end
else
errors.add(:email, I18n.t(:ErroeMessageMustlessthen,:size=>200))
end
end
else
errors.add(:email,I18n.t(:ismissing))
end
#end : Email validation
if email_confirmation.blank?
errors.add(:email_confirmation,I18n.t(:ismissing))
end
#pasword validation
if #new_record==true
if password.blank?
errors.add(:password,I18n.t(:ismissing))
else
if password_confirmation != password
errors.add(:password,I18n.t(:ErrorMessageConfirmPasswordNotmatch))
end
if !password.nil?
if password.length < 4 || password.length > 50 then
errors.add(:password,I18n.t(:ErroeMessageShouldBetween,:from=>"4",:to=>"50"))
end
errors.add(:password,I18n.t(:ErrorMessageInvalidPassword)) if password.match('^[a-z0-9##*-_]*$').nil?
end
end
end
#end password validation
if #new_record==true
if password_confirmation.blank?
errors.add(:password_confirmation,I18n.t(:ismissing))
end
end
if dob.blank?
errors.add(:dob,I18n.t(:ErrorMessageInvalid))
else
begin
#dt = DateTime.strptime(dob, "%m/%d/%Y").to_date
if dob.year <= 1900 then
errors.add(:dob,I18n.t(:ErrorMessageInvalidYear))
end
if dob>=Date.today then
errors.add(:dob,I18n.t(:ErroeMessageInvalidBirthday))
end
rescue Exception => ex
#errors.add(:dob,'is Invalid (MM/DD/YYYY format)')
errors.add(:dob,I18n.t(:ErroeMessageInvalidBirthday))
end
end
end
and the controller calls the Validate method on registration.An urgent help is required If anybody has any suggestions or ideas .
Thanks in Advance
You can use rails default validations..I did for email and gave you the sample here..
validates :email,
:presence =>{ :message => I18n.t(:ismissing)},
:length => {:allow_blank => true, :maximum => 200, :message => I18n.t(:ErroeMessageMustlessthen,:size=>200)},
:format => {:allow_blank => true, :with => /^[^#][\w.-]*#[\w.-]+[.][a-z]{2,4}$/i, :message => I18n.t(:ErrorMess
:uniqueness => {:allow_blank => true, :message => I18n.t(:ErrorMessageAlreadyExists)},
:confirmation => {:message => I18n.t(:ErrorMessageConfirmEmailNotmatch)}
Likewise you can also do for other fields.
Not sure why these wouldn't be executing in order. Have you logged something to indicate that in production?
Rather than put everything in a big validate method, maybe split into several (probably a better practice in general), then call in the order you want.
eg.
before_save :validate_email, :validate_dob
def validate_email
...
end
def validate_dob
...
end

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

Authlogic, can't update user because of validation

I've got authlogic setup as such
acts_as_authentic do |config|
config.login_field = 'email'
config.merge_validates_length_of_email_field_options :in => 5..50
config.validates_length_of_password_field_options = {:on => :update, :minimum => 4 }
config.validates_length_of_password_confirmation_field_options = {:on => :update, :minimum => 4}
end
I can't update user attributes because the password and password_confirmation try to get validated on save and they are nil. Is there any way to turn validations off temporarily, or a better solution?
Here's how it works for me:
Add a condition to your validate statements like this:
config.validates_length_of_password_field_options = {:on => :update, :minimum => 4, :if => :should_validate? }
Then add a custom should_validate? function to your user model. For example you could do
attr_accessor :updating_password
def should_validate?
updating_password or new_record?
end
This way you can explicitly set user.updating_password = true in your controller anytime you want the password to be validated and leave it as it is if you don't want any validation.
(This is my first answer, so I hope it's helpful for you. Otherwise don't hesitate to correct me.)

Resources