Ajax開発

まあ、RailsはフツウにAjaxにも対応してるよー。

  • 初期バージョンで、今も標準はprototype.jsみたいだけど、最近はjQueryだよねー。
  • ってことで、「まだ」標準じゃないけどjQueryを使いますってさ。そりゃそーだ。

jQueryの導入

  • と言っても、大したことはしなくて良くて、単にファイルをゲットして置いて読ませるだけってのが素晴らしいね!
  • で、ファイルを置く場所は、以下の場所ね。
    app/assets/javascripts
    
    • うーん、assetsの導入で、前とパスが変わってるんだねー
    • jQueryの方は、ファイル名を「jQuery.js」に直す必要あり
  • で、アプリ設定ファイル(config/application.rb)を修正
    • この辺、以前とぜんぜん違ってきていて、assetsの導入で必要なくなったみたい。
    • ただ、本だと単にfadeOutを登録しただけでも動くみたいだったけど、クリックイベントに登録しないと動かないなー
  • 後は、jQueryのコードを下みたいにView(app/views/hello/ajax_test.html.erb)に書けばOK!
    <img id="logo" src="/assets/rails.png" />
    <script type="text/javascript">
    $('#logo').click(function () {
      alert("クリック!フェードアウトするよ!")
      $('#logo').fadeOut(3000);
    });
    </script>
    
    • これだと、Rails画像をクリックすると、フェードアウトしますー。
    • 画像の配置場所も、本とは大きく変わってるんだな…。

Ajaxでの表示更新

  • Railsでは、link_toやform_tagがAjax対応してるから、そこで「:remote => true」を書くだけでOKなんだねー。すげ!
  • まずは、単純な表示として、時刻の更新ね
    • 初めは表示画面ね。
      • app/views/hello/ajax_time_update.html.erbに、こんな感じで書く感じ
        <div>現在時刻:<%= Time.now %></div>
        <div id="result">現在時刻:<%= Time.now%></div>
        <%= link_to '更新', {:action => 'update_time'}, :remote => true %>
        
    • 次は、更新時に実行される呼び出し処理ね。
      • アクション(app/controllers/hello_controller.rb)に、こんなのを追加して、
           def update_time
             @time = Time.now.to_s
           end
        
    • 後は、ViewにERBとして、以下の2つを作成
      • JavaScriptは、app/views/hello/update_time.js.erb にこんな感じで書いて、
        $('#result').html(
         "<%= escape_javascript(render :partial => 'ajax_result' ) %>"
        );
        
      • 表示用に部分テンプレートで、app/views/hello/_ajax_result.html.erb をこんな感じで書く、と。
        現在時刻:<%= @time %>
        
    • で、http://localhost:3000/hello/ajax_index にアクセスして、「更新」した時に下の時刻だけ更新されればOKだね!
  • お次は、form_tagを使ったbook検索の場合ね!
    • app/views/hello/search_book.html.erbに、こんな感じで書く感じ
      <%= form_tag({ :action => 'result_book' }, { :remote => true} ) do %>
        <%= select_tag('publish', options_from_collection_for_select(@books,:publish, :publish, '日経BP社') )%>
        <%= submit_tag '検索'%>
      <% end %>
      <div id="result"></div>
      
    • 次は、検索時に実行される呼び出し処理ね。
      • コントローラ[app/controllers/hello_controller.rb]に、初期表示用と検索用に2つメソッドを追加して、
           def search_book
             @books = Book.select('DISTINCT publish')
           end
           def result_book
             @books = Book.where(:publish => params[:publish])
           end
        
    • 後は、ViewにERBとして、以下の2つを作成
      • JavaScriptは、app/views/hello/result_book.js.erb にこんな感じで書いて、
        $('#result').html(
         "<%= escape_javascript(render :partial => 'search_result' ) %>"
        );
        
      • 結果用に部分テンプレートで、app/views/hello/_search_result.html.erb をこんな感じで書く、と。
        <ul>
         <% @books.each do |book| %>
         <li><%= book.title %>(ISBN:<%= book.isbn %>)</li>
         <% end %>
        </ul>
        
    • で、http://localhost:3000/hello/search_book にアクセスして、「検索」した時に下の検索結果が表示されればOKだね!
  • で、「通信中」とかを表示するには、こんな感じねー。
    • まあ、この辺はjQueryの機能なんですねー
    • アプリ全体で使うJavaScriptは、[app/assets/javascripts/application.js]みたいなんで、まずはそこに、こんな感じで!
      $(function() {
       $('*')
         .ajaxStart    (function() { $('#progress').html('通信中…') } )
         .ajaxComplete (function() { $('#progress').html('') } );
      });
      
    • で、上で作った[app/views/hello/search_book.html.erb]の好きなところに、こんな感じで書いて、終わり!
        <span id="progress"></span>
      
    • あとは検索でsleepとかすると、検索中に「通信中…」って表示されると。

