Rails テキストボックスの入力補完(サジェスト)機能 text_field_with_auto_complete
Railsで、テキストボックスに入力された値をもとにDBを検索し、入力補完をするような機能をつけてみる。
Google Suggest のようなオートコンプリート機能のイメージだ。
環境
検索してみるといくつかの方法があったが、一番メジャーっぽい text_field_with_auto_complete というのを使ってみることにした。
参考にしたサイトはこちら
http://wiki.rubyonrails.org/rails/pages/How+to+use+text_field_with_auto_complete
http://d.hatena.ne.jp/zariganitosh/20071007
http://blog.livedoor.jp/maru_tak/archives/50606971.html
http://www.thinkit.co.jp/cert/article/0605/2/5/2.htm
今回は、テキストフィールドに入力された値をもとに、会社マスタ(companies)を検索し、会社名(name)と部分一致するリストを出して入力補完を行えるという機能を作ってみよう。
まずは適当なRailsプロジェクト(仮に autocomplete というプロジェクト名にする)を作って、Company クラスのScaffoldを作る。
jruby -S script/generate scaffold Company
auto_complete のプラグインをインストール。
jruby -S script/plugin install http://svn.rubyonrails.org/rails/plugins/auto_complete
CreateCompanies のマイグレーションファイルに会社名(name)のカラムを追記。
class CreateCompanies < ActiveRecord::Migration def self.up create_table :companies do |t| <span style="color:#FF0000;">t.string :name</span> t.timestamps end end def self.down drop_table :companies end end
config/database.yml にhostを追記
(原因はよくわからないが、hostの情報を書いておかないとDB操作ができなかった)
development: adapter: mysql encoding: utf8 database: autocomplete_development username: root password: socket: /var/run/mysqld/mysqld.sock host: 127.0.0.1 test: adapter: mysql encoding: utf8 database: autocomplete_test username: root password: socket: /var/run/mysqld/mysqld.sock host: 127.0.0.1 production: adapter: mysql encoding: utf8 database: autocomplete_production username: root password: socket: /var/run/mysqld/mysqld.sock host: 127.0.0.1
ちなみに database.yml は、共通の記述箇所は以下のようにまとめることができる(内容は、上記database.ymlと同じ。参考までに。)
common: &common adapter: mysql encoding: utf8 username: root password: socket: /var/run/mysqld/mysqld.sock host: 127.0.0.1 development: database: autocomplete_development <<: *common test: database: autocomplete_test <<: *common production: database: autocomplete_production <<: *common
DBをCreateして、マイグレーションファイルを実行
DBとcompaniesテーブルができたので、companiesテーブルにダミーデータを入れておこう。
以下のような簡単なCSVファイルを作って、companies.csv という名前で test/fixtures 配下に保存する。
この時、もともと companies.yml というファイルが存在しているので、org_companies.yml というような適当な名前にリネームしておく。
"id","name","created_at","updated_at"
1,"まるまる建設",,
2,"居酒屋ぺけぺけ",,
3,"いたくない歯科医院",,
4,"きれい美容室",,
5,"ろっくんろーる電器",,
6,"123病院",,
7,"1256総合病院",,
8,"1237777整形外科",,
9,"しかく商事",,
このCSVファイルをrakeコマンドを使ってDBにLoadする。
jruby -S rake db:fixtures:load FIXTURES=companies
必要なJavascriptライブラリをincludeする。
1.prototype.js
2.effects.js
3.controls.js
(app/views/layouts/companies.html.erb のhead部分に以下3ファイルを追加)
<%= javascript_include_tag "prototype" %> <%= javascript_include_tag "effects" %> <%= javascript_include_tag "controls" %>
今回はサンプルなので、index.html.erb にサジェスト機能のついたテキストボックスを配置してみる。
下記1行をerbファイルに追加する。
<%= text_field_with_auto_complete :company, :name %>
companies_controller.rb にメソッドを追加
auto_complete_for :company, :name def auto_complete_for_company_name find_options = { :conditions => [ "name LIKE ?", '%' + params[:company][:name] + '%' ], :limit => 10 } @items = Company.find(:all, find_options) render :partial => 'auto_complete_for_company_name' end
app/views/companies 配下に、_auto_complete_for_company_name.html.erb を追加
<ul> <% @items.each do |item| -%> <li id=<%= item.id %>> <%= item.name -%> </li> <% end -%> </ul>
http://localhost:3000/companies にアクセスしてみる。
動かない・・・。。
なぜだ。調べてみると、Rails 2 以降では、CSRF対策処理にひっかかるので、それをスキップさせる必要があるようだ。
(ちょっとセキュリティ的には問題があると思うが、まぁ今はとりあえずこれで回避しておこう。)
companies_controller.rb に下記1行を追加
skip_before_filter :verify_authenticity_token
すると、、
ただ、なぜか文字列の両端に半角スペースが入ってしまっている。
いろいろやってみると、以下のようにView上のliタグのところを1行で書いてやれば解決した。
<ul> <% @items.each do |item| -%> <li id=<%= item.id %>><%= item.name -%></li> <% end -%> </ul>
あとは、選択された会社のidをコントローラー側に渡してやりたいので、index.html.erb を以下のように変更した。
変更前
<%= text_field_with_auto_complete :company, :name %>
変更後
<%= text_field_with_auto_complete :company, :name,{}, :after_update_element=>"function(element, selectedItem){$('company_id').value = selectedItem.id;}" -%> <%= hidden_field :company, :id %>
これでコントローラー側で params[:company][:id] で会社のidを取得することができる。