[Rails]パーシャル内パーシャルのrender繰り返しを防ぐには
ハマった点
投稿一覧ページに「いいねボタン」を設置する際、各投稿のパーシャルをrenderする際の繰り返しは、collectionオプションにて解決できた。
しかし、各投稿のパーシャルの中でrenderしているパーシャルにおいては、投稿の分だけrenderの繰り返しが発生してしまう。
↓実際のログ
このrenderのせいで、たった25件の投稿表示に1800ms以上の時間がかかってしまう。しかも、Ajaxによる非同期処理でいいねボタンの切り替えを実装しているため(DRYの観点でも)、いいねボタンをパーシャル化しなければならない。(他に方法があれば知りたいです!) 同じ状況の方も多いのでは?
解決策
renderのlayoutオプションとyieldメソッドを使うことで解決した。
ER図
[NGパターン] renderの繰り返しが発生するrenderの使い方
コントローラー
posts_controller.rb
def index
@posts = Post.All # 今回はN+1問題などは考慮しません
end
View
views/posts/index.html
%div
= render partial: 'posts/shared/post', collection: @posts, as: :post
views/posts/shared/_post.html
%div
= post.id
= post.content
.post-likes{ id: "post-#{post.id}-likes" }
= render 'likes/like', post: post
views/likes/_like.html
- if post.already_liked?(current_user) # 「いいね」済みならtrueを返すメソッド
= link_to post_like_path(post, post.likes), mehod: :delete, remote: true do
%font
.fas.fa-heart.likes-heart-already
- else
= link_to post_likes_path(post), method: :post, remote: true do
%font
.far.fa-heart
%span{ id: "post-#{post.id}-likes-count" }
= post.likes.count
ログ
terminal
web_1 | ↳ app/controllers/application_controller.rb:36
web_1 | Rendering posts/index.html.haml within layouts/application
web_1 | Rendered likes/_like.html.haml (7.7ms)
web_1 | Rendered likes/_like.html.haml (0.6ms)
web_1 | Rendered likes/_like.html.haml (0.6ms)
web_1 | Rendered likes/_like.html.haml (0.5ms)
〜省略〜
web_1 | Rendered likes/_like.html.haml (0.6ms)
web_1 | Rendered likes/_like.html.haml (0.4ms)
web_1 | Rendered likes/_like.html.haml (0.4ms)
web_1 | Rendered collection of posts/shared/_post.html.haml [25 times] (663.9ms)
web_1 | Rendered posts/index.html.haml within layouts/application (690.5ms)
web_1 | Completed 200 OK in 1847ms (Views: 1791.0ms | ActiveRecord: 3.4ms)
[OKパターン] renderの繰り返しが発生しないrenderの使い方
コントローラー
posts_controller.rb
# コントローラは改善前と同じです。
def index
@posts = Post.All # 今回はN+1問題などは考慮しません
end
View
def index
@posts = Post.All # 今回はN+1問題などは考慮しません
end
%div
= render partial: 'posts/shared/post', collection: @posts, as: :post
%div
= post.id
= post.content
.post-likes{ id: "post-#{post.id}-likes" }
= render 'likes/like', post: post
- if post.already_liked?(current_user) # 「いいね」済みならtrueを返すメソッド
= link_to post_like_path(post, post.likes), mehod: :delete, remote: true do
%font
.fas.fa-heart.likes-heart-already
- else
= link_to post_likes_path(post), method: :post, remote: true do
%font
.far.fa-heart
%span{ id: "post-#{post.id}-likes-count" }
= post.likes.count
web_1 | ↳ app/controllers/application_controller.rb:36
web_1 | Rendering posts/index.html.haml within layouts/application
web_1 | Rendered likes/_like.html.haml (7.7ms)
web_1 | Rendered likes/_like.html.haml (0.6ms)
web_1 | Rendered likes/_like.html.haml (0.6ms)
web_1 | Rendered likes/_like.html.haml (0.5ms)
〜省略〜
web_1 | Rendered likes/_like.html.haml (0.6ms)
web_1 | Rendered likes/_like.html.haml (0.4ms)
web_1 | Rendered likes/_like.html.haml (0.4ms)
web_1 | Rendered collection of posts/shared/_post.html.haml [25 times] (663.9ms)
web_1 | Rendered posts/index.html.haml within layouts/application (690.5ms)
web_1 | Completed 200 OK in 1847ms (Views: 1791.0ms | ActiveRecord: 3.4ms)
コントローラー
# コントローラは改善前と同じです。
def index
@posts = Post.All # 今回はN+1問題などは考慮しません
end
View
↓ renderメソッドのlayoutオプションを使い、パーシャルに_like.htmlを指定。さらに、collectionにはpostsを指定する。
.posts-wrap
%div{ id: 'post-items' }
= render partial: 'likes/like', layout: 'posts/post_layout', collection: @posts, as: :post
/ _post_layoutパーシャルは新たに作成します。
↓ yieldメソッドにて_like.htmlパーシャルを表示する。
%div{ id: "post-#{post.id}" }
%div
= post.id
= post.content
.post-likes{ id: "post-#{post.id}-likes" }
= yield
/ このファイルはは新たに作成しています。
ログ
web_1 | ↳ app/controllers/application_controller.rb:36
web_1 | Rendering posts/index.html.haml within layouts/application
web_1 | Rendered collection of likes/_like.html.haml [25 times] (33.6ms)
web_1 | Rendered posts/index.html.haml within layouts/application (61.2ms)
web_1 | Completed 200 OK in 343ms (Views: 295.7ms | ActiveRecord: 2.9ms)
1847msも要していたアクセス時間を343msまで短縮することができました!(正確には短縮ではないですが)
おわり
なんとなく理解した気でいたrenderメソッドとyieldメソッドについて理解を深めることができました。
解決までに時間がかかってしまったので、解決できた時は本当に感動しました。
初めての投稿で、わかりづらい点があるかもしれません。
意見、アドバイス等よろしくお願いします!
今後も学びのアウトプットをしていきたいと思います。
参考にした記事
Author And Source
この問題について([Rails]パーシャル内パーシャルのrender繰り返しを防ぐには), 我々は、より多くの情報をここで見つけました https://qiita.com/Naoya225/items/c4d282ce6c526e1ef798著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .