LoginSignup
0
1

More than 3 years have passed since last update.

Ruby on Rails6 実践ガイド cp13~cp15 【メモ】

Last updated at Posted at 2020-06-09

はじめに

この記事の筆者はプログラミングを学習し始めたばかりの初心者です。間違いがあれば指摘していただけると幸いです。

概要

この記事はRuby on Rails6 実践ガイドを読んで学んだことを自分用のメモとして記録したものです。抜粋してピックアップするので読みづらいと思われます。すいません。
この本には、続編の機能拡張編もあり、記事を書いている段階で二冊とも学習を終えています。復習もかねて記事を書いていくつもりです。
18のチャプターに分かれているので、見出しごとに区切っていきます。

前の記事
Ruby on Rails6 実践ガイド cp4~cp6 【メモ】
Ruby on Rails6 実践ガイド cp7~cp9 【メモ】
Ruby on Rails6 実践ガイド cp10~cp12 【メモ】

Chapter 13 モデル間の関連付け

リソースがネストされているかどうかで処理を切り替える

routes.rb
resources :staff_members do
  resources :staff_evnets, only: [ :index ]
end
resources :staff_events, only: [ :index ]

上のようなルーティングが設定されている時、

staff_events_controller.rb
def index
  if params[:staff_member_id]
    @staff_member = StaffMember.find(params[:staff_member_id])
    @events = @staff_member.events.order(occurred_at: :desc)
  else
    @events = StaffEvent.order(occurred_at: :desc)
  end
end

URLパスにstaff_member_idが含まれるかどうかで処理を切り替えることができます。特定の職員のイベントの場合とすべてのイベントの場合のどちらも同じアクションで処理することができます。


render collection

= render partial: "event", collection: @events

テンプレート内でrenderメソッドのcollectionオプションに配列を指定して呼び出すと、配列の要素の数だけ部分テンプレートが繰り返し埋め込まれます。

詳しく調べて記事を書きました。
Viewでの繰り返しをコレクションをレンダリングすることで実装する【Rails】


N+1問題

クエリの回数を減らせるにもかかわらず、取得したいオブジェクトの個数に1を加えた回数のクエリが発行されてしまうことをN+1問題といいます。

includes

@events = @events.includes(:member)

includesメソッドに対して関連付けの名前を与えると、関連付けられたモデルオブジェクトを一括して取得するクエリが発行されるようになります。
その結果、発行されるクエリの回数が減り、多くの場合でパフォーマンスの向上につながります。

Chapter 14 値の正規化とバリデーション

値の正規化

正規化のためのメソッド

models/concern/string_normalizer.rb
require "nkf"

def normalize_as_text(text)
  NKF.nkf("-W -w -Z1", text).strip if text
end

def normalize_as_furigana(text)
  NKF.nkf("-W -w -Z1 --katakana", text).strip if text
end

NKFモジュールは日本語特有の変換機能を提供します。nkfメソッドは第一引数にフラグ文字列、第二引数に変換対象の文字列をとり、変換後の文字列を返します。

フラグ 意味
-W 入力の文字コードがUTF-8であることを指定
-w UTF-8で出力する
-Z1 全角の英数字、記号、全角スペースを半角に変換する
--katakana ひらがなをカタカナに変換する

フラグ文字列一覧

フラグ文字列は連結して書くことができます。

NKF.nkf("-WwZ1", text)

stripメソッドは文字列の先頭と末尾にある空白文字列を除去します。

before_vallidation

モデルオブジェクトに対してバリデーション、保存、削除などの操作が行われる前後に実行される処理をコールバックまたはフックといいます。
before_validationはバリデーションの直前に実行されます。

before_validation do
  self.family_name = normalize_as_name(family_name)
  self.family_name_kana = normalize_as_furigana(family_name_kana)
end

上の例では、バリデーションが実行される前に名前とフリガナに対して正規化を行っています。


Gem data-validaor

data-validatorはdataタイプのバリデーションを提供します。

オプション チェックする内容
after 指定された日付より後。ただし、指定された日付は含まない。
before 指定された日付よりも前。ただし、指定された日付は含まない。
after_or_equal_to 指定された日付よりも後。ただし、指定された日付を含む。
before_or_equal_to 指定された日付よりも前。ただし、指定された日付を含む。
allow_blank trueをしてすれば空欄が許可される
before: -> (obj) { 1.year.from_now.to_date }

dateタイプのバリデーションでは、Procオブジェクトを指定すると動的に基準となる日付を指定することができます。

before: 1.year.from_now.to_date

上のように書いても動きますが、beforeキーの値が起動時を基準にして固定されてしまうので、予想外の結果を引き起こします。


validate

validate do
  unless Staff::Authenticator.new(object).authenticate(current_password)
    errors.add(:current_password, :wrong)
  end
end

validateは、組み込みバリデーション以外の方法でバリデーションを実装するときに利用します。

Chapter 15 プレゼンター

プレゼンターとは

あるオブジェクトに関連するHTMLコードを生成する役割を担うクラスをプレゼンターと呼びます。
Railsの公式用語ではなく、Railsコミュニティの中で生まれた概念です。


モデルプレゼンター

対象がモデルオブジェクトの場合のプレゼンターです。

app/presenters/model_presenter.rb
class ModelPresenter
  attr_reader :object, :view_context

  def initialize(object, view_context)
    @object = object
    @view_context = view_context
  end
end

ModelPresenterクラスを継承したStaffMemberPresenterクラスを定義します。

staff_member_presenter.rb
class StaffMemberPresenter < ModelPresenter

  # 職員の停止フラグのon/offを表現する記号を返す
  def suspended_mark
    object.suspended? ?
      view_context.raw("&#x2611;") :
      view_context.raw("&#x2610;")
  end
end

使用例

staff_members/index.html.haml
- @staff_members.each do |m|
  - p = StaffMemberPresenter.new(m, self)
  - p.suspended

StaffMemberPresenterのインスタンスを作成しています。第一引数にStaffMemberオブジェクト、第二引数にselfを指定しています。
ビューテンプレート内でselfによって参照されるオブジェクトをビューコンテキストと呼びます。このオブジェクトはRailsで定義されたすべてのへルパーメソッドを自分のメソッドとしてもっています。


委譲

委譲を用いるとコードを簡潔に書くことができます。

model_presenter.rb
  delegate :raw, to: :view_context
staff_member_presenter.rb
  delegate :suspended?, to: :object

delegateメソッドは引数に指定された名前のインスタンスメソッドを定義し、toオプションに指定されたメソッドが返すオブジェクトに委ねます。

要するにメソッドを呼び出すときにレシーバーを省略できるようになります。
delegateを定義した結果、下のように簡潔に書くことができるようになりました。

staff_member_presenter.rb
  def suspended_mark
    suspended? ? raw("&#x2611;") : raw("&#x2610;")
  end

HtmlBuilderモジュールとフォームプレゼンターについては省略します。


続き

続きの記事のURLも順次追加していきます。

Ruby on Rails6 実践ガイド cp16~cp18 【メモ】
Ruby on Rails6 実践ガイド[機能拡張編] cp3~cp6 【メモ】
Ruby on Rails6 実践ガイド[機能拡張編] cp7~cp9 【メモ】
Ruby on Rails6 実践ガイド [機能拡張編] cp10~cp12 【メモ】

引用元

※マークダウンの引用を用いている部分は以下の書籍から引用しています。
Ruby on Rails6 実践ガイド

0
1
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
0
1