Rails3设计/ omniauth - password_required?和form_for:validate =>真的不要一起工作

时间:2012-03-23 21:06:12

标签: validation devise omniauth form-for

我正在使用ryan bates railscasts中描述的设计,omniauth和客户端验证。

我现在面临密码验证问题,在通过omniauth第三方提供商注册时应该省略。

注册表单(html.erb):

  

注册

注册   通过第三方网络

<%= form_for(资源,:as => resource_name,:url =>   registration_path(resource_name),:validate =>是)do | f | %GT;   

直接注册

<%= f.label:firstname%> <%=   f.text_field:firstname%>

<%= f.label:lastname%> <%=   f.text_field:lastname%>

<%= f.label:email%> <%=   f.text_field:email%>

<%= f.label:password%> <%=   f.password_field:密码%>

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

<%= f.submit“立即注册”,:class => “button-big”%>

  <%end%>

我的用户模型有 - 见下面的更新

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

子句和password_required?定义

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

当我通过omniauth第三方提供商注册时,会正确弹出注册表单,并要求用户输入电子邮件地址。不幸的是,用户必须输入密码,尽管由于通过第三方注册而不应该提示他。

任何人都可以给我一个提示,如何完成?

谢谢和最好的问候

Jan

更新:为了提供更具体的视图,我添加了更多代码片段

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&lt;设计:: 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

用户模型:     class User&lt;的ActiveRecord :: Base的     #association     has_many:authentications

# 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

身份验证模型     class Authentication&lt;的ActiveRecord :: Base的     #association     belongs_to:user

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

调试时我发现'apply_omniauth(omniauth)'方法中的'authentications.build()'产生一个空对象,所以'password_required?'永远是真的,必须提供密码。

其他问题: 为什么'authentications.empty?'总是返回'假'?

提前致谢

1 个答案:

答案 0 :(得分:2)

首先,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 %>

然后在您的控制器或模型中,首次创建身份验证方法时,您应该使用构建而不是创建或新建,因为这样authentications.empty?将返回true并且您'将被要求输入密码。

最后,对于验证,您应该查看有关自定义验证的client_side_validations' wiki。您可能需要覆盖密码验证。