はじめに
素人の戯言なんですが、
「フィルタ」と聞くとArray.filter
しか思いつかないんですよね。
(つまり、集合からの抽出)
Rails MVCのコントローラの文脈で「フィルタ」が出てきたので
「それはなんぞや」ということで調べました。
ついでに、MVCモデル周りでわからなかったことをまとめてます。
いつも通り書き捨ての文です。よろしくお願いします。
メモず
コントローラ
フィルタって?
コントローラのアクション前後に特定のメソッドを実行する機能のようです。
viewにおけるapplication.html.erb
ですね。
この「特定のメソッド・共通の処理」を「フィルタメソッド」と呼ぶらしいです。
(Rails独特の言い回し)
具体的には、以下の3つが当てはまります。
before_action(または before_filter):
- アクションが実行される前に呼び出されます。
- 認証チェック、パラメータの検証、セッションの確認などに使用されます。
after_action(または after_filter):
- アクションが実行された後に呼び出されます。
- レスポンスデータの後処理、ログ記録などに使用されます。
around_action(または around_filter):
- アクションの前後で実行されます。
- アクションの実行時間の計測や特定のリソースの管理などに使用されます。
ビュー
パーシャルって?
"partial"・・・"part"
「一部分」という意味。「一部分」を分離して作成すると使いまわせるよね?変更も楽だよね?ってこと。
分離したファイルを「パーシャルファイル」と呼ぶ。
パーシャルファイルは_
から始まる名前になる。例:_form.html.erb
<%= render "機能名" %>
で呼び出すことができる。例:<%= render "form" %>
locals
オプションを渡せる
例
<%# app/views/products/show.html.erb %>
<%= render partial: "products/product", locals: { product: @product } %>
<%# app/views/products/_product.html.erb %>
<%= tag.div id: dom_id(product) do %>
<h1><%= product.name %></h1>
<% end %>
locals
に渡したキーはlocal_assigns
ヘルパーメソッドでアクセスできる。
<%# app/views/products/show.html.erb %>
<%= render partial: "products/product", locals: { product: @product } %>
<%# app/views/products/_product.html.erb %>
<% local_assigns[:product] # => "#<Product:0x0000000109ec5d10>" %>
<% local_assigns[:options] # => nil %>
短く書きたい方へ
↑ コレクションを一つずつ表示する場合のショートハンド記法です。
個人的にはやりすぎだと思いますが・・・
改めて、「テンプレート」「パーシャル」「レイアウト」の違い
ざっくりとした理解
テンプレート:「ビューファイル(.html.erb)」そのもののこと
パーシャル:ビューを一部、別ファイルで定義すること。また、そのファイル(_
で始まる)
レイアウト:全体に共通するビューのこと。application.html.erb
に書く
GPTによる定義とか
テンプレート
- 定義: テンプレートは、通常、特定のアクションの応答として表示されるHTMLコンテンツを生成するためのファイルです。
- 用途: 各コントローラのアクションに対応するビューを提供します。例えば、
index
アクションには通常index.html.erb
テンプレートが使われます。- 特徴: テンプレートは、HTMLの構造を定義し、Rubyコード(ERBやHamlなど)を埋め込むことで動的なコンテンツを生成します。
パーシャル
- 定義: パーシャルは、再利用可能なビューの断片です。ファイル名はアンダースコア(
_
)で始まります(例:_form.html.erb
)。- 用途: ビューの共通部分(例:フォーム、ナビゲーションバー)をパーシャルに分離し、複数のテンプレート間で共有します。
- 特徴: パーシャルは、
render
メソッドを使用してテンプレートや他のパーシャルの中で呼び出されます。レイアウト
- 定義: レイアウトは、アプリケーションの全ページまたは特定のページ群に共通するHTMLの骨格を定義します。通常は
application.html.erbcation.html.erb
に定義されます。- 用途: ページ全体のHTML構造を定義し、ヘッダー、フッター、ナビゲーションなどの共通要素を含むことができます。
- 特徴: レイアウトはアプリケーション全体や特定のコントローラに適用され、各ビューテンプレートの内容は、レイアウトの
<%= yield %>
部分に挿入されます。
モデル
ORM・O/Rマッピング
オブジェクト / リレーショナルマッピングのこと。
オブジェクトをリレーショナルデータベースのテーブルに接続すること。
SQL書ける人を減らした・・・・・・というくらい便利な仕組み。
CRUD
データベース操作周りのヘルパー・コンベンション(慣例)
Create / Read / Update / Deleteの頭文字をとってCRUD
リレーション
クエリを表すオブジェクトのこと。
「これは即時にデータベースを問い合わせるのではなく、必要な時点(例えば、結果セットをイテレートする時)で初めてクエリが実行されます。」
RailsのActive Recordにおいては、「リレーション」は特定のクエリを表すオブジェクトを指します。これは、データベースのテーブルからデータを取得するためのクエリ構築を容易にするための抽象化です。Active Recordリレーションを使用すると、データベースクエリをメソッドチェーンを使って段階的に構築し、必要な時点で実際のデータベースクエリが実行されます。
たとえば、
User.where(active: true)
は、アクティブなユーザーのみを取得するクエリを表すActive Recordリレーションを返します。これは即時にデータベースを問い合わせるのではなく、必要な時点(例えば、結果セットをイテレートする時)で初めてクエリが実行されます。
スキーマって?
スキーマの視覚的な実体を示すものは、具体的には「データベーススキーマ図」や「ER図(エンティティー・リレーションシップ図)」などの形で表現されます。これらの図は、データベースのスキーマを視覚化するために用いられ、テーブル、フィールド、データタイプ、およびテーブル間の関連(リレーションシップ)を図示します。このような図はデータベース設計のプロセスで非常に重要な役割を果たし、データベースの構造を理解しやすくします。
スキーマの視覚的表現
- データベーススキーマ図: テーブルとそのカラム、データ型、およびテーブル間のリレーションシップ(例えば外部キーによる関連)を示します。
- ER図(エンティティ-リレーションシップ図): エンティティ(テーブルに相当)とその間のリレーションシップを図式化したものです。
スキーマの物理的な実体
- データベースのメタデータ: スキーマの「実体」として最も近いものは、データベースのメタデータです。このメタデータは、テーブルの構造、フィールド、データ型、制約などの情報を含みます。
- 設定ファイル: 特定のフレームワークやORM(オブジェクト関係マッピング)ツールでは、スキーマが設定ファイル(例えばRailsの
schema.rb
やマイグレーションファイル)に記述されます。
schema.rb
?マイグレーションファイル?関係は?
マイグレーションファイルを実行すると、「データベース」と「schema.rb
」の2つが更新される。
必要最低限のレベルでは、「マイグレーションファイル」と「データベース」があれば、schema.rb
はいらない子。
ただ、schema.rb
があると以下のメリットがある。つまり「便利だからあるもの」
現在のデータベーススキーマの明確な表現:
schema.rb
は、現在のデータベーススキーマの状態を正確に表現します。これにより、データベースの構造を一目で理解することができます。新しいデータベース環境の迅速なセットアップ:新しい開発環境をセットアップする際、
schema.rb
を使用してデータベーススキーマを一から再構築することができます。これは、特に複数のマイグレーションファイルが存在する大規模なアプリケーションにおいて、時間の節約になります。スキーマの一貫性の保証:
schema.rb
を使用することで、異なる開発環境やデプロイメント環境間でのスキーマの一貫性を保証できます。これにより、特定の環境でのみ発生する問題を回避できます。バージョン管理の簡素化:
schema.rb
は、データベーススキーマの現在の状態を単一のファイルで表すため、バージョン管理システム(例:Git)を用いて追跡しやすくなります。
マイグレーションを逆進(取り消し)可能にする
1.1 マイグレーションを逆進可能にするの内容ママ。
基本的にActive Recordが推測してくれるが、それができない場合(特殊な逆進)は、以下のように設定できる
class ChangeProductsPrice < ActiveRecord::Migration[7.1] def change reversible do |direction| change_table :products do |t| direction.up { t.change :price, :string } direction.down { t.change :price, :integer } end end end end
direction.up
は進める。direction.down
は逆進。
また、change
の代わりにup
・down
も可能。class ChangeProductsPrice < ActiveRecord::Migration[7.1] def up change_table :products do |t| t.change :price, :string end end def down change_table :products do |t| t.change :price, :integer end end end
インデックスとは?
インデックス導入前:
想定するシナリオ:「ユーザーテーブル」で特定の「ユーザー名」を検索する。
- データ検索の方法:データベースは「フルテーブルスキャン」を行います。これは、テーブル内のすべてのレコードを最初から最後まで順番に検索し、クエリの条件に合致するレコードを見つけるプロセスです。
- パフォーマンス:テーブルのサイズが大きくなるにつれて、検索に必要な時間は大幅に増加します。数百万レコードを含む大きなテーブルでは、単純な検索でも時間がかかることがあります。
- データの追加・更新・削除:これらの操作は比較的迅速に行われます。なぜなら、インデックスを更新する必要がないからです。
インデックス導入後:
想定するシナリオ:同じく「ユーザーテーブル」で特定の「ユーザー名」を検索するが、今回は「ユーザー名」カラムにインデックスが設定されている。
- データ検索の方法:データベースはインデックスを使用して検索を行います。インデックスは、特定の値がテーブル内のどこにあるかを迅速に指し示すことができるため、検索ははるかに効率的です。
- パフォーマンス:インデックスのおかげで、検索の速度は大幅に向上します。特に大規模なテーブルにおいて、この効果は顕著です。インデックスにより、データベースは関連するレコードを迅速に特定し、フルテーブルスキャンを行う必要がなくなります。
- データの追加・更新・削除:これらの操作はインデックスの導入前に比べて若干遅くなる可能性があります。インデックスはデータが変更されるたびに更新される必要があるため、追加の処理が発生します。
結論:
- インデックス導入のメリット:データの検索速度が大幅に向上します。これは、特に大きなデータセットにおいて、クエリのパフォーマンスを劇的に改善します。
- 考慮すべきトレードオフ:データの追加、更新、削除の速度が若干遅くなる可能性があります。また、インデックス自体が追加のストレージスペースを消費します。
具体例
図書館の本の整理:
カテゴリ分け:まず、本を大まかなカテゴリで分けます。例えば「文学」「科学」「歴史」などです。これがB-ツリーにおける「ルートノード」に相当します。
さらなる分類:次に、それぞれのカテゴリをさらに細かいセクションに分けます。「文学」なら「小説」「詩」「戯曲」などです。これがB-ツリーにおける「中間ノード」です。
具体的な棚:最後に、これらのセクション内で本を特定の順番(例えば著者名やタイトルでアルファベット順)に並べます。これが「葉ノード」、つまりB-ツリーの最終段階です。
B-ツリーにおける探索プロセス:
ルートノードの確認:探索はB-ツリーのルートノード(最上部のノード)から始まります。ルートノードには、子ノードが持つキーの範囲が含まれています。
キーの範囲に基づく分岐:例えば、ルートノードに「1-100」、「101-200」、「201-300」といった範囲が含まれているとします。IDが「1」のデータを探す場合、最初の範囲「1-100」に該当する子ノードへと分岐します。
中間ノードの探索:中間ノードでは、さらに細かいキーの範囲に基づいて次のノードへの分岐を決定します。例えば、このノードが「1-50」と「51-100」の範囲を持っていれば、「1」は「1-50」の範囲に該当します。
葉ノードへの到達:最終的に、探索は葉ノード(B-ツリーの最下層のノード)に到達します。葉ノードには具体的なデータレコードへのポインタが含まれており、ここでID「1」に対応するデータが見つかります。
マイグレーションの実行順
Railsはマイグレーションの実行順序をファイル名のタイムスタンプで決定するので、マイグレーションを他のアプリケーションからコピーする場合や、自分でマイグレーションを生成する場合は、実行順に注意する必要があります。
ポリモーフィック関連付けとは
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class Article < ApplicationRecord
has_many :comments, as: :commentable
end
class Photo < ApplicationRecord
has_many :comments, as: :commentable
end
この例では、:commentable
という枠組み(名前)を定義して、クラス同士を紐づけている。
なお、このとき自動的に:commentable_id
と:commentable_type
カラムを使用して識別される、ということになる。
この、「枠組み・名前・インターフェイス」の名前付き宣言をポリモーフィック関連付けと呼ぶ。
アソシエーションとは?
クラス同士の関連付けのこと。ポリモーフィック関連付けはアソシエーションの一種。
belongs_to
とhas_many
elongs_toを単独で利用すると、一方向のみの「1対1」つながりが生成されます。つまり上の例で言うと、「個別の書籍はその著者を知っている」状態になりますが、「著者は自分の書籍について知らない」状態になります。
双方向関連付けをセットアップするには、belongs_to関連付けを使うときに相手側のモデル(ここではAuthorモデル)にhas_oneまたはhas_many関連付けを指定します。
belongs_to
は、関連付けを無視することはできない
class Author < ApplicationRecord
has_many :books, dependent: :destroy
end
class Book < ApplicationRecord
belongs_to :author
end
このとき、author
を持たないBook.new
はできない(Rails5以降)。
スキーマダンプって?
schema.rb
のこと
スキーマダンプ(Schema Dump)とは、データベースのスキーマ(構造)を表す情報を含むファイルのことを指します。この用語を英語の原義から理解すると、以下のようになります:
スキーマ(Schema):データベースのスキーマは、データベース内のテーブル、カラム、関連付け、インデックスなどの構造を定義するものです。英語で「schema」という言葉は、一般的に「計画」や「図式」を意味し、この場合ではデータベース内のデータの構成や配置の「設計図」に相当します。
ダンプ(Dump):コンピューティングの文脈において、「dump」は、システムの一部分(通常はメモリやストレージ)の内容を別の場所に出力することを意味します。つまり、データや構造の完全なコピーを生成し、それを閲覧や保存、または他の場所での使用のために利用できる形にするプロセスです。
アプリケーションのデータベースの新しいインスタンスを作成する場合、マイグレーションの全履歴を最初から繰り返すよりも、単に
rails db:schema:load
でスキーマファイルを読み込む方が、高速かつエラーが起きにくい傾向があります。
yieldって?
原義は「与える」転じて「譲る」
「処理を譲る」という意味
yield
を含むメソッドに対し、ブロックを渡すことで、そのブロックをyield
部分で実行する。
例
def example_method
puts "メソッドの開始"
yield
puts "メソッドの終了"
end
example_method do
puts "ブロック内部の処理"
end
# 出力:
# メソッドの開始
# ブロック内部の処理
# メソッドの終了
終わりに
Rails特有の言い回しが多い!
Railsのちょっとどうなん?ポイントをまとめた記事も出します。
メモ記事が散らかってきたので、いずれはまとめようかな?