日頃のコードレビューの言語化です。
前提
- Ruby on Railsのバージョンとしては6ぐらいを想定しています
- viewの記述にはerbを想定しております。
よくあるケース
例えば下記のようなテーブル構成をしているModelがあるとする
create_table "users", force: :cascade do |t| t.string "uid", null: false t.string "name", null: false t.string "image_url", null: false t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false end create_table "posts", force: :cascade do |t| t.bigint "owner_id" t.string "title", null: false t.text "homepage_url", null: false t.text "message", null: false t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.index ["owner_id"], name: "index_posts_on_owner_id" end
class User < ApplicationRecord has_many :posts end
class Post < ApplicationRecord belongs_to :user, foreign_key: :owner_id end
そしてviewで以下のように記述したくなる事がある。
<div> 最後の投稿は「<%= @user.posts.last.title =>」でした! </div>
このような場合にもし、@user
に対応するPostのレコードが1つもないと nil.last
ということをやろうとしてエラーになってしまう。
解決策の一例
このような場合、 @user.posts.last.title
が取得できないことを検知して、その内容を返せばいいので、ぼっち演算子( .&
)を活用する。
今回の例では present?
を利用する。 present?
はnilに対しても備え付けられているメソッドなので、ぼっち演算子と一緒に利用しやすい
<% if @user.posts.last.title.present? %> <div> 最後の投稿は「<%= @user&.posts&.last&.title =>」でした! </div> <% endif %>
こうすることで、@user.posts
がnilだったとしても後続には続くため、最後の present?
まで正しく動作をしてくれる。
他のアプローチ
どちらかというとViewでnilになりうる構造のデータを取り扱うこと自体がかなり使い勝手を悪くしている話でもあるので、ControllerやHelper、Decoratorなどの層を活用してなるべくerbなどviewのレイヤーで長いメソッドチェインを利用する記述を減らす方が肝要ではあります。