Ruby on Railsの深堀り~アプリ作りの前に意識すること~


はじめに

初学者です。
アプリケーションを作る上で、前提に意識することや、根本的な考え方についてまとめていきます。

基本理念(根本的な考え方)

「DRY」無駄の無いコードを書く

Don't Repeat Yourself.
同じ情報を繰り返し書かない、定義しない。

  • 可読性の向上
  • コード量を減らすことでアプリケーションの動作が早くなる。
  • 修正工数が減る。
  • ミスによるバグも減らせる。

「CoC」フレームワークのルールに沿った実装を心掛ける

Convention Over Configuration.
ゼロから自分で設定するのではなく、Railsがあらかじめ用意してる規約を優先して作業する。

  • 「すでに定義されている処理を利用する」ことで、開発スピードが上がり質も担保される。
  • 規約は開発者同士の共通認識であり、可読性も向上する。

オブジェクト指向の確認

簡単にいうと「複数のオブジェクトを組み合わせてプログラムを構築する」というもの。
自分なりにまとめたものはこちら→オブジェクト指向

Railsにおける「モデル」「ビュー」「コントローラー」はそれぞれの役割を持ったオブジェクト。
Rails自体もオブジェクトの集合体といえる。

と、ここまでの学習でRailsについて学習しました。
ここからは、最後に少しだけ出てきた「MVC」についても深堀って行きます!

MVC

Model

モデルには「アソシエーションでテーブル間の関連性をもつ機能」や「バリデーションを組み、送られていたデータを検証する機能」、「データベースとRailsを繋ぐ機能」など多数存在する。
この機能を実行する裏では、Active Modelという仕組みが動いており、そのおかげで実現している。

Active Model

  • Railsにおける、モデルの機能を実現するために必要なオブジェクトのこと。
  • 保存前のデータの処理を検証する

モデルの処理は?

モデルの機能は、

  • データベースにデータを保存(Active Recordにより実現できてる)
  • 保存する前のデータを検証(Active Modelにより実現できてる)

などがある。
モデルは2つの仕組みから構成されていて、実装に使えるモジュールを提供している。
よく使うモジュールに焦点を当てて下記に記述する。

詳しくはRailsガイドを参照。Active Modelの基礎

Callbacksモジュール
データ保存時に、任意のタイミングで実行できるよう設定できるモジュール。
実行前(before)、実行後(after)、あるいは実行中(around: beforeとafterの両方)など、コールバックのタイミングが登録できる。

Validationsモジュール
データの保存時に検証するフィルターの役割を持つ。(Active Moduleのモジュール)
正しければ通して保存し、誤っていればはじいて保存させない。

Serializationモジュール
JSONなどのデータを編曲する値を整えてくれるモジュール。

例 とあるアプリのindexアクションにて

Controller
class TweetsController < ApplicationController
  def index
    @tweets = Tweet.includes(:user).order("created_at DESC")
    render json: @tweets
  end
end

この時のJSONの中身は以下の通り。

[
  {"id":2,"text":"太陽の写真","image":"data:image/sample","created_at":"2020-04-22T06:11:44.134Z","updated_at":"2020-04-22T06:11:44.134Z","user_id":1},
  {"id":1,"text":"綺麗な景色","image":"data:image/jpeg;base64,/9j","created_at":"2020-04-22T06:11:25.425Z","updated_at":"2020-04-22T06:11:25.425Z","user_id":1},
]

返却されている内容は「id, text, image, created_at, updated_at, user_id」。

もしSerializationモジュールを使用すると、これを限定的に制限ができる。

たとえば、JSONを受け取る側ではtextとimageしか必要がないとする。そんな時は、

Controller
class Tweet < ApplicationRecord

  def attributes
    {'text' => nil, 'image' => nil}
  end

  validates :text, presence: true
  belongs_to :user
  has_many :comments

  def self.search(search)
    if search != ""
      Tweet.where('text LIKE(?)', "%#{search}%")
    else
      Tweet.all
    end
  end

end

このattributesを追加すると、返却されるJSONは下記のように制限できる。

[
  {"text":"太陽の写真","image":"data:image/sample"},
  {"text":"綺麗な景色","image":"data:image/jpeg;base64,/9j"}
]

View

ビューは、コントローラーの処理後に実行される「HTMLなどのレスポンスをブラウザ上に表示する」という機能を持っている。
この機能を実行する裏ではAction Viewという仕組みにより動いている。(Railsが搭載している機能)

