本投稿は講義資料であり、Rubyの基礎は理解しているが、rails tutorialで躓く読者を対象としています。
1章:環境構築
2章:Scaffold を用いた高速なアプリケーション構築 及び MVCの理解
3章:Scaffold を用いない開発方法 及び 応用
4章:ログイン機能
3章で作成した、蔵書管理アプリ bukukore にログイン機能を付与していきます。
ログイン機能は、 Devise という GEM を用いて構築していきます。
Devise
bukukore ディレクトリ内の、Gemfile を立ち上げて下記のコードを追記してください。
gem 'devise'
Gemfile に追記したら、 bundle install していきましょう。
$ bundle install --path vendor/bundle
devise のインストールが完了したら、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', 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.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
2つ目のメッセージは、3つ目のメッセージは、のちほど追加します。
4つ目のメッセージでViewを作成するのですが、そのまえにModelをつくっておきます。
devise で使いたいのは User登録機能なので 下記のコマンドを実行します。
config.scoped_views = true
config.scoped_views を false から true に書き換えてください。
(devise をどのフォルダにインストールするかの設定です。)
(行頭の #は削除してください)
使い方はこちら
$ 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認証を追加したい場合に使用します。 |
# 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 もすべての機能が使用できるように変更しておきます。
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
マイグレーションファイル を変更したので適応させましょう。
マイグレーションファイルの実行は下記のコマンドでしたね。
$ 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(アカウント作成関連) も作っていきます。
$ 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
いまのうちに、新規登録、ログインへのリンクを用意しておきましょう。
<!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 二段階認証アプリパスワードの発行方法
まず、上記のURLにアクセスし、Googleの2段階認証アプリパスワードの発行を行いましょう。
学校のメールアドレスでは発行できないので、自身で作成したメールアドレスを使用しましょう。
config/initializers/devise.rb の21行目あたりにある
config.mailer_sender を自分の gmail アドレスに変更します。
config.mailer_sender = '[自分のアドレスに置き換えます]@gmail.com'
最後に開発環境の設定ファイルの最後に以下を追加します。
(省略)
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 を作成します。
$ rails g controller Users index show
2つ目のメッセージにあったルート設定もここでしておきましょう。
ユーザーの一覧ページ(users#index)をTOPページにしたいので、下記コードを追加します。
(省略)
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の解答例はここをクリックすると表示されます
class UsersController < ApplicationController
def index
@users = User.all
end
def show
end
end
2の解答例はここをクリックすると表示されます
<h1>ユーザーの一覧</h1>
<% @users.each do |user| %>
<p><%= user[:id] %></p>
<p><%= user[:email] %></p>
<% end %>
3の解答例はここをクリックすると表示されます
class UsersController < ApplicationController
def index
@users = User.all
end
def show
@user = User.find(params[:id])
end
end
# get 'users/show'(コメントアウト)
get 'users/show/:id', to: 'users#show', as: 'user'
as: 'user' とすることで、user_path と記述すれば、アクセスできるようになります。
<h1>ユーザーの情報</h1>
<p><%= @user.id %></p>
<p><%= @user.email %></p>
#新しいカラムの追加方法
現在 id,email と2つのカラムがあります。これだけでは誰か分かりづらいので
名前を登録するために、 name カラムを追加してみましょう。
$ rails g migration AddNameToUsers name:string
上記のコマンドで、usersテーブルに name カラムを追加するためのマイグレーションファイルが自動生成されます。
class AddNameToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :name, :string
end
end
マイグレーションファイルを実行します。
$ rails db:migrate
== 20200222020202 AddNameToUsers: migrating ===================================
-- add_column(:users, :name, :string)
-> 0.0017s
== 20200222020202 AddNameToUsers: migrated (0.0018s) ==========================
users テーブルに、nameカラムを追加することができました。
####ストロングパラメータに name を許可する
しかし、追加しただけでは保存できないようになっています。
これは rails が自動的行っているセキュリティ対策の為です
ストロングパラメータについて
保存できるようにするためには、ストロングパラメータへの追加が必要です。
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.ユーザーの詳細ページに、登録した本の情報が表示されるようにしてください。
解答例はここをクリックすると表示されます
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
class Book < ApplicationRecord
belongs_to :user
end
class UsersController < ApplicationController
def index
@users = User.all
end
def show
@user = User.find(params[:id])
@books = @user.books
end
end
<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 とすれば取得できます。
また、ログインしていない状態で蔵書登録を行うと、user_idがnilのエラーが出ます。
なので、コントローラーの先頭にbefore_action :authenticate_user!
を記載する必要があります。
解答例はここをクリックすると表示されます
def create
(省略)
@book.user_id = current_user.id
(省略)
end
もともとあった
@book.user_id = params[:book][:user_id]
を
@book.user_id = current_user.id
に置き換えることで、ログイン中のユーザーの蔵書として登録できます。
- <%= f.label :user_id %>(削除)
- <%= f.number_field :user_id %>(削除)
上記の2行は不要になるので削除しておきます。