Help us understand the problem. What is going on with this article?

Before Rails Tutorial4章 ログイン機能

本投稿は講義資料であり、Rubyの基礎は理解しているが、rails tutorialで躓く読者を対象としています。
1章:環境構築
2章:Scaffold を用いた高速なアプリケーション構築 及び MVCの理解
3章:Scaffold を用いない開発方法 及び 応用
4章:ログイン機能

3章で作成した、蔵書管理アプリ bukukore にログイン機能を付与していきます。
ログイン機能は、 Devise という GEM を用いて構築していきます。

Deviseの使い方はこちら

Devise

bukukore ディレクトリ内の、Gemfile を立ち上げて下記のコードを追記してください。

Gemfile(追記)
gem 'devise'

Gemfile に追記したら、 bundle install していきましょう。

terminal
$ bundle install --path vendor/bundle

devise のインストールが完了したら、deviseを適応させていきます。

terminal
$ 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', port: 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. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

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

deviseをインストールすると、上記のようなメッセージが表示されます。
1つ目のメッセージに従い、デフォルトのURL を設定します。今回は指示通りで良いので、
config/environments/development.rb の一番下に下記のコードを追加します。

config/environments/development.rb(追加)
(省略)
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

2つ目のメッセージは、3つ目のメッセージは、のちほど追加します。
4つ目のメッセージでViewを作成するのですが、そのまえにModelをつくっておきます。
devise で使いたいのは User登録機能なので 下記のコマンドを実行します。

config/initializers/devise.rb(235行目あたりの該当箇所を書換)
config.scoped_views = true

config.scoped_views を false から true に書き換えてください。
(devise をどのフォルダにインストールするかの設定です。)
使い方はこちら

terminal
$ rails g devise User
  create   db/migrate/20200216064430_devise_create_users.rb
  create   app/models/user.rb
   route   devise_for :users

これで user.rb の他に、devise に関するマイグレーションファイルと、ルーティングが追加されています。
ルーティングは、 rails routes を実行することで確認できます。
マイグレーションファイルは、 db/migrate の中にあります。
devise では機能毎に ON / OFF 設定可能です。

モジュール名    各機能の説明
database_authenticatable データベースに保存されたパスワードが正しいかどうかの検証とを行ってくれます。またパスワードの暗号化も同時に行ってくれます。
registerable ユーザー自身がアカウント登録、編集、削除することを許可します。
recoverable パスワードをリセットできるようにし、メールで通知します。
rememberable 30日間ログインしたままにするというような永続ログインを可能にします。ログイン画面の下のチェックボックスにチェックすることで永続ログインを有効化できます。
trackable ユーザーのサインイン回数や、サインイン時間、IPアドレスなどを記録できるようにします。
validatable Emailやパスワードのバリデーションを可能にします。独自に定義したバリデーションを追加することもできます。
confirmable メールに記載されているURLをクリックして本登録を完了する、といったよくある登録方式を可能にします。また、サインイン中にアカウントが認証済みかどうかを検証します。
lockable 一定回数ログインを失敗するとアカウントをロックします。ロック解除にはメールによる解除か、一定時間経つと解除するといった方法があります。
timeoutable 一定時間活動していないアカウントのログインを破棄します。
omniauthable TwitterやFacebookなどのSNS認証を追加したい場合に使用します。
db/migrate/2020(省略)_devise_create_users.rb
# frozen_string_literal: true
class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, default: 0, null: false
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Confirmable
      t.string   :confirmation_token
      t.datetime :confirmed_at
      t.datetime :confirmation_sent_at
      t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      t.string   :unlock_token # Only if unlock strategy is :email or :both
      t.datetime :locked_at


      t.timestamps null: false
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
    add_index :users, :confirmation_token,   unique: true
    add_index :users, :unlock_token,         unique: true
  end
end

上記のようにすべての機能をコメントアウトしておきます。(講義終了後に、興味ある学生が拡張して遊べるための配慮)
今回はメール認証を行いたいので Confirmable を使用します。
user.rb もすべての機能が使用できるように変更しておきます。

app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :confirmable, :lockable, :timeoutable
end

マイグレーションファイル を変更したので適応させましょう。
マイグレーションファイルの実行は下記のコマンドでしたね。

terminal
$ rails db:migrate
== 20200220202020 DeviseCreateUsers: migrating ================================
-- create_table(:users)
   -> 0.0021s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0008s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0010s
== 20200220202020 DeviseCreateUsers: migrated (0.0041s) =======================

rails db:migrate した後は、 rails sever を再起動しておいてください。

