7
7

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 2章 まとめ

Last updated at Posted at 2014-12-08
  • MVCアーキテクチャ
  • モデル
  • コントローラの役割
  • ビューの役割
  • MVCについてのまとめ

MVCアーキテクチャ

モデル


ActiveRecord::Relation

  • Query Interface による捜査結果をオブジェクトとして表現したもの
  • どんなSQLを発行するか、という情報だけを保持している
  • そのSQLの実行結果が必要になるタイミングまではDBアクセスを行うことはない

どういうことか?

動作
  • ActiveRecord に対してQuery Interface が呼ばれると ActiveRecord::Relation のインスタンスが生成される
  • 繰り返し呼び出した Query Interface は ActiveRecord::Relation のインスタンスに蓄積され、どんなSQLを発行するかの情報が更新されていく
  • 実際にデータが必要になった時点で、蓄積された情報を元にSQLを発行しデータを取得する
データが必要になったタイミングで初めて実行される理由

=> メソッドチェーンによるクエリ構築を行うため。

最初のメソッド呼び出し時に検索条件が自明でない場合もあります。
このような場合、組み立てた時点で実行されてしまうと複雑な条件や外部からの引数でSQLを切り替えたい場合に記述が難しくなってしまいます。
このような理由により、データが必要になったタイミングで実行されるようになっています。
(明示的に任意の箇所でクエリを発行したい場合には to_a を呼び出すなどを行うとできます。返却されるものはモデルのインスタンスの配列です。)

Scope

検索結果に名前をつけてひとまとめにしたもの。

  • クエリに名前をつけることで可動性が向上する
  • 重複コードが減る
scope :written_about, ->(theme) { where("name like ?", "%#{theme}%")}

バリデーション

エラーになったら、例えば book.errors とすることで取得できる

コールバック

  • before_validation
  • after_validation

コントローラ


ルーティングとリソース

bundle exec rake routes

で設定されているルーティング一覧を見ることができます。

resources について

resources は REST にしたがって endpointを作成してくれる。


resources :publishers

と書くと、RESTの統一インターフェースにしたがって

  • リソースの取得(GET)
  • リソースの作成(POST)
  • リソースの更新(PATCH(PUT))
  • リソースの削除(DELETE)

というendpointを作成する。

ちなみに、

resources :publisher do
  resources :books
    member do
      get 'detail'
     end
  end
end

こんなかんじで親子関係をルーティングすることができます。

resources 以外

resource :profile

一人のユーザーからみてアプリケーション上1つしか存在しないようなリソースの時にはこのように書くと便利です。
例えば、ログインユーザーが参照する自身のプロフィールなど。

表示と更新だけにしたいときとかそういう時には only を使って

resource :profile, only: %i{show edit update}

とかくと show, edit, update を呼び出すendpointのみ作成します。

例外処理

rescue_from

ApplicationController などに定義しておく。

rescue_from LoginFailed, with: :login_failed

def login_failed
  render template: 'shared/login_failed', status: 401
end

すると、ApplicationController を継承したクラス内で、raise したときに、rescue_from してある例外はキャッチしてくれる。

class LoginController < ApplicationController
 def create
   @user = User.where(name: params[:name], password: params[:password]).first
   raise LoginFailed unless @user
  end
end
StrongParameters とは
  • Mass Assignment 機能を利用する際に起こりうる脆弱性に対抗する手段の一つ。
  • Mass Assignment とはモデルの生成や更新の際に、以下の様なRubyのHashクラスを使って一括で属性を設定できる非常に便利な仕組み。

下記のようにすると、意図しない属性の変更を一般ユーザーに許してしまう。

user = User.find(1)
user.update(name: "Bob", email: "bob@example.com")

params[:user] には外部からどんな値も送られてきうる。(params はユーザーが送ってきたHTTPリクエストから組み立てられるものなので)

class ProfileController < ApplicationController
  def update
    user = current_user
    user.update(params[:user])
  end
end

これを防ぐための機構が StrongParameters です。
StrongParameters は Mass Assignment で、利用を許可する Hash の key を事前に検査する。

