0
0

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 1 year has passed since last update.

【Rails】部分テンプレートに気をつけたい話

Posted at

こんにちは。

この前部分テンプレート関連でちょっと想定外のエラーに出くわしたので、記事にしてみました。

実行環境は以下の通りです

  • Ruby3.1.0
  • Rails7.0.2.2

どんな問題?

別リソースのコントローラからviewファイルをrenderするとき、renderするviewファイルの中で部分テンプレートを呼び出している時に発生する問題です。

簡単にいうと部分テンプレートの呼び出し方には少し注意しましょうということですが、文字の説明だけだととても分かりにくいのでイメージとコードで説明していきます

具体的なコードとエラー内容

例えば店舗の詳細ページで、ステータス変更の処理があったとします。
さらに、詳細ページには他の店舗一覧の表示をしているとします(部分テンプレートで実装)
↓以下イメージ
7c1bc31c2571ec548451c3a1a2af3343.gif

詳細ページのコードは以下のようになってます

↓コントローラ

shops_controller.rb
class ShopsController < ApplicationController
  # 他のアクションは略

  def show
    @shop = Shop.find(params[:id])
    @related_shops = Shop.order(created_at: :desc).limit(3).where.not(id: @shop)
  end
end

↓showのviewファイル

views/shops/show.html.slim
p style="color: green" = notice

== render @shop

= button_to 'openにする', shop_shop_status_path(@shop), method: :patch, class: 'btn btn-primary btn-sm'

div.mt-2
  = link_to "Edit this shop", edit_shop_path(@shop)
  ' |
  = link_to "Back to shops", shops_path

  = button_to "削除する", @shop, method: :delete, class: 'btn btn-danger btn-sm mt-2'

div.mt-3 style="background-color: #eee;"
  p 部分テンプレートエリア
  / ここに注目
  = render partial: 'shop', collection: @related_shops

↓shopの部分テンプレート

views/shops/_shop.html.slim
div id="#{dom_id shop}"
  p
    strong 店舗名:
    = shop.name

そしてステータス変更のコントローラは以下のようにしていたとします

shop_statuses_controller.rb
class ShopStatusesController < ApplicationController
  def update
    @shop = Shop.find(params[:shop_id])
    if @shop.update(status: 'open')
      redirect_to @shop, notice: 'Openに変更しました'
    else
      @related_shops = Shop.order(created_at: :desc).limit(3).where.not(id: @shop)
      render 'shops/show', status: :unprocessable_entity
    end
  end
end

「ステータス変更だけならrender処理する必要ないじゃん」という意見が聞こえてきそうですが、いったんスルーしてください。例えば日付入力などが必要だとして入力値を保持させたいケースなどを想定していて、説明用にシンプルな構造にするためにこのようにしています(単に面倒だったということもありますが

このコードで普通にステータス変更に成功する場合は、問題なく動作します

試しに失敗のケースの動作チェックをしてみましょう(以下のようにして強制的に失敗処理を実行)

- if @shop.update(status: 'open')
+ if @shop.update(status: 'open') && false

これで更新処理しようとするとエラーになります
スクリーンショット 2022-06-26 11.23.46.png

Missing partial shop_statuses/_shopと言われているので、どうやら更新処理をするコントローラ名と同じshop_statusesディレクトリ内でテンプレートファイルを探しているようです。

個人的にはshops/show.html.slimのviewファイル内で呼び出している部分テンプレートなんだから、viewファイルの呼び出し元がどこであれ部分テンプレートはshops/_shop.html.slimを読み込むはずと思っていましたがそうではないみたいですね

解決策

ちゃんとパスを指定すれば直ります

- = render partial: 'shop', collection: @related_shops
+ = render partial: 'shops/shop', collection: @related_shops

補足ですが、collectionオプションの省略形で書くとなぜか問題なく動作しました

= render @related_shops

Rails6のアプリでやったときはこの形ではダメだった気がするんですが、7からよしなにやってくれるようになったんですかね(うーん謎🤔)

Rails6だとダメだったよーとか、省略形だと内部的にどんな動きをしてるよーとか補足情報あればコメントいただけると嬉しいです。

さいごに

エラー内容を読むとなんてことはない問題なんですが、こういう仕様になっているという参考になれば幸いです。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?