僕のYak Shavingは終わらない

車輪の再発明をやめたらそこには壮大なYakの群れが

WEB+DB No.73の記事よりRails 4に入門する 〜最終回〜

WEB+DB No.73の記事よりRails4に入門する 〜その1〜 - 僕の車輪の再発明
WEB+DB No.73の記事よりRails4に入門する 〜その2〜 - 僕の車輪の再発明

ちょっと間が空いてしまいましたが、上記の続きをやりましょう。

今日が最終回です。

検索機能の実装 ActiveModelを使う

ActiveModel::Modelを使うと、DBとは連動しないモデルを定義できるようです。

$ vi app/models/search_form.rb
class SearchForm
  include ActiveModel::Model
  attr_accessor :q
end

Viewの追加

続けてこれを使ったViewを作成します。

$ vi app/views/books/index.html.erb
<%= form_for @search_form, url: books_path, html: {method: :get} do |f| %>
  <%= f.search_field :q %>
  <%= f.submit '検索' %>
<% end %>

scopeを使った検索処理

次はControllerを書き換えます。

$ vi app/controllers/books_controller.rb
...
  def index
    # 本のレコード全部を表示する
    @books = Book.all

    # 以下追記箇所
    @search_form = SearchForm.new params[:search_form]
    if @search_form.q.present?
      # Book.allしたあとでも条件を追加できる
      @books = @books.titled @search_form.q
    end
  end
...

titledを実装しましょう。

$ vi app/models/book.rb
class Book < ActiveRecord::Base
  scope :titled, ->(q) {where 'title like ?', "%#{q}%"}
end

スコープ、使ってますね、はい、ちょっと今の僕だとよくわからないので調べますか・・。

一旦これで動くはず。
http://localhost:3000
にアクセスしてみましょう。

検索バーがつきましたね。
f:id:kazuph1986:20130506175014p:plain

試しにRubyと打ち込んで見ると、
f:id:kazuph1986:20130506175033p:plain
Railsのあの本が消えましたね!

ちなみにPerlと打ち込んでみると・・・
f:id:kazuph1986:20130506175127p:plain
はい!Perlなんてなかったんや!!

検索処理のAjax

Jbuilderを使うのが新しいですね!

編集した結果はこんなかんじです。
これで番号付きでを作成してくれます。

$ git diff app/views/books/index.html.erb
 -17,15 +17,13 @@
   </thead>

   <tbody>
-    <% @books.each do |book| %>
-    <tr>
+    <%= content_tag_for :tr, @books do |book| %>
       <td><%= book.title %></td>
       <td><%= book.price %></td>
       <td><%= book.published_on %></td>
       <td><%= link_to 'Show', book %></td>
       <td><%= link_to 'Edit', edit_book_path(book) %></td>
       <td><%= link_to 'Destroy', book, method: :delete, data: { confirm: 'Are you sure?' } %></td>
-    </tr>
     <% end %>
   </tbody>
 </table>
(END)

jsonの返却をidだけにしましょう。

$ git diff app/views/books/index.json.jbuilder
@@ -1,4 +1,3 @@
 json.array!(@books) do |book|
-  json.extract! book, :title, :price, :published_on
-  json.url book_url(book, format: :json)
+  json.extract! book, :id
 end
(END)

Ajaxの処理部分の実装

検索フォームにremote: trueを追加します。

$ git diff app/views/books/index.html.erb
@@ -1,4 +1,4 @@
-<%= form_for @search_form, url: books_path, html: {method: :get} do |f| %>
+<%= form_for @search_form, url: books_path(format: :json), remote: true, html: {method: :get} do |f| %>
   <%= f.search_field :q %>
   <%= f.submit '検索' %>
 <% end %>

最後にJSONを受け取ったJSの処理です。CSですが。
ちなみに、JSONで返ってきたものだけ表示するようにしています(手抜き)。

vi app/assets/javascripts/books.js.coffee
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
$ ->
  $('#new_search_form').on 'ajax:success', (e, books) ->
    $('tr.book').hide()
    ids = (books.map (b) -> "#book_#{b.id}").join(',')
    $(ids).show()

さあ、動くか確認してください。
http://localhost:3000

問題ないようです。

Turbolinks対応

最後に。

Turbolinks機能が有効になっていて、jQuery.ready()と処理が競合し検索が利かなくなることがあるときの対処です。

$ vi Gemfile
# 以下を追加
gem 'jquery-turbolinks'

gemを増やしたのでbundleしましょう。

bundle

そしてjsに以下の行を入れれば完成です。
require jqueryの次の行にいれないと動作しません。雑誌では「任意の場所」とありましたが間違いです。

It's easy to use: just require it immediately after jquery.js.

参考:https://github.com/kossnocorp/jquery.turbolinks

$ git diff app/assets/javascripts/application.js
@@ -11,6 +11,7 @@
 // GO AFTER THE REQUIRES BELOW.
 //
 //= require jquery
+//= require jquery.turbolinks
 //= require jquery_ujs
 //= require turbolinks
 //= require_tree .
(END)

Railsを再起動して以下の手順を試しても問題なければ終了です。

  • Showリンクをクリック
  • ブラウザのリロードボタンでリロード
  • BackリンクでTOPに戻り検索を実行

何事もなくできたでしょうか?
お疲れ様でした。

Turbolinksに関する参考
Rails 4のturbolinksについて最低でも知っておきたい事 | KRAY Inc

まとめ

たかが雑誌の一特集ですが、侮る無かれ、結構読み応えがありました。

写経ベースでやってみてわかりましたが、雑誌のまま試してもできないことが割りと多かったです。内容としては「執筆時点の著者では予期できない違い」がほとんどだったと思います。雑誌の特集の執筆時点から仕様が変わってるモジュールが多かったのではないかと思います。なので全然しょうがないですね。

ですが、その辺にストレートにハマって全部解決できたのは、良い経験になったと思います。

実はRails3がWEB+DBで特集されたときも同じように通してやったのですが、そのたびにRailsの簡単さには驚かされます。
それとは反対に予期せぬ場所(プログラミングと関係ないところ、例えば環境構築、バージョン差…)などでハマることが多く、自分はたまたま短時間で回避出来ましたが、プログラミング初心者の人たちはこの辺でかなり時間を食うでしょう(最近10名弱にRailsを教えていましたが、ほぼ全員がプログラミングを始められる前の段階で多くの時間を費やしていました)。

プログラマーになるのであれば、当然通る道ですが、プログラマーではないけどWebサービスを作りたい人にとっては大変なYak Ratioですね。まあこれはRailsに限った話ではなく、他のどの言語にも言えることですが。。。

この記事はつまずいたときのエラー分なども含めて記述することでググられビリティーをあげています。初心者の方が行き着き、問題解決の手助けとなれば幸いです。

くれぐれも環境構築なんかで挫折しないで、プログラミングの醍醐味に触れてください。

githubにも完成版のソースを上げておきました。
kazuph/webdb_rails_4 · GitHub

以上です。

Enjoy Rails!