マイグレーションを実行することでデータベースの中に、usersテーブルが作成されます。
4つ目のメッセージに書いてあるように、Devise が使用するView(アカウント作成関連) も作っていきます。

terminal
$ rails g devise:views user
  app/views/devise/shared/_links.html.erb (リンク用パーシャル)
  app/views/devise/confirmations/new.html.erb (認証メールの再送信画面)
  app/views/devise/passwords/edit.html.erb (パスワード変更画面)
  app/views/devise/passwords/new.html.erb (パスワードを忘れた際、メールを送る画面)
  app/views/devise/registrations/edit.html.erb (ユーザー情報変更画面)
  app/views/devise/registrations/new.html.erb (ユーザー登録画面)
  app/views/devise/sessions/new.html.erb (ログイン画面)
  app/views/devise/unlocks/new.html.erb (ロック解除メール再送信画面)
  app/views/devise/mailer/confirmation_instructions.html.erb (メール用アカウント認証文)
  app/views/devise/mailer/password_change.html.erb (メール用パスワード変更完了文)
  app/views/devise/mailer/reset_password_instructions.html.erb (メール用パスワードリセット文)
  app/views/devise/mailer/unlock_instructions.html.erb (メール用ロック解除文)

上記コマンドを実行することで、 Devise の機能により、ユーザー作成関連の View が自動生成されます。
この時点でアカウント作成画面などにアクセスは可能ですが、メール認証機能は実装していないのでアカウントは作れません。
http://localhost:3000/users/sign_up

いまのうちに、新規登録、ログインへのリンクを用意しておきましょう。

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Bukukore</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <% if user_signed_in? %>  
      <%= link_to 'ユーザー編集', edit_user_registration_path %> |  
      <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>  
    <% else %>  
      <%= link_to "新規登録", new_user_registration_path %> |  
      <%= link_to "ログイン", new_user_session_path %>  
    <% end %>  
    <%= yield %>
  </body>
</html>

メール認証

Google 二段階認証

config/initializers/devise.rb の21行目あたりにある
config.mailer_sender を自分の gmail アドレスに変更します。

config/initializers/devise.rb
config.mailer_sender = '[自分のアドレスに置き換えます]@gmail.com'  

最後に開発環境の設定ファイルの最後に以下を追加します。

config/environments/development.rb(追記)
(省略)
ActionMailer::Base.smtp_settings = {  
  address: 'smtp.gmail.com',  
  port: 587,  
  user_name: '[自分のアドレスに置き換えます]@gmail.com',  
  password: '先程取得した二段階認証のアプリパスワード',
  authentication: 'plain',  
  enable_starttls_auto: true  
}  

以上でメール認証処理は完了です。

「こんなの自力でわかるわけない!自力開発なんてできない」
と思うかもしれませんが、GEMの使い方はリファレンスにすべて書いてあるのでご安心ください。
今後、リファレンスを読む癖、調べる癖をつけていきましょう。
https://github.com/heartcombo/devise#getting-started
https://qiita.com/gakkie/items/6ef70c0788c3cbff81ee

実際にユーザー登録を行い、メールが届くことを確認できます。
http://localhost:3000/users/sign_up
届いたメールに記載されている URL をクリックすることで、認証完了です。
rails server のログにも URL が書いてあるので、そちらをコピペしても認証可能です。

どういう仕組みで、メールの認証やログイン・ログアウトが行われているのか詳しくは
https://railstutorial.jp/
で学べます。

ユーザーの一覧と詳細表示ページ

Userの一覧をみるページ、詳細情報をみるページを作成していきましょう。
Model はすでに作っているので、 Controller と View を作成します。

terminal
$ rails g controller Users index show