Action Viewとは?

  • Railsにおいて、ビューの機能を実現するのに必要な処理のまとまり(オブジェクト)のこと。
  • ビューの機能の裏で実は動いている。
  • ERBの実行に必要。 ビューファイルの.html.erbという拡張子を持っていて、これはテンプレートエンジンのERBを使っている。 このERBもAction Viewの仕組みに含まれている。

ControllerとViewの関係

まず最初に初心者あるあるな考え方だと思うのですが、「ビューファイルがそのままブラウザにポンと表示されているわけではない」です。この認識ができてるかできてないかでもMVCの流れが少しわかるような気がします!

ブラウザに表示されているのは確かです。でもその裏では処理が実行されています。

ブラウザに返却されるビューを生成するファイルは、app/viewsディレクトリに作ります。
詳細を話すと、上記のディレクトリにコントローラー名と同じディレクトリを作成し、その下にビューファイルを作ります。

これによって、コントローラーとビューが関連付けれらました!
その関連づいたビューファイルに、+レイアウト+部分テンプレートなどが全部組み合わさって、ブラウザに表示されています。
つまり、ビューファイルの内容がAction Viewによってまとめられ、ブラウザに返却される役目をになってくれています。

インスタンス変数の動き

ControllerとViewの関係につながりますが、コントローラーでは@tweets = Tweet.allのようにインスタンス変数を定義することがあります。
このインスタンス変数はビューファイル内でも使えます。でもこれもインスタンス変数がすぐに表示されているわけではないんです。
コントローラーで取得した@tweetsは、Railsの裏側で定義された複数のメソッドを通して読み替えられます。
そしてAction Viewに渡され、再びビューファイルのインスタンス変数としてセットされて、ようやく使えるという仕組みです。

Controller

コントローラーは、「ルーティングによって処理されたリクエストを受け取り、ビューファイルなどをレスポンスとして返却する」という機能を持っている。
この機能の実現に、Action Controllerという仕組みが動いている。(Railsが搭載している機能)

Action Controllerとは?

  • Railsにおいて、コントローラーの機能を実現させるために必要なオブジェクトのこと。

コントローラーの役目は?

  • リクエストの処理
    「どのコントローラーで、どのアクションを実行するか」の判断をする。
    これは、コントローラー内のアクションによって呼ばれるメソッドが実行されている。
    (例: index→一覧ページ表示、 show→詳細ページ表示 など)

  • アクション
    アクションは、リクエストに対する処理の実行後、最終的なレスポンスを返却する。
    ※注意点
    コントローラーは「コントローラーの役目がわかるように、整理された状態を保つ」ことが大切とされています。
    場合によってはモデルなどへ切り出すこともあります。どのような場合かというと、検索や計算などの「細かいデータの処理」を行う場合です。
    あくまでコントローラーは「リクエストを受け取り、レスポンスを返す」のが役目だからです。「何がレスポンスで返却されるのか」が分かりづらくなってしまうことは避けましょう!

「何がレスポンスで返却されるのか」を意識するためにも、レスポンスについて深堀りましょう!

  • レスポンス レスポンスにはHTMLなどのビューファイルを返却する「レンダリング」や、「JSON」というデータを返却する場合がある。

レンダリング
指定したHTMLなどのビューファイルを画面に表示すること。(index.html.erbなどのビューファイルを画面に表示すること)

「JSON」
データを扱うフォーマットのこと。
「JSON」のいい点は、

  • 動作が軽い
  • モダンなフロント言語と親和性が高く管理しやすい

7つのアクションを使う場合
index,show,new,create,edit,update,destroyの7つのアクションがある。
例えばindexアクションに対するレスポンスは、自動的にindex.html.erbに設定される。

TweetsController
class TweetsController < ApplicationController
 def index
  # index.html.erbがレスポンスとして返却される
 end
end

render template:を使う場合
今度は自分の好きなファイルを呼び出したい場合。
renderメソッドを用いて返却するHTMLファイルを指定する。

TweetsController
class TweetsController < ApplicationController
 def render_top_page
   render template: "tests/index"
 end
end

render jsonを使う場合
最後に「JSON」、つまりデータの返却を指定したい場合。

PostController
class PostsController < ApplicationController
  def create
    post = Post.create(content: params[:content], checked: false)
    render json:{ post: post }
  end

json:{ post: post }のように指定すると、{ post: post }というデータをJSON形式で返却することができる。
※書き方は一例です!
他にもあるので気になる方はrenderメソッドを調べると良いかと。