Reputation: 355
I am trying to skip password validation as facebook does not return a password for login.
I am getting a error;
"Validation failed: Password can't be blank" on line user.save!
Application trace;
app/models/user.rb:36:in block in 'from_omniauth'
app/models/user.rb:29:in 'from_omniauth'
app/controllers/sessions_controller.rb:6:in 'create'
Is this because from_omniauth
is a class method, wrapped inside the user variable and then I am trying to skip password validation, as, a instance variable, when the instance is not created yet. Ie first_or_create do |user|
has not created or registered the user before the instance?
If so, I was wondering how I could refactor my code to make this work?
Sessions controller
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env["omniauth.auth"])
user.skip_password_validation = true
...
model.rb
class User < ApplicationRecord
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true,
unless: :skip_password_validation
attr_accessor :skip_password_validation
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.email = auth.info.email
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
end
Upvotes: 0
Views: 836
Reputation: 355
With this, the problem is has_secure_password
, which has 3 validation methods by default shown here api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html. You add in has_secure_password validations: false
, and can add in validations manually in the validates
method. The proper code should be,
Sessions controller
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env["omniauth.auth"])
...
Model
has_secure_password validations: false
validates :password, on: :create, presence: true, length: { minimum: 6 }, allow_nil: true,
unless: :skip_password_validation
attr_accessor :skip_password_validation
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.email = auth.info.email
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.skip_password_validation = true
user.save!
end
...
EDIT I come back to this question again as you need to have the skip method in the model on the model object before save as rails evaluates the model method first. So you could do as what @Vladan Markovic has written or simply put user.skip_password_validation = true
in the from_omniauth
method in the model before save is called which I have edited to show.
Upvotes: 0
Reputation: 354
You could pass skip_password parameter to your instance function:
def self.from_omniauth(auth, skip_password)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.email = auth.info.email
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.skip_password_validation = skip_password
user.save!
end
end
And then call it like this:
user = User.from_omniauth(env["omniauth.auth"], true)
Upvotes: 1