2013年6月15日土曜日

[Rails3] サイドバーの実装には Cells が便利

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
class SidebarCell < Cell::Rails
def show
render
end
end
view raw sidebar_cell.rb hosted with ❤ by GitHub

使ってみる

Cellを埋め込みたいViewの部分に render_cell を使うとレンダリングされる。引数は Cell名, アクション名

= render_cell :sidebar, :show
#main
article
%h1= @article.title
%div= @article.body
view raw show.html.haml hosted with ❤ by GitHub

Cellの中では普通にModelが呼べるので

class SidebarCell < Cell::Rails
def show
@recent_articles = Article.recents
render
end
end
view raw sidebar_cell.rb hosted with ❤ by GitHub

こんなかんじでModelからデータを受け取ってインスタンス変数に入れておけばCellのViewで使えるようになる

%ul
- @recent_articles.each do |article|
%li= link_to article.title, article
view raw show.html.haml hosted with ❤ by GitHub

render_cellには3番目の引数があって、ここに渡したものはCellのアクションメソッドの引数に入るようになる

= render_cell :sidebar, :show, { hoge: 'this is hoge' }
#main
%article
%h1= @article.title
%div= @article.body
view raw show.html.haml hosted with ❤ by GitHub
class SidebarCell < Cell::Rails
def show(arg)
@hoge = arg[:hoge]
render
end
end
view raw sidebar_cell.rb hosted with ❤ by GitHub

もう少し便利に

このままだと通常のViewで使えるヘルパーメソッドは一切呼べないので、ApplicationCell を作って継承するようにしてる。

class ApplicationCell < Cell::Rails
helper ApplicationHelper
end

helperというメソッドに使いたいヘルパーのモジュールを渡すと使えるようになる

また helper_method というメソッドも用意されていて、個別にヘルパーを追加できるようにもなってる。
自分はdeviseの current_user をCellのViewでも使いたかったので以下のようにしてみた

class ApplicationCell < Cell::Rails
helper ApplicationHelper
helper_method :c
def c
parent_controller
end
end
view raw sidebar_cell.rb hosted with ❤ by GitHub

これで 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)
view raw show.html.haml hosted with ❤ by GitHub

以前はSidebarControllerを実装してサイドバーのhtmlだけajaxで取得とかやってたこともあるけど、そもそもjsがオフってあると使えないし、Controllerはアプリケーションのリソースのためだけに使うようにしたいからこの方法がベストだと思う。
railsに取り込まれてもいいんじゃないかなぁ

0 コメント:

コメントを投稿