LoginSignup
1
1

More than 1 year has passed since last update.

[Rails]パーシャル内パーシャルのrender繰り返しを防ぐには

Last updated at Posted at 2021-10-16

ハマった点

投稿一覧ページに「いいねボタン」を設置する際、各投稿のパーシャルをrenderする際の繰り返しは、collectionオプションにて解決できた。

しかし、各投稿のパーシャルの中でrenderしているパーシャルにおいては、投稿の分だけrenderの繰り返しが発生してしまう。

 ↓実際のログ

このrenderのせいで、たった25件の投稿表示に1800ms以上の時間がかかってしまう。しかも、Ajaxによる非同期処理でいいねボタンの切り替えを実装しているため(DRYの観点でも)、いいねボタンをパーシャル化しなければならない。(他に方法があれば知りたいです!) 同じ状況の方も多いのでは?

解決策

renderのlayoutオプションyieldメソッドを使うことで解決した。

ER図

Screen Shot 2021-10-16 at 23.42.51.png

[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

↓ renderメソッドのlayoutオプションを使い、パーシャルに_like.htmlを指定。さらに、collectionにはpostsを指定する。

views/posts/index.html
.posts-wrap
  %div{ id: 'post-items' }
    = render partial: 'likes/like', layout: 'posts/post_layout', collection: @posts, as: :post

/ _post_layoutパーシャルは新たに作成します。

↓ yieldメソッドにて_like.htmlパーシャルを表示する。

views/posts/post_layout.html
%div{ id: "post-#{post.id}" }
  %div
    = post.id
    = post.content
    .post-likes{ id: "post-#{post.id}-likes" }
      = yield

/ このファイルはは新たに作成しています。

ログ

terminal
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メソッドについて理解を深めることができました。
解決までに時間がかかってしまったので、解決できた時は本当に感動しました。

初めての投稿で、わかりづらい点があるかもしれません。
意見、アドバイス等よろしくお願いします!

今後も学びのアウトプットをしていきたいと思います。

参考にした記事

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