外部のWebサービスを使うには?

  • この例だと、Yahoo!検索Web APIですねー
    • まあ、基本は検索のコントローラ内で、Net::HTTPクラスを使って、外部のAPIを呼び出す感じだね
    • 本格的には、RailsのActiveResorceを使うのかな?
  • まずは、初期表示用のテンプレート[app/views/hello/keyword.html.erb]を、こんな感じで書いて、
    <%= form_tag({ :action => 'search_yahoo' }, { :remote => true} ) do %>
      <%= text_field_tag( :keyword, '', {:size => 30 })%>
      <%= submit_tag '検索'%>
      <span id="progress"></span>
    <% end %>
    <div id="result"></div>
    
  • コントローラ[app/controllers/hello_controller.rb]に、これを追加して、
       def search_yahoo
         Net::HTTP.start('search.yahooapis.jp') do |http|
           response = http.get('/WebSearchService/V2/webSearch?appid=wings-project&query=' + ERB::Util.url_encode(params[:keyword]))
           @body = Hash.from_xml(response.body)
         end
       end
    
    • うーん、ERB::Util.url_encode でURLエンコードしてるのかー。
    • ええ!Hash.from_xmlって、一発でXMLからハッシュにしてくれるんだなー。これ、便利だな!
  • 結果表示用のjsとhtmlのERBを用意して、完了!
    • [app/views/hello/search_yahoo.js.erb]は、こう
      $('#result').html(
       "<%= escape_javascript(render :partial => 'yahoo_result' ) %>"
      );
      
    • [app/views/hello/_yahoo_result.html.erb]は、こうね
      <ul>
        <% @body['ResultSet']['Result'].each do |result| %>
        <li><%= result['Title'] %>(URL:<%= result['Url'] %>)</li>
        <% end %>
      </ul>
      
  • あとは、http://localhost:3000/hello/keyword にアクセスして、キーワードを入力後、検索すれば結果が表示される、と。
    • 日本語キーワードもちゃんと出てるねー
    • ただ、本で解説してるappidをそのまま使ってるから、結構頻繁にユーザ数制限に引っ掛かって、以下のエラーが返ることがあるので、注意!
      Service unavailable.Too many users
      
  • ほうー。この辺で、xml/json用のAPIサービスにするのも簡単なんだ!素晴らしいなー
    • まずは、コントローラのsearch_yahooメソッド内に、こんな感じで書いて、
             respond_to do |format|
               format.js
               format.xml  { render xml: response.body }
               format.json { render json: Hash.from_xml(response.body).to_json }
             end
      
    • config/routes.rb に、こんなルートを書けば、
       match 'hello/search_yahoo(.:format)'
      
    • 以下のURLで、検索結果がXMLやjsonで返ってくると。もちろん、今までの検索もOKのはず。
    • うーん、エラーが多すぎて、正しく動いてるかの確認が取れんなw

-
最終更新:2012年02月17日 07:59