【rails】viewのerbファイルをslim化パーシャル化
この記事を読んでいるということはみなさんrailsで何かしらのサービスを作っていることでしょう。どうでしょうか、進捗は順調でしょうか。
そしてどうでしょうか。そろそろerb
ファイル、読む気が失せてきたのではないでしょうか。僕は読みたくなくなりました。少なくとももう<>
を見たくない。
というわけで今回はviewの憎きerb
ファイルを撲滅し、シンプルで読みやすいslim
ファイルへ移行する方法について書こうと思います。
(slim
化が思いのほか簡単だったのでついでにパーシャルもやってみました。)
erbは目が痛い
htmlに準じた記法であるerb
。コードが少ないうちは特に気にならないですね。
<!DOCTYPE html> <html> <head> <title>About | Ruby on Rails Tutorial Sample App</title> </head> <body> <h1>TimeLine</h1> <% @posts.each do |post| %> <ul> <li>投稿ID:<%= post.id %></li> <li>投稿者:</li> <li>投稿:<%= post.text_content %></li> </ul> <% end %> </body> </html>
この頃はまだそんなに気になってなかったんですが、これが最近だとこうなりました。
<!DOCTYPE Html> <html> <head> <title>About | Ruby on Rails Tutorial Sample App</title> </head> <body> <% if !session[:login_id] %> <p>ログインしてください。</p> <p><%= link_to "ログイン", login_path %></p> <% else %> <h1>TimeLine</h1> <p><%= link_to "投稿する", new_post_path %></p> <ul> <% @posts.each do |post| %> <% if post.sharing.present? %> <%= User.find(post.user_id).account_id %>さんがシェア <% share_post_id = post.id %> <% post = post.sharing %> <% end %> <li> <%= link_to User.find(post.user_id).account_id, user_path(id: post.user_id) %> <%= post.created_at.strftime("%Y-%m-%d%H:%M:%S") %> </li> <p> <% if post.replying.present? %> to: <%= link_to User.find(post.replying.user_id).account_id, user_path(id: User.find(post.replying.user_id).id) %><br> <% end %> <%= post.content %><br> </p> <p> <%= link_to "詳細", post_path(id: post.id) %> <%= link_to "返信", new_post_path(reply: {replying_id: session[:login_id], main_post_id: post.id}) %>: <%= post.replied.length %><br> <% if post.shared.map(&:user_id).include?(session[:login_id]) %> <%= link_to "シェア", destroy_share_path(post: {id: post.id, share_post_id: share_post_id}) %>: <%= post.shared.length %><br> <% else %> <%= link_to "シェア", share_path(post: {id: post.id}) %>: <%= post.shared.length %><br> <% end %> <% if post.likes.find_by(user_id: session[:login_id]).present? %> <%= link_to "いいね", like_path(id: post.likes.find_by(user_id: session[:login_id]).id, like: {post_id: post.id}), method: :delete %>: <%= post.likes.length %> <% else %> <%= link_to "いいね", likes_path(like: {post_id: post.id}), method: :post %>: <%= post.likes.length %><br> <% end %> </p> <% end %> </ul> <% end %> </body> </html>
コードの拙さは一旦置いといて、流石にちょっと読みづらい。なんというか、全体的にトゲトゲしてて目が痛い。
というわけで早速slim
の方を導入していきたいと思います。
slim化する
やることは以下の2ステップです。
Gemfile
に記述を追加する- サーバーを再起動する
とてもシンプルですね。
1. Gemfile
に記述を追加する
Gemfile
に以下の2行を追加します。
gem 'slim-rails' gem 'html2silm'
僕はここでハイフン(-)をアンダースコア(_)で書いていて10分ほどハマったのでしっかり確認しましょう。
2. サーバーを再起動する
すでにサーバーを立ち上げている方はCtrl + c
で一度サーバーを止めましょう。
そしてサーバーを再起動します。
rails s
これで全てのerb
ファイルがslim
ファイルに変換されているはずです。
確認
早速さきほどの目が痛かったerb
ファイルを確認してみましょう。
doctype html html head title | About | Ruby on Rails Tutorial Sample App body - if !session[:login_id] p | ログインしてください。 p = link_to "ログイン", login_path - else h1 | TimeLine p = link_to "投稿する", new_post_path ul - @posts.each do |post| - if post.sharing.present? = User.find(post.user_id).account_id | さんがシェア - share_post_id = post.id - post = post.sharing li = link_to User.find(post.user_id).account_id, user_path(id: post.user_id) = post.created_at.strftime("%Y-%m-%d %H:%M:%S") p - if post.replying.present? | to: = link_to User.find(post.replying.user_id).account_id, user_path(id: User.find(post.replying.user_id).id) br = post.content br p = link_to "詳細", post_path(id: post.id) br = link_to "返信", new_post_path(reply: {replying_id: session[:login_id], main_post_id: post.id}) | : = post.replied.length br - if post.shared.map(&:user_id).include?(session[:login_id]) = link_to "シェア", destroy_share_path(post: {id: post.id, share_post_id: post.shared.find_by(user_id: session[:login_id]).id}) | : = post.shared.length br - else = link_to "シェア", share_path(post: {id: post.id}) | : = post.shared.length br - if post.likes.find_by(user_id: session[:login_id]).present? = link_to "いいね", like_path(id: post.likes.find_by(user_id: session[:login_id]).id, like: {post_id: post.id}), method: :delete | : = post.likes.length - else = link_to "いいね", likes_path(like: {post_id: post.id}), method: :post | : = post.likes.length br
はい、ちょっとシンタックスが効かないみたいなので色がつかないんですが、かなりすっきりしたような気がしますね。
これで晴れてerb
の目の痛さからも解放されました!
パーシャル化(おまけ)
あまりにも簡単にslim
化できてしまったのでこの際ついでにパーシャル化もしてしまおう!という雑な魂胆です。お付き合いください。
パーシャルをざっくり説明すると、viewファイルの一部を別ファイルに切り出し、それをテンプレートとして元のviewファイルからテンプレートファイルを呼び出して表示することです。
百聞は一見に如かず
自分でも何言ってるかよくわからなかったので実際のコードを書いてみます。
元のviewファイルは先ほどslim
化したapp/view/posts/index.html.slim
を例としてみていきます。
以下が元のapp/view/posts/index.html.slim
ファイルです。
※シンタックスが効いていないですがもうしばらくお付き合いください。
doctype html html head title | About | Ruby on Rails Tutorial Sample App body - if !session[:login_id] p | ログインしてください。 p = link_to "ログイン", login_path - else h1 | TimeLine p = link_to "投稿する", new_post_path ul - @posts.each do |post| - if post.sharing.present? = User.find(post.user_id).account_id | さんがシェア - share_post_id = post.id - post = post.sharing li = link_to User.find(post.user_id).account_id, user_path(id: post.user_id) = post.created_at.strftime("%Y-%m-%d %H:%M:%S") p - if post.replying.present? | to: = link_to User.find(post.replying.user_id).account_id, user_path(id: User.find(post.replying.user_id).id) br = post.content br p = link_to "詳細", post_path(id: post.id) br = link_to "返信", new_post_path(reply: {replying_id: session[:login_id], main_post_id: post.id}) | : = post.replied.length br - if post.shared.map(&:user_id).include?(session[:login_id]) = link_to "シェア", destroy_share_path(post: {id: post.id, share_post_id: post.shared.find_by(user_id: session[:login_id]).id}) | : = post.shared.length br - else = link_to "シェア", share_path(post: {id: post.id}) | : = post.shared.length br - if post.likes.find_by(user_id: session[:login_id]).present? = link_to "いいね", like_path(id: post.likes.find_by(user_id: session[:login_id]).id, like: {post_id: post.id}), method: :delete | : = post.likes.length - else = link_to "いいね", likes_path(like: {post_id: post.id}), method: :post | : = post.likes.length br
このファイルのul
行以下からは@posts
で渡された複数のpost
を一覧表示する処理になっています。
いまの状態だとposts.html.slim
ファイルがごちゃごちゃしてみづらいですし、ul
以下はテンプレート化しておけば他の部分でも使い回す機会があるかもしれません。
というわけで、この部分をテンプレート化(パーシャル化)してみましょう。
パーシャル化するには以下のステップを踏みます。
- パーシャルとして参照用のファイルを作成する
- (元ファイルに)パーシャルを参照する処理を書く
早速見ていきましょう。
1. パーシャルとして参照用のファイルを作成する
元のファイル(app/view/posts/index.html.slim
)のul
以下の処理を切り出し、app/view/posts/_posts_list.html.slim
として保存します。
以下がapp/view/posts/_posts_list.html.slim
です。
ul - @posts.each do |post| - if post.sharing.present? = User.find(post.user_id).account_id | さんがシェア - share_post_id = post.id - post = post.sharing li = link_to User.find(post.user_id).account_id, user_path(id: post.user_id) = post.created_at.strftime("%Y-%m-%d %H:%M:%S") p - if post.replying.present? | to: = link_to User.find(post.replying.user_id).account_id, user_path(id: User.find(post.replying.user_id).id) br = post.content br p = link_to "詳細", post_path(id: post.id) br = link_to "返信", new_post_path(reply: {replying_id: session[:login_id], main_post_id: post.id}) | : = post.replied.length br - if post.shared.map(&:user_id).include?(session[:login_id]) = link_to "シェア", destroy_share_path(post: {id: post.id, share_post_id: post.shared.find_by(user_id: session[:login_id]).id}) | : = post.shared.length br - else = link_to "シェア", share_path(post: {id: post.id}) | : = post.shared.length br - if post.likes.find_by(user_id: session[:login_id]).present? = link_to "いいね", like_path(id: post.likes.find_by(user_id: session[:login_id]).id, like: {post_id: post.id}), method: :delete | : = post.likes.length - else = link_to "いいね", likes_path(like: {post_id: post.id}), method: :post | : = post.likes.length br
パーシャルとなるファイルには、_
から始まる名前をつけるのがルールとなっています。
簡単ですが、これでテンプレートとなるパーシャルの準備は完了です。
2. (元ファイルに)パーシャルを参照する処理を書く
続いて元のファイル(app/view/posts/index.html.slim
)にパーシャルを参照する処理を書きます。
パーシャルを参照する元のファイルは以下のようになります。
doctype html html head title | About | Ruby on Rails Tutorial Sample App body - if !session[:login_id] p | ログインしてください。 p = link_to "ログイン", login_path - else h1 | TimeLine p = link_to "投稿する", new_post_path = render 'posts_list'
とても簡潔になりました。
最後の行に注目してください。
さっきまでul
が書いてあった部分に= render 'posts_list'
という処理が追加されています。
これがパーシャルを参照する処理になります。
_○○.html.slim
というパーシャルを呼び出す際には、= render '○○'
のように書きます。_
が省略されることに注意してください。
以上でパーシャルの呼び出しは完了です。
結果的には= render 'posts_list'
の行から先はapp/view/posts/_posts_list.html.slim
の処理が読み込まれるため、元のファイルと全く同じview画面が作成されます。
パーシャルまとめ
パーシャルとしてコードを分けることのメリットには以下のようなものがあると思います。
- コードが簡潔になることで可読性が上がる
- 機能単位でパーシャルを作成することで他のページでも簡単に機能を使い回すことができる
- 複数のページで利用される機能をパーシャルでまとめることで、修正時の修正箇所を抑えることができる
あまりにも細かく分けすぎるのもそれはそれでファイル管理が煩雑になってしまうため考えものですが、基本的に適度に使う分には便利な機能だと思います。
全体まとめ
気がつけばおまけのパーシャルについての方がボリュームが出てしまってますね。まぁそんなこともあります。
slim
もパーシャルもストレスなくコードを読むためには便利な機能ですので、ぜひ試してみてください。