2つ目のメッセージにあったルート設定もここでしておきましょう。
ユーザーの一覧ページ(users#index)をTOPページにしたいので、下記コードを追加します。

config/routes.rb(追加)
(省略)
  root to: 'users#index'

これで、root(最初のページ)にアクセスがあった時に、usersControllerのindexアクションを呼び出します。
http://localhost:3000/

課題 MVCの復習

1, User Model を使い、users テーブルから全データを取り出し
2, user index ページに表示してみましょう。
3, user show ページにユーザー情報を表示してください http://localhost:3000/users/show/1

ヒント: Model は Controller に記述します。
一度何も見ずにやってみてみると理解度チェックになります。
曖昧な場合は、前章の内容を確認してください。

1の解答例はここをクリックすると表示されます
app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    @users = User.all
  end

  def show
  end
end

2の解答例はここをクリックすると表示されます
app/views/users/index.html.erb
<h1>ユーザーの一覧</h1>

<% @users.each do |user| %>
  <p><%= user[:id] %></p>
  <p><%= user[:email] %></p>
<% end %>

3の解答例はここをクリックすると表示されます
app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    @users = User.all
  end

  def show
    @user = User.find(params[:id])
  end
end
config/routes.rb(書き換え)
#   get 'users/show'(コメントアウト)
  get 'users/show/:id', to: 'users#show', as: 'user'

as: 'user' とすることで、user_path と記述すれば、アクセスできるようになります。

app/views/users/show.html.erb
<h1>ユーザーの情報</h1>

<p><%= @user.id %></p>
<p><%= @user.email %></p>

新しいカラムの追加方法

現在 id,email と2つのカラムがあります。これだけでは誰か分かりづらいので
名前を登録するために、 name カラムを追加してみましょう。

terminal
$ rails g migration AddNameToUsers name:string

migration コマンドのまとめはこちら

上記のコマンドで、usersテーブルに name カラムを追加するためのマイグレーションファイルが自動生成されます。

db/migrate/2020(省略)_add_name_to_users.rb(自動生成)
class AddNameToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :name, :string
  end
end

マイグレーションファイルを実行します。

terminal
$ rails db:migrate
== 20200222020202 AddNameToUsers: migrating ===================================
-- add_column(:users, :name, :string)
   -> 0.0017s
== 20200222020202 AddNameToUsers: migrated (0.0018s) ==========================

users テーブルに、nameカラムを追加することができました。

ストロングパラメータに name を許可する

しかし、追加しただけでは保存できないようになっています。
これは rails が自動的行っているセキュリティ対策の為です
ストロングパラメータについて

保存できるようにするためには、ストロングパラメータへの追加が必要です。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :permitted_parameters, if: :devise_controller?

  private

  def permitted_parameters
    devise_parameter_sanitizer.permit :sign_up, keys: [:name]
    devise_parameter_sanitizer.permit :account_update, keys: [:name]
  end

end 

permitted_parameters アクションの中を見てください。
devise_parameter_sanitizer.permit 【許可する場所】, keys: 【許可するカラム名】
というようにして、許可を与えます。

before_action は、このファイルが呼び出されたときに最初に実行されるものです。

これで新たに、名前を保存できるようになりました。

課題

1, 登録画面に、名前を登録するためのフォームを追加してください。
   http://localhost:3000/users/sign_up
2, 実際に名前を登録し、 show ページで名前を表示してください。
   http://localhost:3000/users/show/1 (必要があればidは登録した番号に変更してください)

BookテーブルとUserテーブルの関連付け

続いて、2章で学習したテーブルの関連付けの復習をやっていきます。
詳細ページに、そのユーザーが登録した、本の情報を表示していきましょう。

http://localhost:3000/users/show/1 ←ユーザーの詳細ページ

http://localhost:3000/books/new ←本の情報登録ページ
http://localhost:3000/books/show/1 ←登録内容を確認

課題

1.ユーザーの詳細ページに、登録した本の情報が表示されるようにしてください。

解答例はここをクリックすると表示されます
app/models/user.rb(1行追加)
class User < ApplicationRecord
   has_many :books

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :confirmable, :lockable, :timeoutable
end
app/models/book.rb
class Book < ApplicationRecord
  belongs_to :user
end
app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    @users = User.all
  end

  def show
    @user = User.find(params[:id])
    @books = @user.books
  end
end
app/views/users/show.html.erb
<p><%= @user.id %></p>
<p><%= @user.email %></p>
<p><%= @user.name %></p>

<% @books.each do |book| %>
  <p>本のタイトル: <%= book.title %></p>
  <p>著者: <%= book.author %></p>
<% end %>

2. ログイン中のユーザーは、新規蔵書登録の際に、自動的に自身の user_id で投稿できるようにしてください。

ヒントはここをクリックすると表示されます

user_id の登録は、books_controller.rb の create アクションでおこなわれています。
ログイン中のユーザーID は current_user.id とすれば取得できます。

 

解答例はここをクリックすると表示されます
ruby/app/controllers/books_controller.rb(一部変更)
  def create
    (省略)
    @book.user_id = current_user.id
    (省略)
  end

もともとあった
@book.user_id = params[:book][:user_id]

@book.user_id = current_user.id
に置き換えることで、ログイン中のユーザーの蔵書として登録できます。

app/views/books/new.html.erb(削除)
-  <%= f.label :user_id %>(削除)
-  <%= f.number_field :user_id %>(削除)

上記の2行は不要になるので削除しておきます。

https://bbbbruno.qrunch.io/entries/wcNZqbMwA5SRBqQj

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした