【before_actionって？】Ruby on Rails初心者に向けて

どうも！
三町哲平です。
MacBook Airを触り出して２週間、扱いにもだいぶ慣れてきました。

さて今回は、
[Ruby on Rails5 学習コース VIII | プログラミングの入門なら基礎から学べるProgate[プロゲート]](https://prog-8.com/lessons/rails5/study/8class) 
で勉強中にこれなんだったっけ？というソースコードを見つけました。

```ruby:users_controller.rb
class UsersController < ApplicationController
  before_action :authenticate_user, {only: [:index, :show, :edit, :update]}
  before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]}
  before_action :ensure_correct_user, {only: [:edit, :update]}
...
...
...
end
```
今回はこのソースコードを深掘りしていきます。

```ruby:users_controller.rb
class UsersController < ApplicationControlle
```
まずソースコードの上記部分からの説明で、これを一言で説明すると「classの継承」をしています。

## 継承とは?

>継承は、既存のクラスから、新しく作ったクラスに「変数定義」や「メソッド」などを引き継ぐことです。継承される既存のクラスを「スーパークラス（親クラス）」、継承した新しく作ったクラスを「サブクラス」といいます。
引用元:[オブジェクト指向「継承」とは？わかりやすく解説してみた | 侍エンジニア塾ブログ（Samurai Blog） - プログラミング入門者向けサイト](https://www.sejuku.net/blog/9598)

つまり今回の場合、
__ApplicationControllerクラス__を__UsersControllerクラス__へ継承しているということになる訳です。

## ApplicationControllerクラスとは？
>異なるコントローラ間で共通に使用するメソッドは, ApplicationControllerクラスで定義します。各コントローラは, 原則としてApplicationControllerを継承しているのでここ(app/controllers/application.rb)で定義すればどのコントローラでも使えます。
引用元:[Railsで共通メソッドの作り方 - 線路は続くよどこまでも。](https://whitech0c0late.hatenablog.com/entry/20120128/1327759552)

Ruby on Rails5の学習をしていたのですが、これはRailsのControllerという機能に関係するのですが、Controllerとは、ルーティングに関わる機能です。

# before_actionとは？
アクションを実行する前に処理を実行したい場合に使用します。

users_controller.rbを実行する前に下記の内容を実行することになります。

```ruby
:authenticate_user, {only: [:index, :show, :edit, :update]}
:forbid_login_user, {only: [:new, :create, :login_form, :login]}
:ensure_correct_user, {only: [:edit, :update]}
```
ちなみに、__:authenticate_user__の部分は、メソッドにあたります。

そして、残りのソースコードは、下記の部分ということになりますが、

```ruby
{only: [:index, :show, :edit, :update]}
{only: [:new, :create, :login_form, :login]}
{only: [:edit, :update]}
```
まず、__only:__の部分ですが、これはオプションにあたります。
before_actionには様々なオプションを付けることができる訳ですね。

## onlyオプションとは？

特定のアクションのときだけbefore_actionを使いたい場合はonlyを使います。

つまり、

* authenticate_userメソッド → index, show, edit, updateアクションのみで使用可
* forbid_login_userメソッド → new, create, login_form, loginアクションのみで使用可
* ensure_correct_user → edit, updateアクションのみで使用可

このような意味だった訳ですね。

それを踏まえた上で、users_controller.rbの隠れていた部分も含め表示してみましょう！

```ruby:users_controller.rb
class UsersController < ApplicationController
  before_action :authenticate_user, {only: [:index, :show, :edit, :update]}
  before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]}
  before_action :ensure_correct_user, {only: [:edit, :update]}
...
...
...
end
```
↓

```ruby:users_controller.rb
class UsersController < ApplicationController
  before_action :authenticate_user, {only: [:index, :show, :edit, :update]}
  before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]}
  before_action :ensure_correct_user, {only: [:edit, :update]}
  
  def index
    @users = User.all
  end
  
  def show
    @user = User.find_by(id: params[:id])
  end
  
  def new
    @user = User.new
  end
  
  def create
    @user = User.new(
      name: params[:name],
      email: params[:email],
      image_name: "default_user.jpg",
      password: params[:password]
    )
    if @user.save
      session[:user_id] = @user.id
      flash[:notice] = "ユーザー登録が完了しました"
      redirect_to("/users/#{@user.id}")
    else
      render("users/new")
    end
  end
  
  def edit
    @user = User.find_by(id: params[:id])
  end
  
  def update
    @user = User.find_by(id: params[:id])
    @user.name = params[:name]
    @user.email = params[:email]
    
    if params[:image]
      @user.image_name = "#{@user.id}.jpg"
      image = params[:image]
      File.binwrite("public/user_images/#{@user.image_name}", image.read)
    end
    
    if @user.save
      flash[:notice] = "ユーザー情報を編集しました"
      redirect_to("/users/#{@user.id}")
    else
      render("users/edit")
    end
  end
  
  def login_form
  end
  
  def login
    @user = User.find_by(email: params[:email], password: params[:password])
    if @user
      session[:user_id] = @user.id
      flash[:notice] = "ログインしました"
      redirect_to("/posts/index")
    else
      @error_message = "メールアドレスまたはパスワードが間違っています"
      @email = params[:email]
      @password = params[:password]
      render("users/login_form")
    end
  end
  
  def logout
    session[:user_id] = nil
    flash[:notice] = "ログアウトしました"
    redirect_to("/login")
  end
  
  def ensure_correct_user
    if @current_user.id != params[:id].to_i
      flash[:notice] = "権限がありません"
      redirect_to("/posts/index")
    end
  end
  
end
```
引用元:[Ruby on Rails5 学習コース VIII | プログラミングの入門なら基礎から学べるProgate[プロゲート]](https://prog-8.com/lessons/rails5/study/8class) 

__該当するアクションが全て含まれていることが確認できます！__

### さいごに
before_actionのonlyオプション意外のオプションも知りたいという方は、こちらの参考サイトもご参照ください。
[【Rails】before_actionの使い方を徹底解説！ | Pikawaka - ピカ1わかりやすいプログラミング用語サイト]
(https://pikawaka.com/rails/before_action#before_action%E3%81%AE%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3)