読者です 読者をやめる 読者になる 読者になる

気軽に楽しくプログラムと遊ぶ

自分が興味があってためになるかもって思う情報を提供しています。

Rails プロゲートの上級3章(ユーザー認証を仕上げよう)

今回はプロゲートの上級3章、「ユーザー認証を仕上げよう」をやっていきます。

プロフィールの編集を制限しよう

下記の対応を行う。

  • ユーザー一覧でログインユーザー(自分)のみ編集可能とする。
  • 別ユーザーの編集ページにURL直で遷移できないようにする。

ユーザー一覧でログインユーザー(自分)のみ編集可能とする

ログインユーザーのみ編集ボタンを表示する。

users/show.html.erb

・
・
<% if current_user.id == @user.id %>
  <div>
   <%= link_to '編集', edit_user_path(current_user.id)... %>
  </div>
<% end %>

別ユーザーの編集ページにURL直で遷移できないようにする

users_controller.rb

class UsersController < ApplicationContoller
  # 編集画面表示、修正内容の更新アクション実行時はログインしているユーザーの場合のみ実行可とする。
  before_action :correct_user, only: [:edit, :update]
  ・
  ・
  private
  def correct_user
    user = User.find(params[:id])
    if current_user != user
      redirect_to root_path
    end
  end
end

コントローラでヘルパーを使おう

Noteにも認証を追加しよう

NoteもUserと同様に自分が作成した投稿のみを編集できるように修正する。

notes_controller.rb

class NotesController < ApplicationController:Base
  before_action :correct_user, only: [:edit, :update]
  ・
  ・
  private
    def correct_user
     note = Note.find(params[:id])
     # belong_toのおかげでnoteオブジェクトからuserオブジェクトへアクセスできる。
     if current_user.id = note.user.id
       redirect_to root_path
     end
    end
end

userとnoteは認証方法が全く同じなので、ヘルパーを定義し、DRYな実装にリファクタリングする。

ログインユーザー判定ヘルパーを作成する

ヘルパークラスがモジュールである理由
ヘルパーに定義した関数はコントローラー、viewへの機能追加の意味を持つ。 よってクラスへインクルードできるmoduleで定義する。

action_helper.rb

module ApplicationHelper
  def current_user?(user)
    current_user.id == user.id
  end
end

自作ヘルパーのデフォルトスコープ

view: すべてのveiwで呼び出せる
controller: helperをinclude(機能追加)すれば呼び出し可能

ヘルパーのinclude

ヘルパーをインクルードする対象によって呼び出し可能なスコープが変化する。
〜Controller: 〜Controller内で呼び出し可能
ApplicationController: 全Controller内で呼び出し可能(ApplicationControllerは全Controllerで継承されているから)

アクションを移動しよう

ログイン後のみ、新規登録フォーム・投稿記事一覧を表示する対応を行う。
まず、トップ画面の表示コントローラーに新規登録と投稿記事一覧表示アクションを移動する。

移動対象のアクションは以下のnewとindex
notes_controller.rb

class NotesController < ・・・
  ・
  ・
  def new
    @note = Note.new
  end

  def index
    @notes = Note.all
  end
  ・
  ・
end

home_controller.rb.へ移動する。

class HomeController < ・・・
 ・
 ・
  def top
    # deviseのログイン状態返却メソッドでログイン時のみ、Noteの情報を取得する
    if user_signed_in?
      @note = Note.new
      @notes = Note.all
    end
  end
  ・
  ・
end

一覧を表示する順番を指定しよう

モデルより取得した情報を昇順、降順に並び替える。

  Note.all.order(created_at: :desc) #作成日の降順で並び替え
  Note.all.order(created_at: :asc)  #作成日の昇順で並び替え

orderの引数には、ハッシュの形でKeyに項目名、valueに並び替え方を設定する。
上記はcreated_at => :descを短く書く書き方

buildを使おう

Note生成時にログインユーザーのIDが自動設定されるように修正する。
記事投稿フォームからユーザーIDを削除する。
上記に伴い、作成アクションのstrongパラメータでユーザーIDを受け取らないように変更。

notes_controller.rb

class NotesController < ApplicationController
  def create
   @note = Note.new(note_params)
   ・
   ・
  end
  private
    def note_params
      params.require(:note).permit(:title, :content) # user_idを削除
    end
end

createメソッドでuser_idを設定する

class NotesController < ApplicationController
  def create
    # この時点ではuser_idは未設定
    @note = Note.new(note_params)
    # user_idをログイン情報から取得し、user_idのsetterで設定する
    @note.user_id = current_user.id
  end
end

buildを使ってuser_idを設定する

Note.newではuser_idは設定されないがbuildではuser_id(外部参照key)を自動セット。

class NotesController < ApplicationController
  def create
    # 以下は @note = Note.new(user_id: current_user.id)と同じ意味
    @note = current_user.notes.build
  end
end