Railsでviewを作成する際、部分テンプレートとして
partialメソッドを利用しない日はないと思います。
ですが、このpartial、あくまでビューに特化した機能なので、
ロジックをwrapして部分テンプレート化しようとすると、非常に煩雑。
以下に想定される利用シーンとcellを利用した解決策をメモがてら残しておきます。
Cellsの利用シーンの具体例
- ログインポップアップ
- サイドメニューのランキング表示
- 最近流行りのフッダーにお問い合わせフォームを置くやつとか。
など、全てのページでよく使われる部分パーツなどが
具体的な利用シーンで上げられます。
たとえばログインポップアップで言うと、
以下のようなpartialの読み出しをします。
- unless user_signed_in?
.header
.header__login-button
= link_to 'ログインする', 'javascript:void(0);'
= render partial: 'popup_login'
*あ、上記コードは ** dashboard以外にも、あらゆるページに存在している** という前提で!
で、partialのpopup_loginの中身は以下。
- unless user_signed_in?
.popup-login //cssはデフォルトdisplay:none;
= form_for(@user, url:user_session_path) do |f|
%dl
%dt= f.label :email
%dd= f.email_field :email
%dt= f.label :password
%dd= f.password_field :password
= f.submit 'ログインする'
:javascript
$('.header__login-button a').click(function(){
$('.popup-login').css({ 'display' : 'block'});
});
といった感じ。'ログインする'というリンクをクリックすると、
jsで上記のポップアップが出現するという仕組みです。(cssの記述はここでは省きます。)
ここで問題が。
haml:_popup_login.html.haml内の@user
を、どこで生成するのか、という問題です。
コントローラで@userに関する記述を書かないと上記エラーが発生します。
ではこれを書くのは、applicationコントローラー?
まさかまさかの毎回それぞれのページにactionごとに設定する?(いやいやいや!ナシっしょ)
applicationコントローラに書いた場合(やらない方がいい例)
愚直に考えると…
class ApplicationController < ActionController::Base
before_action: :pre_load
def pre_load
@user = User.new unless current_user.present?
end
end
か。
ただ、今回はログイン周りだけのため簡素だが、
例えばランキング機能とか、サイトコメント機能?とか増えていくと、
ここが肥大していく。
また、通常のrailsのようにactionとviewの関連がわからず、
ぱっと見viewと関連が「疎」なため管理しづらい。
また、後々@userを読みたくないページがあるんだけどとかの場合、
そのページでbefore_actionをexpectしなくちゃいけないとかになってくると、
全てのコントローラーでこのメソッドを意識してロードしなくちゃいけないとか
結構めんどくなる。
ここででる本音は、viewとロジック(controller)をワンセットでパッケージ化してくれると
便利なんだどなぁという心の声。
そしたらありました、便利なGemが。
それがCellsです。なんか定番みたいで今更っすけど… メモがてら。
Cellsとは。
例えばさっきのhaml:dashboard.html.hamlのコード。
= render partial: 'popup_login'
がありましたが、
= render_cell :popup_login, :show
ってな感じで書くことで、
ロジックとviewをセットで読みだしてくれるという便利Gem。
render_cellした:popup_loginがどうなっているかというと
こんな感じに設置されたshow.html.haml
とpopup_login_cell.rb
がワンセットになって
呼び出されます。
/app
/assets
/cells
/popup_login
show.html.haml
popup_login_cell.rb
class PopupLoginCell < Cell::Rails
def show
@user = User.new unless current_user.present?
render
end
end
- unless user_signed_in?
.popup-login //cssはデフォルトdisplay:none;
= form_for(@user, url:user_session_path) do |f|
%dl
%dt= f.label :email
%dd= f.email_field :email
%dt= f.label :password
%dd= f.password_field :password
= f.submit 'ログインする'
:javascript
$('.header__login-button a').click(function(){
$('.popup-login').css({ 'display' : 'block'});
});
といった具合です。読出元のdashboard.html.hamlでは、
render_cellsメソッドを使うだけ。
コントローラーとviewを一緒くたに読みだしてくれます。
Cells導入方法
gemfileに書いて
gem 'cells'
bundle installして
bundle instrall
generateします。
rails generate cell popup_login show -e haml
create app/cells/
create app/cells/popup_login
create app/cells/popup_login_cell.rb
create app/cells/popup_login/show.html.haml
create test/cells/popup_login_cell.rb
-e hamlでerbではなくhamlで書きだしてくれます。
cellsの部分テンプレートを読み出す場合は
= render_cell :popup_login, :show, :property => @property_name
# 上記は変数を受け渡す場合の例
といった感じです。
公式サイト
helper等より詳細な設定は下記をご参考ください。
github : apotonick/cells
https://github.com/apotonick/cells