RailsでViewを作りこんでいくと、ifやeach、さらに変数を代入するだけの行とか出てきてしまってあまり綺麗なViewではなくなっていくとこがよくある。
ifとか文字列の連結を省略したいだけなら ActiveDecorator とかが便利
↑こうゆうやつ
でもブログのサイドバーみたいにサイト全体で使うViewがあったりすると、
- データはControllerで用意するの? => before_filter使うとか
- Viewから直接Modelは呼び出したくないよね。。
- そもそもViewファイルはどこに置けばいいんだろ? => views/layouts/_sidebar.html.erbとか?
- SidebarControllerを実装してサイドバーだけajaxでhtmlを取得するとか?
いろいろモヤモヤするとこがあって、あんまり最適解じゃない気がする。
でも Cells というgemを使うとViewの部品を小さなコントローラのような形で実装できるようになるのでスッキリ綺麗に書けて凄くイイネ!
インストール
Gemfileに以下を書いてbundle installするだけ
Gemfile
+ gem 'cells'
$ bundle install
ジェネレート
インストールするとジェネレータが追加されているので、cellの名前とアクション名を渡して作成出来る
$ bundle exec rails g cell sidebar show
ERB以外のテンプレートを使う場合は -e オプションを指定すればOK
$ bundle exec rails g cell sidebar show -e haml
生成したCellは app/cells にある
app ├── cells │ ├── sidebar │ │ └── show.html.haml │ └── sidebar_cell.rb
使ってみる
Cellを埋め込みたいViewの部分に render_cell を使うとレンダリングされる。引数は Cell名, アクション名
= render_cell :sidebar, :show | |
#main | |
article | |
%h1= @article.title | |
%div= @article.body |
Cellの中では普通にModelが呼べるので
こんなかんじでModelからデータを受け取ってインスタンス変数に入れておけばCellのViewで使えるようになる
%ul | |
- @recent_articles.each do |article| | |
%li= link_to article.title, article |
render_cellには3番目の引数があって、ここに渡したものはCellのアクションメソッドの引数に入るようになる
= render_cell :sidebar, :show, { hoge: 'this is hoge' } | |
#main | |
%article | |
%h1= @article.title | |
%div= @article.body |
もう少し便利に
このままだと通常のViewで使えるヘルパーメソッドは一切呼べないので、ApplicationCell を作って継承するようにしてる。
class ApplicationCell < Cell::Rails | |
helper ApplicationHelper | |
end |
helperというメソッドに使いたいヘルパーのモジュールを渡すと使えるようになる
また helper_method というメソッドも用意されていて、個別にヘルパーを追加できるようにもなってる。
自分はdeviseの current_user をCellのViewでも使いたかったので以下のようにしてみた
これで c.current_user とすれば呼び出せて、ログインしてたら編集ボタンを表示するようにできた
%ul | |
- @recent_articles.each do |article| | |
%li | |
= link_to article.title, article | |
- if c.current_user | |
%span= link_to '(編集)', edit_article_path(article) |
以前はSidebarControllerを実装してサイドバーのhtmlだけajaxで取得とかやってたこともあるけど、そもそもjsがオフってあると使えないし、Controllerはアプリケーションのリソースのためだけに使うようにしたいからこの方法がベストだと思う。
railsに取り込まれてもいいんじゃないかなぁ
0 コメント:
コメントを投稿