0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

基礎Ruby on Rails Chapter8 アクション・コールバック/マイアカウントページの作成

Last updated at Posted at 2018-09-29

基礎Ruby on Rails Chapter8 単数リソース
基礎Ruby on Rails Chapter9 ActiveRecoedの活用/コールバック

アクション・コールバックを利用したアクセス制限

アクション・コールバックとは

  • コントローラ内で、いずれかのアクションが呼ばれたときに行う前処理。アクセス制限などに使う。2種類の書き方がある。
  • 1つ目の書き方。ブロックを使用する。全てのアクション実行前に、コードが実行される。
class ExampleController < ApplicationController
  before_action do
    # アクション実行前に行う処理
  end
end
  • 1つ目の書き方の特定アクションバージョン。onlyで指定したもののみ。exceptで除外。
class ExampleController < ApplicationController
  before_action only: [:index, :show] do
    # アクション実行前に行う処理
  end
end
  • 2つ目の書き方は、プライベートメソッドを定義して、そのメソッドを定義する方法。onlyexceptは上記と同じ
class ExampleController < ApplicationController
  before_action :do_something, only: [:index, :show]
  before_action :do_something, except: [:index, :search]

  private def :do_something
    # アクション実行前に行う処理
  end
end

会員限定のコンテンツ

  • LoginRequiredForbiddenを一般的なエラーを表すStandardErrorから継承して作成する。
  • loginRequiredメソッドは、ログインしていないとエラーが発生する。before_actionのために作成。
app/controllers/application_controller.rb(一部)
# 以下を追加
  class LoginRequired < StandardError; end
  class Forbidden < StandardError; end

  private def loginRequired
    raise LoginRequired unless current_member
  end
end
  • before_actionにlogin_requiredメソッドをアクション・コールバックに指定する。これによりログインしていない状態で、membersのアクションを呼ぶとエラーが発生する。
app/controllers/members_controller.rb(一部)
class MembersController < ApplicationController
  before_action :login_required
  • ヘッダのメニューに、if current_memberを入れて、会員名簿と管理ページをログインしていない状態では見えなくする。
app/views/shared/_header.html.erb(一部)
<nav class="menubar">
  <ul>
    <%= menu_link_to "TOP", :root %>
    <%= menu_link_to "ニュース", "#" %>
    <%= menu_link_to "ブログ", "#" %>
    <% if current_member %>
      <%= menu_link_to "会員名簿", :members %>
      <%= menu_link_to "管理ページ", "#" %>
    <% end %>
  </ul>
</nav>
  • ログインしていない状態でmembersにアクセスすると、エラーが発生する。

image.png

マイアカウントページの作成

ルーティングの設定

  • ルーティングに、AccountControllerにshow、edit、updateのアクションを追加する。
config/routes.rb(一部)
  resource :account, only: [:show, :edit, :update]
end
アクション パス HTTPメソッド パスを示すシンボル パスを返すメソッド
show /account GET :account account_path
edit /account/edit GET :edit_account edit_account_path
update /account PATCH :account account_path
  • bin/rails routes -c コントローラ名で、routes.rbで設定されたパスとHTTPメソッドの一覧を表示できる。
$ bin/rails routes -c account
      Prefix Verb  URI Pattern             Controller#Action
edit_account GET   /account/edit(.:format) accounts#edit
     account GET   /account(.:format)      accounts#show
             PATCH /account(.:format)      accounts#update
             PUT   /account(.:format)      accounts#update

AccountsControllerの作成

アカウント情報の表示

  • AccountControllerを作成する。show、editも加えて、テンプレートファイルも作成する。
$ bin/rails g controller accounts show edit
      create  app/controllers/accounts_controller.rb
      invoke  erb
      create    app/views/accounts
      create    app/views/accounts/show.html.erb
      create    app/views/accounts/edit.html.erb
  • sessionコントローラはログインしたメンバーのみアクセスできるように、before_action :login_requiredを付ける。
  • showメソッドでは、自分自身のオブジェクトをインスタンス変数@memberにセットする。
app/controllers/accounts_controller.rb
class AccountsController < ApplicationController
  before_action :login_required

  def show
    @member = current_member
  end
(省略)
  • 部分テンプレート_body.html.erbを新規作成する。ほぼ同じなので、app/views/members/show.html.erbから、tableタグの部分をコピペして作成する。
