[Rails] Devise 改使用 username 或 email 登入
本文使用 Ruby 2.3.1 / Rails 5.0.0
建立 Username
rails generate migration add_username_to_users username:string:uniq
rails db:migrate
設定 Strong parameters
# [path] application_controller.rb
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
added_attrs = [:username, :email, :password, :password_confirmation, :remember_me]
devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
devise_parameter_sanitizer.permit :account_update, keys: added_attrs
end
end
在 User 裡面建立一個虛擬屬性: login
# [path] User.rb
def login=(login)
@login = login
end
def login
@login || self.username || self.email
end
告訴 Devise 要使用 :login 當作 authentication_keys
# [path] config/initializers/devise.rb
config.authentication_keys = [ :login ]
Override Devise 的 find_for_database_authentication method
# [path] User.rb
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions.to_h).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
elsif conditions.has_key?(:username) || conditions.has_key?(:email)
where(conditions.to_h).first
end
end
加入驗證機制
# [path] User.rb
validates_format_of :username, with: /^[a-zA-Z0-9_\.]*$/, :multiline => true
validates :username, :presence => true, :uniqueness => { :case_sensitive => false }
產生View畫面
第一種方式:(路徑會在/view/devise/之下)
rails g devise:views
第二種方式:(路徑會在/view/user/之下,但要去devise調整scoped_views參數才會生效)
rails g devise:views user
# [path] config/initializers/devise.rb
config.scoped_views = true
調整 View 畫面
# [path] sessions/new.html.erb
<div class="form-group">
<%= f.label :login, "Username" %><br />
<%= f.text_field :login, autofocus: true, class: "form-control", placeholder: "" %>
</div>
# [path] registrations/new.html.erb
<div class="form-group">
<%= f.label :username %><br />
<%= f.text_field :username, autofocus: true %>
</div>
# [path] registrations/edit.html.erb
<div class="form-group">
<%= f.label :username %><br />
<%= f.text_field :username, autofocus: true %>
</div>
留言