[Ruby on Rails] rails初学者がつまずきがちなポイントをレベル別に紹介！

#はじめに
こんにちは！<font color="Red">DMM WEBCAMP Advent Calendar 2021</font> :christmas_tree: 16日目担当の@naoyuki0920です。

今回は日ごろメンターとして質問対応をしていく中で、質問の多いポイントがいくつかありましたので、メンター視点で書いていきたいと思います。もしかしたら、皆さんが実装している方法とは異なる部分もあるかもしれませんが、こんな方法もあるんだー程度でぜひ参考にしてみてください。

それではレッツゴー！！

#目次
- [つまずきレベル1](#つまずきレベル1-)
 - [renderとredirect_to](#render-と-redirect_to)
 - [MVCとは？](#mvcとは)
- [つまずきレベル2](#つまずきレベル2-)
 - [form_withで指定するmodelとは？](#form_withで指定するmodelとは)
 - [eachメソッドについてもっと詳しく](#eachメソッドについてもっと詳しく)
- [つまずきレベル3](#つまずきレベル3-)
 - [フォロー・フォロワー機能の仕組み](#フォローフォロワー機能の仕組み)
- [さいごに](#さいごに)

#つまずきレベル1 ★☆☆
まずはRailsを学習し始めて最初につまずきがちなポイントです！
###render と redirect_to
まず初めにrenderとredirect_toをチョイスしました。この違い、皆さんきちんと理解できておりますでしょうか？他人に自分の言葉で説明できますか？ちょっと怪しいと思ったそこのあなた！復習のチャンスです！

一言で違いを言うならば、コントローラーを新たに呼び出すか、呼び出さないかです。

>**render**はrenderを記述したコントローラを使ってrender先のViewを表示する
>**ridirect_to**は、指定したパスが示すコントローラーのアクションを起動し、Viewを表示する

言葉で説明するとこんな感じです。わかりやすいように図を載せます。

![render.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2299375/c25655d6-7808-55cf-f8b9-39efc412cdad.jpeg)

いかがでしょうか？イメージわきましたか？今ははっきりイメージできなくても、使い分けていくうちにそれぞれの特徴をつかめると思います。renderとredirect_toはそれぞれ、指定するものや記述方法、使う際の注意点などがいろいろありますので、詳しくは`render redirect_to 違い`などで調べてよりわかりやすい説明を見つけてみましょう！

###MVCとは？
意外と見落としがちなMVCですが、Railsで開発を進めていくうえで必要不可欠です。Railsだけでなく、様々なアプリケーションでMVCを基本とした開発が行われています。これを機に復習しましょう！

MVCとはモデル（**Model**）、ビュー（**View**）、コントローラー（**Controller**）の頭文字をとった言葉です。アプリケーションでは様々なデータを扱うと同時に、ユーザーの操作に合わせたアクションを行います。これらの管理をするための司令塔の代表みたいなものです。**三権分立**（立法権、行政権、司法権）に少し似ていますね。

これも先ほどと同様図を載せて説明しますね。

![MVC.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2299375/7da0665e-f740-c8aa-cce2-9c170b662da7.jpeg)


どうでしょうか視覚的にイメージできましたか？目に見える部分と目に見えない部分、その2つをつなぐ部分という役割分担によってアプリケーションは出来上がっているのですね。MVCのほかにもMVPモデルやMVVNなどもありますが、RailsではMVCを使用しています。これからはMVCを意識してデータの動きや変数の受け渡しを考えて実装してみましょう！

#つまずきレベル2 ★★☆
続いて実際にアプリケーションを作成している途中にあれ？ってなりがちなポイントを押さえていきましょう！
###form_withで指定するmodelとは？
意外と見落としがちですよね。きちんと説明できますか？
まず、form_with内のmodelとは**モデルオブジェクト**のことを指しています。モデルオブジェクトは、form_withを使って新規にデータを投稿したり、データを更新したいテーブルのカラムを指すことが多いです。
>新規投稿する際のmodelは`.new`を付けたインスタンス変数
>編集する際のmodelは`.find(params[:id])`で探索を行ったインスタンス変数

主にこの2つをform_withのmodelに渡します。
form_withを使う目的によってmodelに渡す内容は変化するので、form_withの目的を意識して実装するとわかりやすいです。
このことを意識しておくだけで、form_withを使う際のハードルがぐっと下がるので意識してみましょう！

###eachメソッドについてもっと詳しく
webサイトを作成するときに繰り返し処理を行いたいときありますよね。データベースの情報を複数取得して一覧表示したいときなどによく使います。今一度確認しておきましょう。

eachメソッドを使う際のテンプレートを紹介します。


```:user/index.html.erb
<% @users.each do |user| %>
  <%= user.id %>
  <%= user.name %>
  <%= user.email %>
<% end %>
```
こんな感じになりますね。ざっくり流れを見ていきます。

>1．usersコントローラーのindexアクション内で定義した`@users`というインスタンス変数をViewが受け取る。
>2．受け取ったインスタンス変数の中身をデータベースのレコード単位で取り出し、Viewのeach文内だけで使えるローカル変数`user`に代入する。
>3．eachメソッドをインスタンス変数が所持しているレコード数だけ繰り返し、Viewとして出力する。

このような流れでViewを表示しています。データの流れを意識しながらコーディングできるようになるとより上達できるかと思います。ぜひ意識してみてください。

#つまずきレベル3 ★★★
ここからはRailsをある程度学習し、よりレベルの高い機能を実装しようとしている方向けです。私も、受講生さんにわかりやすいイメージを伝えるのが難しいなと感じる部分です。では行きましょう！

###フォロー・フォロワー機能の仕組み
昨今のSNSには必ずといっていいほど搭載されている機能ですね。実装の大まかな流れを解説します。またすでにuserモデルやテーブルは存在しているものとして進めます。今回紹介するもの以外の実装方法もたくさんあるのであしからず。

>1．ユーザーとユーザーをつなげるためのrelationshipsテーブルとモデルを作成。
>2．userモデルとrelationshipsモデルにアソシエーションを記述
>3．userモデルにフォロー機能のメソッドを定義する。
>4．relationshipsコントローラーの作成、編集

####1. relationshipsモデルの作成
まず初めにuserとuserをつなぐための中間テーブルを作成します。
`rails g model relationships`を実行しmigrationファイルを作成し編集しましょう。
migrationファイルは以下の通りです。

```ruby:db/migrate/~_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[5.2]
  def change
    create_table :relationships do |t|
      t.references :user, foreign_key: true
      t.references :follow, foreign_key: { to_table: :users }

      t.timestamps

      t.index [:user_id, :follow_id], unique: true
    end
  end
end
```
referencesという見慣れないものが出てきました。これは**既に存在しているテーブルを指定する場合**に使用します。`t.references :user`がさしているのは既存のuserテーブルだということですね。foreign_keyとはデータベースの外部キー制約の事です。詳しい説明は省きますので興味があれば調べてみましょう。

`rails db:migrate`の実行を忘れずに！

####2. アソシエーションの設定
続いて先ほど作成したrelationshipsモデルとuserモデルのアソシエーションを設定します。

```ruby:relationships.rb
class Relationship < ApplicationRecord
  belongs_to :user
  belongs_to :follow, class_name: 'User'
  validates :user_id, presence: true
  validates :follow_id, presence: true
end
```

ここで、あれ？となった方。大丈夫です。followモデルは作成していません。`belongs_to :follow, class_name: 'User'`について少し補足しますね。`class_name: 'User'`とすることで、Userモデルを参照できるようになります。followモデルは実体のない仮想上のモデルというイメージです。

それって`belongs_to :user`と同じじゃない？ってなりますよね。なぜこんな回りくどいやり方をするかについてはもう少し進むとわかります。いったん先に進みますね。

次はuserモデルのリレーションです。

```ruby: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

  # フォローしている人
  has_many :relationships
  has_many :followings, through: :relationships, source: :follow
  
  # フォロワー
  has_many :reverse_of_relationships, class_name: 'Relationship', foreign_key: 'follow_id'
  has_many :followers, through: :reverse_of_relationships ,source: :user
end 
```
上の方から順番に行きますね。
まずはフォローの設定から。
`has_many :relationships`
これは大丈夫ですね。いつも通りのデータベースのリレーションを定義しています。

`has_many :followings, through: :relationships, source: :follow`
これは少し難しいですね。また見知らぬモデル`followings`が登場しました。これも先ほどのfollowモデルと同じ存在です。

`through: :relationships`は中間テーブルがrelationshipsだよと宣言しています。中間テーブルとはテーブルとテーブルを結ぶためのテーブルの事です。

次にフォロワーの設定です。
`has_many :reverse_of_relationships, class_name: 'Relationship', foreign_key: 'follow_id'`
うわまたかよ…って思うかもしれないですが、これもたった今新しく作成したモデルです。followとは逆のフォローされる関係になるのでreverse_of_をつけてあるだけです。ただ、勝手にモデルを作ることはできないので、`class_name: 'Relationship'`を使ってrelationテーブルを参照するように設定しています。

`foreign_key: 'follow_id'`についてですが、これを追加することによって、`@user.followings`を使うことができるようになります。


####3. Userモデルでフォロー・アンフォロー機能の設定
次にUserモデルにメソッドを追記していきます。

```ruby: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

  # フォローしている人
  has_many :relationships
  has_many :followings, through: :relationships, source: :follow
  
  # フォロワー
  has_many :reverse_of_relationships, class_name: 'Relationship', foreign_key: 'follow_id'
  has_many :followers, through: :reverse_of_relationships ,source: :user
  
  def following?(another_user)
    self.followings.include?(another_user)
  end

  def follow(another_user)
    unless self == another_user      
      self.relationships.find_or_create_by(follow_id: another_user.id)
    end
  end
  
  def unfollow(another_user)
    unless self == another_user
      relationship = self.relationships.find_by(follow_id: another_user.id)
      relationship.destroy if relationship
    end
  end
end 
```
こんな感じになります。書き方はいくつもあるので、ご自身が好きな書き方で実装してみてください！

####4. relationshipsコントローラーの作成編集
続いて、コントローラーを作成、編集します。

```ruby:relationships_controller.rb
class RelationshipsController < ApplicationController
  before_action :authenticate_user!
  def create
    @user = User.find(params[:user_id])
    current_user.follow(@user)
    redirect_to request.referer
  end

  def destroy
    @user = User.find(params[:user_id])
    current_user.unfollow(@user)
    redirect_to request.referer
  end
end
```
こんな感じになるかと思います。説明は省きますね。
ここまで来たら、あとはViewとrouteを作成するだけです。気合で頑張りましょう。

いかがでしょうか。このような感じで実装すると、フォローフォロワー機能を作成することができます。
やはりポイントになってくるのが、データベースに対する理解ですね。中間テーブルなど、フォローフォロワー機能には複数のデータベースの知識が必要になります。データベースに関する資格があるくらいですので、とても奥が深いです。もし興味があれば、ぜひデータベースについて勉強してみましょう！

#さいごに
ここまで初学者の方が躓きがちなポイントをいくつか紹介してきました。複雑な処理を実装するためにはとても多くの経験と知識が必要になると考えています。皆さんの実装したいアプリケーションにこの記事が少しでも参考になれば幸いです。また、今回紹介しきれなかったものについても、少し調べるとたくさんの記事が見つかるはずです。ぜひ調べて、ともにどんどん成長していきましょう！
それでは最後までお付き合いいただきありがとうございました！あなたのRailsライフが充実することを願っています！！