simple_formとTwitter bootstrapで作る俺流鉄板Railsアプリ(その3)


前回はsimple_formを使ったカスタムインプットの作成方法を紹介しました。今回はそのカスタム・インプットとbootstrapの『Typeahead』を組み合わせた便利なインプットを作成したいと思います。

Typeaheadとは

Typeaheadとは、Twitter Bootstrapが提供するJavascriptのひとつで、オートコンプリート付きのテキストフィールドを簡単に作成することができるjQueryプラグインです。

Typeahead

個人的には、BootstrapのJavascriptの中で、一番使える機能だと思っています。bootstrap-rails.gemを導入していれば、この便利な機能があなたのRailsアプリですぐに使用できます。さっそく使ってみましょう。

どこに適用するかというと・・・Bookを登録する際に『Author』という項目を入力しますね。

Author

同一の著者が複数の本を執筆するのはよくあることです。そこで、データベースに登録されている全ての著者を入力候補としたオートコンプリート機能を実現してみることにします。

Typeaheadを適用する

ではさっそくソースを編集していきましょう。app/views/books/_form.html.erbを修正します。

📄_form.html.erb
<%= simple_form_for @book, :html => { :class => 'form-horizontal' } do |f| %>
  <%= f.input :title %>
  <%= f.input :author, input_html: {
        :"data-provide" => "typeahead",
        :"data-source" => '["test1", "test2"]',
        :autocomplete => "off" } %>
  <%= f.input :review, as: :review %>
  <%= f.input :description %>
  <div class="form-actions">
    <%= f.button :submit, :class => 'btn-primary' %>
    <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
                books_path, :class => 'btn' %>
  </div>
<% end %>

authorインプットに input_htmlオプションを指定しました。『data-provide』に”typeahead”を指定すると自動的にtypeahead機能が付与されます。オートコンプリートの候補は『data-source』に配列形式で指定します。たったこれだけで素敵なオートコンプリート機能が使えるとは便利ですねえ。(autocompleteをoffにしているのは、ブラウザが勝手に提供する入力履歴オートコンプリートを表示しないようにするためです)

さっそく画面をリロードして動作を確認してみると・・・

試し

ちゃんとできてる! まだ3行しか書いてなにのに、ここまで辿り着きました。あなおそろしやbootstrap・・・

では次に、オートコンプリートの入力候補をちゃんと実装しましょう。データベースから全ての『Author』を取得するようにします。

📄_form.html.erb
  <%= f.input :author, input_html: {
        :"data-provide" => "typeahead",
        :"data-source" => Book.pluck(:author).compact.uniq.to_s,
        :autocomplete => "off" } %>

pluckメソッドを使い、ユニークなauthor一覧を取得しています。特に難しい箇所はないと思います。さて・・・ちゃんと動くのでしょうか??

Author

うむ! ちゃんと動いてますよ!日本語が問題ないところも素敵です。

要件としてはこれで満たしているのですが、前回と同様にこのインプットをカスタム・インプットにして再利用性を高めましょう。他の画面でも著者を入力する場面がきっとあるはずです。

前回の ReviewInputと同様に、app/inputs/author_input.rbというファイルを作成して、カスタムインプットを定義します。

📄author_input.rb
class AuthorInput < SimpleForm::Inputs::StringInput
  def input
    input_html_options[:type] = "text"
    input_html_options[:"data-provide"] = "typeahead"
    input_html_options[:"data-source"] = Book.pluck(:author).compact.uniq.to_s
    input_html_options[:autocomplete] = "off"
    super
  end
end

app/views/books/_form.html.erbも修正して、カスタムインプットを呼び出すようにします。

📄_form.html.erb
<%= simple_form_for @book, :html => { :class => 'form-horizontal' } do |f| %>
  <%= f.input :title %>
  <%= f.input :author, as: :author %>
  <%= f.input :review, as: :review %>
  <%= f.input :description %>
  <div class="form-actions">
    <%= f.button :submit, :class => 'btn-primary' %>
    <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
                books_path, :class => 'btn' %>
  </div>
<% end %>

画面をリロードして動作を確認してみましょう。先程と同様に正しく動作するはずです。

入力候補を取得する

正しく動作はしていますが、イケてない箇所がありますね。それは、カスタムインプット内からBookモデルに直接アクセスして入力候補を取得していることです。View層からデータベースをいじり倒すのはよろしくありませんし、もし1画面に複数のAuthorインプットを配置する場合、無駄なデータベースアクセスが増えるのもよくありません。入力候補はコントローラで1回取得するようにしましょう。

app/controllers/books_controller.rbを修正しましょう。

📄books_controller.rb
class BooksController < ApplicationController
  before_action :set_input_sources, only: [:new, :edit, :create, :update]
...
...
  private
...
...
    def set_input_sources
      @author_input_source = Book.pluck(:author).compact.uniq.to_s
    end
end

2行目でフィルタを登録しています。実際に著者候補を取得してくるのは8~10行目の set_input_sourcesメソッドです。アプリケーションの各所で著者インプットを使用するなら、このメソッドは ApplicationControllerに定義してもよいかもしれません。

続いて、author_input.rbを修正します。

📄author_input.rb
class AuthorInput < SimpleForm::Inputs::StringInput
  def input
    input_html_options[:type] = "text"
    input_html_options[:"data-provide"] = "typeahead"
    input_html_options[:"data-source"] = @builder.template.assigns["author_input_source"]
    input_html_options[:autocomplete] = "off"
    super
  end
end

InputsクラスのコンテキストからViewのインスタンス変数にアクセスするには@builder.template.assigns["変数名"] のように記述します。修正が完了したら、画面をリロードして最終確認です!

Author完成

ディ・モールト(非常に良い)!! 軽快に動作するナイスなオートコンプリートの完成です!

今回で『simple_formとTwitter bootstrapで作る俺流鉄板Railsアプリ』は終了です。大した手間もなく、そこそこリッチなWebアプリケーションが作れることがお分かり頂けたでしょうか。simple_form/bootstrapには、この他にも便利な機能がいろいろとありますので、ぜひとも探訪してみてください。

関連する記事