Rails3 devise / omniauth - password_required? и form_for: validate => true не работают вместе - PullRequest
1 голос
/ 24 марта 2012

Я использую devise, omniauth и client-side-validation, как описано в ryan bates railscasts.

Теперь у меня проблема с проверкой пароля, которая должна быть пропущена при регистрации через omniauth третьей стороной.провайдер.

Регистрационная форма (html.erb):

Регистрация

Регистрация через сторонние сети

<% = form_for (resource,: as => имя_ресурса,: url => путь регистрации (имя_ресурса),: validate => true) do | f |%>

Зарегистрируйтесь напрямую

<% = f.label: имя%>> <% = f.text_field: имя%>> 1017 *

<% = f.label: фамилия%> <% = f.text_field: фамилия%>

<% = f.label: электронная почта%> <% = f.text_field: email%>

<% = f.label: пароль%> <% = f.password_field: пароль%>

<% = f.label: password_confirmation%> <% = f.password_field: password_confirmation%>

<% = f.submit "Зарегистрируйтесь сейчас ",: class =>" button-big "%>

<% end%>

Моя пользовательская модель имеет - см. ОБНОВЛЕНИЕ ниже

validates :password, :presence => true, :confirmation =>true

предложение и пароль_ требуется?определение

def password_required?
(authentications.empty? || !password.blank?)
end

Когда я регистрируюсь через стороннего провайдера omniauth, корректно отображается форма регистрации, и пользователю предлагается ввести адрес электронной почты.К сожалению, пользователь должен ввести пароль, хотя он не должен запрашиваться из-за регистрации через стороннего разработчика.

Кто-нибудь может подсказать, как это сделать?

Спасибо и наилучшими пожеланиями

Ян

ОБНОВЛЕНИЕ: чтобы дать более конкретное представление, я добавил еще несколько фрагментов кода

AuthenticationsController:

class AuthenticationsController < ApplicationController
def index
@authentications = current_user.authentications if current_user
end

def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, authentication.user)
elsif current_user
current_user.authentications.create(:provider => omniauth['provider'], :uid => omniauth['uid'])
flash[:notice] = "Authentication successful."
redirect_to authentications_url
else
user = User.new
user.apply_omniauth(omniauth)
if user.save
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, user)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end

def destroy
@authentication = current_user.authentications.find(params[:id])
@authentication.destroy
flash[:notice] = "Successfully destroyed authentication."
redirect_to authentications_url
end

end

RegistrationsController: class RegistrationsController

def create
super
session[:omniauth] = nil unless @user.new_record? 
end

private
def build_resource(*args)
super
if session[:omniauth]
@user.apply_omniauth(session[:omniauth])
@user.valid?
end
end

end

Модель пользователя: класс User

# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, 
:validatable, :email_regexp =>  /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i

# Setup accessible (or protected) attributes for your model
attr_accessible :firstname, :lastname, :email, :password, :password_confirmation, :remember_me

# validations
validates :firstname, :presence => true
validates :lastname, :presence => true

validates :email, :presence => true, :uniqueness => true
validates_email :email

validates :password, :presence => true, :confirmation =>true            

# omniauth reference 3rd party
def apply_omniauth(omniauth)
if self.firstname.blank?
self.firstname = omniauth['info']['first_name'].presence || omniauth['info']['name'].presence || " "
end

if self.lastname.blank?
self.lastname = omniauth['info']['last_name'].presence || omniauth['info']['name'].presence || " "
end

if self.email.blank?
self.email = omniauth['info']['email'].presence
end

authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'])
end

# omit validation for omniauth session
def password_required?
(authentications.empty? || !password.blank?) && super
end

end

Аутентификация Класс модели Аутентификация

# Setup accessible (or protected) attributes for your model  
attr_accessible :user_id, :provider, :uid
end

Во время отладки я обнаружил, что метод authentications.build () в методе apply_omniauth (omniauth) создает пустой объект, так что password_required?всегда имеет значение true и пароль должен быть предоставлен.

ДОПОЛНИТЕЛЬНЫЙ ВОПРОС: почему «authentications.empty?»всегда возвращать «ложь»?

Заранее спасибо

Ян

1 Ответ

2 голосов
/ 24 марта 2012

Прежде всего, password_required?метод должен быть определен следующим образом:

def password_required?
  (authentications.empty? || !password.blank?) && super
end

Затем, по вашему мнению, вы должны обернуть поля пароля следующим образом:

# app/views/registrations/new.html.erb
<% if @user.password_required? %>
  <%= f.label :password %>
  <%= f.password_field :password %>
  <%= f.label :password_confirmation %>
  <%= f.password_field :password_confirmation %>
<% else %>
  ...
<% end %>

Затем в вашем контроллере или модели при созданииПри первом способе аутентификации вы должны использовать build , а не создавать или создавать новый, потому что таким образом authentications.empty? вернет true, и вам будет предложено ввести пароль.

Наконец,Что касается проверок, вы должны взглянуть на client_side_validations 'wiki о пользовательских проверках.Вам, вероятно, придется переопределить проверку пароля.

...