Rails Tutorialで学べることメモ-第13章-
Rails Tutorial を改めてしっかりやり直してのメモ第 13 章編
https://railstutorial.jp/chapters/user_microposts?version=7.0
便利なコマンド・メソッド
belongs_to
, has_many
ActiveRecord に存在するメソッドで、引数にとった ActiveRecord モデルと自身を関連づける。
Rails ではこの関連付けを利用して、外部キーを明示的に指定せずに正しい関連のレコードを作成することができる。
micropost = Micropost.new(content: "Lorem ipsum", user_id: @user.id) # これは素直な書き方
micropost = @user.microposts.build(content: "Lorem ipsum") # railsが勝手にuser_idを入れてくれる
order
SQL のORDER_BY
句を発行できるメソッド。
デフォルトでは昇順(ascending, 古い方が先頭に来る)並びになる。
Rails4.0 より前は生の SQL を書くしかなかったらしいが、最近では次のように書ける。
order('created_at DESC') # Rails4.0より前はこのように書くしかなかった
order(created_at: :desc) # Rubyの書き方で書けるようになった
time_ago_in_words(date)
time_ago_in_words(3.weeks.ago)
は21 days
のようにいい感じの文字表示にしてくれる。
take
引数分のレコードを取得する。引数なしの場合は最初の 1 件を取得。
first
と似ているが、first
は何も指定がなければプライマリキーでソートした 1 件目を返す。
fixture_file_upload
テストのfixture
内で定義されたファイルをアップロードする処理を模擬できる特別なメソッド。
active_storage_validations
ActiveStorage で取り扱うファイルに対してバリデーションを簡単に実装できる gem
content_type
やsize
などで制限をかけることができる。
知識
複合キーインデックス(Multiple Key Index)
インデックスを複数列に対して作成すること。
指定の順番が大事で、カーディナリティが高い列を先頭に持ってきた方が良い。
カーディナリティはデータのバリエーションを表す概念で、例えば性別カラムが「男」「女」「不詳」だけを取る場合、カーディナリティ 3 と考える。
インデックスは基本 B-tree インデックスが利用される。詳しく知らなくても、木構造のイメージで分岐がたくさんあるものを先にざっくり絞った方が効率よくデータにたどり着けそうな感覚は理解できる。
このチュートリアルの場合、microposts
はユーザーごと、それも投稿日時順などで取得することが多いことが明確なので、add_index :microposts, [:user_id, :created_at]
は上記の説明で納得できる。
ラムダ記法
->
はブロックを引数に取り、Proc
というオブジェクトを返す。
このProc
またはlambda
(無名関数)オブジェクトはcall
メソッドが呼ばれたときにブロックの処理を評価する。
例えばdefault_scope
のように値ではなく、処理を設定したい場合に使われる。
関連の依存
has_many
のような所有の関連付けを行う際、自身が削除されたら子モデルをどのように扱うかを指定できる。
例えばhas_many :microposts, dependent: :destroy
としたら、自身が消えたときに関連づいたmicroposts
は全て一緒に削除される。
count
メソッドの処理
DB のレコードを全て読み出してlength
を呼ぶような処理はしていない。
DB の機能を利用して計算されたレコード数を取得するような動きになる。
SQL インジェクション
例えば、リクエストで受け付けた値を利用して次のような生の SQL を実行する処理を考える。
user = User.where("id=#{params[:id]}")
4 章で出た式展開を利用した記述で、一見よさそうに見える。処理の意図としては、id で指定されたユーザー情報を取得するシンプルなものになっている。
しかし、ここで悪意あるリクエストとして次のような値が送信されるとする。
params[:id] = '3 OR 1=1'
これが先ほどの記述で実行されると、発行される SQL は次のようになる。
SELECT "users".* FROM "users" WHERE (id=3 OR 1=1)
WHERE
句の評価式はOR
以降が常にtrue
となるため、この SQL は全ての User 情報を取得する。
このように、実装意図と違う命令が注入されてしまう攻撃を SQL インジェクションと呼ぶ。
一般に発生する上記のような攻撃を防ぐために、エスケープ処理を実施する必要がある。
Rails の場合、生の SQL を実行しない書き方では何らかの対策が行われており、生で書く場合も次のような記述ができる。
user = User.where("id = ?", params[:id])
このように?
を書き、そこにparams[:id]
が入るような書き方をすることで、例えば先ほどの悪意ある値が入っても次の SQL が実行される。
SELECT "users".* FROM "users" WHERE (id='3 OR 1=1')
id が3 OR 1=1
という値のレコードは存在しないので、空の結果が返るだけになる。
referrer
HTTP 仕様にある HTTP referer は、そのページやリソースに「どこから要求が来たか」を示す。
referer というのは誤字だったが、HTTP がこのままで普及してしまったがゆえに直せないらしい。
ActiveStorage
画像、平文テキスト、PDF、音声ファイルなど様々なファイルをモデルに紐づけて保存する仕組み。
次のコマンドで Rails アプリケーションに追加できる。
rails active_storage:install
MIME タイプ
コンテンツの形式を表す識別子。
Wiki がかなりいい情報量でまとまっているのは初めて知った。
https://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%87%E3%82%A3%E3%82%A2%E3%82%BF%E3%82%A4%E3%83%97
まとめ
Rails を取り扱う大筋はここまでの章で完了しているため、目新しいことは ActiveStorage の扱い程度だったが、その分 SQL をはじめとして、Web アプリケーションに共通して必要な知識の新規情報が多い内容だった。
特にラムダやインデックスのようにサラッと流すにはよくわからんけど、しっかり理解しようとするとかなり時間がかかるトピックが混じっているので生真面目だと挫折する可能性がある。
自分が 2 年前とかにやってたら挫折してたかもなぁと感じつつ、今ならある種の流し方も何となくわかる。流し方みたいなのは時間と一定の経験があってこそ自分流で身につくものなので、この手の学習は本当に最初のハードルが高いなと改めて感じた。