Web Marina

日々の業務や勉強などで得た知識をアウトプットしていきます。

【Bootstrap/Rails】popoverのdata-contentの中身をHelperに切り出してみた。

f:id:song-of-life1352607:20170220105406j:plain

こんにちは、マリンです。

今回はBootstrapのpopoverです。

popoverはtitleに表示するタイトル。data-contentに表示する内容を書きます。

でも長い内容をタグ内に書きたくないでしょ!

ってなわけでRailsのHelperにメソッド切って表示内容を切り出してみました。

注)HTML上ではベタ書きになっちゃいますけど。




概要

- 環境 -

Rails5

Bootstrap3


- 例に使うテーブル構造 -

Usersテーブル

  • id

  • name

Childrenテーブル

  • id

  • name

  • user_id




- 概要 -

Userの名前をクリックすると、

ポップオーバーでChildrenの名前が表示されるようにします。

この時data-contentの中身が複雑になるので、

Helperにメソッドを切ってそれをdata-contentに渡します。


詳細

そもそもなんでこんなことになるのか?ちょっと詳細を説明します。

まず前提として、対象のページはindex.html.erbで、

Userの名前はUser.alleachで回して表示しているとします。

さらにChildrenは複数いる可能性があります。


そこで問題となるのが、

  1. どのUserの子供であるかを特定するためにuserを渡す必要があること。

  2. Childrenはuser.childrenの配列になること。

  3. その配列から名前を取得して表示するには、ループを回す必要があること。




ポップオーバーの内容は複雑になる場合、別エリアに切り出すことも可能です。

しかし今回の場合、まず一番外側でUser.allをループしています。

切り出すにはこのループの外になるでしょう。

となると1番のどのUserかを特定するuserを渡すのが大変です。

Ajaxを駆使してコントローラに値を渡して〜・・・なんてことが予想されます。




2、3番は表示内容が複雑になる理由です。

てことでHelperにメソッドを切ってみてはどうか?となったわけです。

ちなみに子の名前は一人一人改行して表示します。

HTML上はベタ書きになってしまいますが、コードはすっきりします。


ソースコード

さて前置きが長くなりましたが、ここから本題です。

まぁやってることは真新しいことではないのですが・・・

ControllerとModelは特に特筆することはないので、コードだけで解説は省略します。

Controller

# controllers/users_controller.rb

def index
    @users = User.all
end




Model

# user.rb

has_many :children

# child.rb

belongs_to :user




View

<!-- views/users/index.html.erb -->

<% @users.each do |user| %>
    <button class="btn" data-html="true" data-toggle="popover" title="子ども" data-cotent="<%= children_popover(user) %>">
        <%= user.name %>
    </button>
<% end %>




まずbuttonタグの中にあるdata-html="true"をご覧ください。

今回のメソッド切り出しとは直接関係はありませんが、

これを入れることでポップオーバーの中で改行<br>を使うことができるようになります。




次に本題のdata-content="<%= children_popover(user) %>"です。

このerb表記の中身が、後述のHelperに切り出すメソッド名です。

引数にuserを渡していることにご注目ください。

別エリアへの切り出しではないため、大枠のループのuserをそのまま使うことができます。




Helper

# helpers/users_helper.rb

def children_popover(user)
    users_children = []
    user.children.each do |child|
        users_children << child.name
    end
    users_children.join("<br>")
end




まず最初に子どもの名前を入れる空の配列を用意します。

そしてuser.childrenのループを回し、

その中で名前を先ほどの配列に格納していきます。

最後にループの外で出来上がった配列を、

区切り文字に<br>改行を指定して返します。

これを使うために先ほどViewでdata-html="true"を指定しました。

解説は以上になります。


まとめ

今回は値の取得などにたいした時間がかからないものでしたのでこの方法を使用しました。

しかし、表示する値の取得に時間がかかるようでしたら、

やはり別エリアに表示内容を切り出し、

値の取得にはAjaxを使って行うなどの方法をとった方が良いかと思います。

私も機会がありましたら挑戦してみようと思います。

ちなみに、今回の検証でpopoverを使用するためにclass="btn"が必ず必要だったのですが、

これは仕様でしょうか?それとも私の設定ミスでしょうか?

どなたかわかる方いらっしゃいましたら是非教えてください。

よろしくお願い致します。