app/views/members/_body.html.erb
<table class="attr">
  <tr>
    <th width="150">背番号</th>
    <td><%= @member.number %></td>
  </tr>
  <tr>
    <th>ユーザー名</th>
    <td><%= @member.name %></td>
  </tr>
  <tr>
    <th>氏名</th>
    <td><%= @member.full_name %></td>
  </tr>
  <tr>
    <th>性別</th>
    <td><%= @member.sex == 1 ? "男" : "女" %></td>
  </tr>
  <tr>
    <th>誕生日</th>
    <td><%= @member.birthday&.strftime("%Y年%m月%d日") %></td>
  </tr>
  <tr>
    <th>メールアドレス</th>
    <td><%= @member.email %></td>
  </tr>
  <tr>
    <th>管理者</th>
    <td><%= @member.administrator? ? "○" : "-" %></td>
  </tr>
</table>
  • app/views/members/show.html.erbは、上記で作成した_body.html.erbで置き換える。
app/views/members/show.html.erb(一部)
(省略)
<div class="toolbar"><%= link_to "編集", [:edit, @member] %></div>
<%= render "body" %>
  • app/views/account/show.html.erbは、上記で作成した_body.html.erbを使用する。
app/views/account/show.html.erb
<% @page_title = "マイアカウント" %>
<h1><%= @page_title %></h1>
<ul class="toolbar">
  <%= menu_link_to "アカウント情報の編集", :edit_account %>
</ul>
<%= render "members/body" %>
  • サイトのヘッダーにある「〇〇さん」を、自分自身の情報を見るshowアクションのリンクにする。
app/views/shared/_header.html.erb(一部)
    <%= menu_link_to current_member.name + "さん", :account %>

image.png

アカウント情報の編集

  • _form.html.erb_member_form.html.erbと名称変更して、sharedディレクトリに移動する。
$ mv app/views/members/_form.html.erb app/views/shared/_member_form.html.erb
  • new.html.erbも、member_formshared/member_formに変更する。
app/views/members/new.html.erb(一部)
  <%= render "shared/member_formber_form", form: form %>
  • edit.html.erbも、member_formshared/member_formに変更する。
app/views/members/edit.html.erb(一部)
  <%= render "shared/member_form", form: form %>
  • アカウント情報の変更画面を作成する。
app/views/accounts/edit.html.erb
<% @page_title = "アカウント情報の変更" %>

<h1><%= @page_title %></h1>

<div class="toolbar"><%= link_to "マイアカウントに戻る" %></div>

<%= form_for @member, as: "account", url: :account do |form| %>
  <%= render "shared/member_form", form: form %>
  <div><%= form.submit %></div>
<% end %>
  • 管理者欄は、Memberコントローラの場合のみ表示させる。Accountコントローラでは表示しない。
  • human_attribute_nameは、属性名をロケールテキスト(ja.yml)から取得する。
app/views/shared/_member_form.html.erb(一部)
(省略)
  <% if controller.kind_of?(MembersController) %>
  <tr>
    <th><%= Member.human_attribute_name(:administrator) %></th>
    <td>
      <%= form.check_box :administrator, disabled: !current_member.administrator? %>
      <%= form.label :administrator %>
    </td>
  </tr>
  <% end %>
</table>
  • editアクションと、updateアクションを実装する。
app/controllers/accounts_controller.rb(一部)
(省略)
  def edit
    @member = current_member
  end

  def update
    @member = current_member
    @member.assign_attributes(params[:account])
    if @member.save
      redirect_to :account, notice: "アカウント情報を更新しました。"
    else
      render "edit"
    end
  end
end

image.png

パスワード変更機能

独立したパスワード変更フォームを作る理由

  • パスワード変更は上記で作成したアカウント情報変更フォームにパスワード変更欄を置いておくと、パスワードが空の場合はパスワードを変更しないのか、空にするのかよくわからない。
  • パスワードを変更するのに、変更前と、変更後を2回入力されるなど、わかりやすいユーザーインタフェースを提供するため。

ルーティングの設定

  • 自分のパスワードは、自分のアカウント情報と同様に単数リソースとして扱える。
  • passwordコントローラに、showeditupdateのアクションを用意する。
config/routes.rb(一部)
(省略)
  resource :password, only: [:show, :edit, :update]
end
アクション パス HTTPメソッド パスを示すシンボル パスを返すメソッド
show /password GET :password password_path
edit /password/edit GET :edit_password edit_password_path
update /password PATCH :password password_path

