Red > Green > Refactor > Red

cycle is based on desire

Devise gem で email もしくは 他の項目 を使って sign in をする方法(sign in 以外もいくつか)

今回は ドキュメントに倣って項目を username にする

分類: 準備

Devise 用設定ファイルの作成

$ rails g devise:install
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here 
     is an example of default_url_options appropriate for a development environment 
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { :host => 'localhost:3000' }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root :to => "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. If you are deploying on Heroku with Rails 3.2 only, you may want to set:

       config.assets.initialize_on_precompile = false

     On config/application.rb forcing your application to not access the DB
     or load models when precompiling your assets.

  5. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================

デバイス用モデルの作成

$ rails g devise user
      invoke  active_record
      create    db/migrate/20131225152844_devise_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      insert    app/models/user.rb
       route  devise_for :users

デバイス用モデルのテーブルを変更。email もしくは別に入力させたい カラムを指定

$ rails g migration add_username_to_users username:string
      invoke  active_record
      create    db/migrate/20131225152848_add_username_to_users.rb

マイグレート

$ rake db:migrate
==  DeviseCreateUsers: migrating ==============================================
-- create_table(:users)
   -> 0.0082s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0007s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0006s
==  DeviseCreateUsers: migrated (0.0098s) =====================================

==  AddUsernameToUsers: migrating =============================================
-- add_column(:users, :username, :string)
   -> 0.0022s
==  AddUsernameToUsers: migrated (0.0024s) ====================================

分類: Controller の設定

ストロングパラメータの定義

class ApplicationController < ActionController::Base
  before_filter :configure_permitted_parameters, if: :devise_controller? # フィルターを定義
  protect_from_forgery with: :exception

  protected

  # このメソッドを定義
  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me) }
    devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email, :password, :remember_me) }
    devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:username, :email, :password, :password_confirmation, :current_password) }
  end
end

Model の設定

User Model のアトリビュートを作成。email と username に紐づくらしい

app/model/user.rb

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  attr_accessor :login # アトリビュートを定義
end

Devise に :login を authentication_keys に割り当てる設定

config/initializers/devise.rb

config.authentication_keys = [ :login ]

(多重モデルを使っていたら下の書き方が良いらしい(書いたことはない)

devise :database_authenticatable, :registerable,
       :recoverable, :rememberable, :trackable, 
       :validatable, :authentication_keys => [:login]

first_by_auth_conditions を定義しなければいけない。

本来やるべきことはfind_first_by_auth_conditions をオーバーライドする

こと(ややこしいが新の意味ではfind_for_database_authentication

を弄らないといけないが)

first_by_auth_conditions を弄れば find_for... を弄ったことになるらしい

validation もかけておく。

app/models/user.rb

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  attr_accessor :login

  validates :username,
    :uniqueness => {
      :sensitive => false
    }

  def self.find_first_by_auth_conditions(warden_conditions)
    conditions = warden_conditions.dup
    if login = conditions.delete(:login)
      where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
    else
      where(conditions).first
    end
  end
end

View の設定(時々config)

sign_in 時の view を変更する

app/views/devise/session/new.html.erb 

<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>

  <div><%= f.label :login %><br />   <!-- 追加 -->
  <%= f.text_field :login %></div>   <!-- 追加 -->

  <div><%= f.label :email %><br />              <!-- 削除 -->
  <%= f.email_field :email, :autofocus => true %></div> <!-- 削除 -->

sign_up 時の view を変更する

app/views/devise/registrations/new.html.erb

<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
  <%= devise_error_messages! %>

  <div><%= f.label :username %><br />   <!-- 追加 -->
  <%= f.text_field :username %></div>  <!-- 追加 -->

  <div><%= f.label :email %><br />
  <%= f.email_field :email, :autofocus => true %></div>
app/views/devise/registrations/edit.html.erb

<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
  <%= devise_error_messages! %>

  <div><%= f.label :username %><br /> <!-- 追加 -->
  <%= f.text_field :username %></div> <!-- 追加 -->

  <div><%= f.label :email %><br />
  <%= f.email_field :email, :autofocus => true %></div>

Devise に login を パスワードリセットおよびパスワード確認のキーとして設定する

config/initializers/devise.rb

config.reset_password_keys = [ :login ]
config.confirmation_keys = [ :login ]

パスワード忘れましたかビューを変更する

app/views/devise/passwords/new.html.erb

<h2>Forgot your password?</h2>

<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %> 
  <%= devise_error_messages! %>

  <div><%= f.label :login %><br /> <!-- 追加 -->
  <%= f.text_field :login %></div> <!-- 追加 -->
  <div><%= f.label :email %><br />                       <!-- 削除 -->
  <%= f.email_field :email, :autofocus => true %></div>  <!-- 削除 -->

パスワード再送ビューを変更する

app/views/confirmations/new.html.erb

<h2>Resend confirmation instructions</h2>
  
<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %>
  <%= devise_error_messages! %>
  
  <div><%= f.label :login %><br /> <!-- 追加 -->
  <%= f.text_field :loin %></div> <!-- 追加 -->
  <div><%= f.label :email %><br /> <!-- 削除 -->
  <%= f.email_field :email, :autofocus => true %></div> <!-- 削除 -->


自由には代償がある

引用元

https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address