class ProfileController < ApplicationController
  def update
    user = current_user
    user.update(user_params)
  end

  private

    def user_params
      params.require(:user).permit(:name, :email)
    end
end

リクエストに :user という key が必要であることに注意。
上記のコードでは、user の中で受け付けても良いのは [:name, :email] の2つのkeyのみ。

require に指定したパラメータが params に含まれていなかった場合は、
ActionController::ParmeterMissing 例外が発生する。

StrongParameter が生まれた背景 = "mass assignment"

ビュー


テンプレートの検索

render :show

  • 描画するためのテンプレートを探す
  • 探されたテンプレートを基に、データを展開し、最終的なHTMLを生成する

どうやってcontrollerからの指定でviewファイルを探索しているのか?
=> RAILS_ROOT/app/views/コントローラ名/アクション名.html.erb

ex) app/controllers/books_controller.rb -> app/views/books/show.html.erb

render を省略した場合

def show
  @book = Book.find(params[:id])
end

コンテンツのタイプによって表示を出し分ける

HTML, JSON, XML などその他のフォーマットで表示させる。

class BookController
  def show
    @book = Book.find(params[:id])
    respond_to do |format|
      format.html
      format.csv
    end
  end
end

app/views/books/show.csv.erb
=> コントローラ名/アクション名.フォーマット.エンジン

format.xml { render xml: @book }

partialテンプレートとlayout

同じ内容を複数箇所で使いまわす。
-> :partial によって使いまわしたい部分を切り出せる。

partial: をつけると prefix _ で始まるファイル名のテンプレートから検索する。

テンプレートの構造化

app/views/layouts/ というディレクトリにレイアウト用のテンプレートを配置する。
デフォルトでは application.html.erb というファイルが用いられる。

  • pp/views/layouts/application.html.erb

<%= yield %>

こうするとそれぞれのページのコンテンツが展開されるので、

  • app/views/books/show.html.erb

^^ このファイルには body タグの中身だけ書けば良い。

variants によるテンプレートの切り替え

variants ... Rails 4.1 でテンプレートを切り替える機構として導入されたもの。

テンプレートエンジンの紹介

ERB

Ruby に標準添付されているテンプレートエンジン。
Railsでも標準のテンプレートエンジンとして採用されている。

<ul>
  <%= 3.times do |n| %>
    <li>Number = <%= n %></li>
  <% end %>
</ul>
Haml

railsで使いたいときには haml-rails
indentベース

%html
  %head
    %title Hi
  %body
    %h1 #header Header
    - 3.times do |i|
      %p Item
      %p= i
Slim

railsで使うには slim-rails
indentベース
Hamlよりもさらに簡素な表記が可能

doctype html
html
  head
    title Hi
  body
    h1 id="header" Header
    - 3.times do
      p Item

ヘルパー

url_for
url_for(controller: :users, action: :index)
# => /users

url_for(controller: :users, action: :index, id: 1234, detailed: 'true')
# => /users/1234?detailed=true
form_tag/form_for
  • form_tag ... 単純なフォームを作る
  • form_for ... モデルの情報を基に対応するフィールドの内容を埋めたり、エラーを表示したり
<% form_for(@publisher) do |f| %>

<% end %>
エスケープ処理

Railsのエスケープの仕組み。
XSSに対する対策がフレームワークとして組み込まれている。

そのまま出したいときには 'raw' を使う

<%= raw "<script>alert('sample');</script>" %>

raw ヘルパは内部的には String#html_safe というメソッドを読んで String オブジェクトを ActiveSupport::SafeBuffer のオブジェクトに変換している。

<%= "<script>alert('sample');</script>".html_safe %>

つまり、^^ともかける。

APIサーバにとってのビュー

最近ではJSONが主流。

  • format.json
json.extract! @book, :id, :name, :price, :created_at
  • "!" => 終わるメソッドはJSON化する
  • "!" => 終わらないメソッドはそのままJSONのキーになる。
json.name_with_id "#{@book.id} - #{@book.name}"

json.publisher do
  json.name @book.publisher.name
  json.addredd @book.publisher.address
end

unless @book.high_price?
  json.low_price true
end
7
7
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
7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?