Memberモデルの変更

  • memberモデルにcurrent_passwordを読み書き可能な属性に追加する。
  • 元々password属性には、空文字禁止のバリデーションが設定されているが、これは新規作成の時しか働かない。
  • current_passwordに値がセットされている場合は、常に空文字でもnilでもないことを確認するようにする。
app/models/member.rb(一部)
(省略)
  attr_accessor :current_password
  validates :password, presence: { if: :current_password }
(省略)

パスワード変更フォームの作成

  • PasswordsControllerを作成する。editも加えて、テンプレートファイルも作成する。
$ bin/rails g controller passwords edit
      create  app/controllers/passwords_controller.rb
      invoke  erb
      create    app/views/passwords
      create    app/views/passwords/edit.html.erb
  • PasswordsControllerに、show、editアクションを追加する。
app/controllers/passwords_controller.rb
class PasswordsController < ApplicationController
  before_action :login_required

  def show
    redirect_to :account
  end

  def edit
    @member = current_member
  end
end
  • パスワードを変更フォームのテンプレートを追加する。
app/views/passwords/edit.html.erb
<% @page_title = "パスワードの変更" %>
<h1><%= @page_title %></h1>

<div class="toolbar"><% link_to "マイアカウントに戻る", :account %></div>

<%= form_for @member, as: "account", url: :password do |from| %>
  <%= render "shared/errors", obj: @member %>

  <table class="attr">
    <tr>
      <th><%= form.label :current_password %></th>
      <td><%= form.password_field :current_password %></td>
    </tr>
    <tr>
      <th><%= form.label :password %></th>
      <td><%= form.password_field :password %></td>
    </tr>
    <tr>
      <th><%= form.label :password_confirmation %></th>
      <td><%= form.password_field :password_confirmation %></td>
    </tr>
  </table>

  <div><%= form.submit "変更" %></div>
<% end %>
  • パスワード変更フォームで使用するラベルテキストをロケールファイルに追加する。
config/locales/ja.yml(一部)
#(省略)
        current_password: 現在のパスワード
        password: 新しいパスワード
        password_confirmation: 新しいパスワードの確認
#(省略)
  • 入力フォームのテーブルの上に、パスワードの変更リンクを追加する。
app/views/accounts/show.html.erb(一部)
(省略)
<ul class="toolbar">
  <%= menu_link_to "アカウント情報の編集", :edit_account %>
  <%= menu_link_to "パスワードの変更", :edit_password %>
</ul>
<%= render "members/body" %>
  • パスワード変更フォームが表示される。

image.png

新しいパスワードの保存

  • パスワードを変更する、updateアクションを追加する。
  • 現在のパスワードを画面から取得し、authenticateで認証する。
  • 正しければ、assign_attributesで、画面の値(新パスワード)を@memberにセットする。
  • 新しいパスワードが空だったり、確認と異なっていたりするとバリデーションエラーとなる。
  • 保存に成功したら、マイアカウントに戻る。
app/controllers/passwords_controller.rb(一部)
(省略)
  def update
    @member = current_member
    current_password = params[:account][:current_password]

    if current_password.present?
      if @member.authenticate(current_password)
        @member.assign_attributes(params[:account])
        if @member.save
          redirect_to :account, notice: "パスワードを変更しました。"
        else
          render "edit"
        end
      else
        @member.errors.add(:current_password, :wrong)
        render "edit"
      end
    else
      @member.errors.add(:current_password, :empty)
      render "edit"
    end
  end
end
  • エラーメッセージwrongを追加する。「現在のパスワードが正しくありません。」に使う。
config/locales/ja.yml

    errors:
      messages:
        invalid_member_name: は半角英数字で入力してください。
        wrong: が正しくありません。

メンバー追加フォームの修正

  • メンバーを追加するには初期パスワードを入力する必要があるので、新規作成の場合、emailの下にパスワード欄を表示する。
  • new_record?はモデルオブジェクトがデータベースに保存されていないときにtrueを返す。
app/views/shared/_member_form.html.erb(一部)
(省略)
  <% if @member.new_record? %>
    <tr>
      <th><%= form.label :password, "パスワード" %></th>
      <td><%= form.text_field :password %></td>
    </tr>
  <% end %>
  • 新規登録に、パスワード入力欄が表示された。

image.png

参考
改訂4版 基礎 Ruby on Rails (IMPRESS KISO SERIES)

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?