我正在使用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
更新:为了提供更具体的视图,我添加了更多代码片段
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?'总是返回'假'?
提前致谢
扬
答案 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。您可能需要覆盖密码验证。