ラベル backbonejs の投稿を表示しています。 すべての投稿を表示
ラベル backbonejs の投稿を表示しています。 すべての投稿を表示

2011年7月28日木曜日

backbone.jsがいつのまにかpjax対応していた

■概要

年初にbackbone.jsの調査をしていた頃は、ajaxで画面遷移を行うには、fragmentを利用する事しかできませんでした。

しかし0.5以降では、Backbone.Routerを利用する事によって、pjax(HTML5のpushStateを利用した話題のあれ)な画面遷移が出来るになっています。

pjaxについては、こちらをご参照ください。
またgithubのファイルブラウザはpjaxの良例として有名なのでチェックしてみて下さい。


■何処がpjaxなのか?

まずは下記手順を実施後、http://localhost:3000/を閲覧してみましょう。chrome等html5対応ブラウザで確認して下さい。


次にhelpをクリックしてみましょう。

注目すべきなのは、
①URLが変わっている
②画面下部のレンダリング日時が変わっていない。

次にaboutをクリックしてみましょう。helpの時と同じです。

ブラウザの「戻る」ボタンをクリックしてみましょう。
About => Help => Indexに遷移します。「進む」ボタンもいい感じに遷移します。

次にHelpが画面に表示されている状態で、「F5」を押下してみましょう。
レンダリング日時が変わったはずです。


■説明

ajaxは非同期に(高速に)画面の一部を書き換える技術ですが、ユーザーの利便性の観点から、ブラウザの戻る、進むを利用可能にする必要があります。これまでのajaxでは、#(フラグメント)を利用して実現する事が多かったのですが、あまり良い解決策では有りませんでした。

pjaxでは、HTML5のpushStateを利用する事により、ブラウザのURLを切り替えつつ、画面の一部のみ切り替える事ができます。無論、URLは通常のURLですので、「通常のHTTPリクエスト」として処理するように実装する事が可能です。下記のIndexControllerでは、Ajax通信かどうかでレイアウトの適用を変更しています。
これができたら何が嬉しいのか?!それは読者への宿題にしておきます(^.^;

ちなみに、IE(≒pushStateをサポートしていないブラウザ)でみたら fragment での遷移に自動的に切り替わってました。。

■体験手順

・まずは前回の記事を参考にプロジェクトを生成する。

$ ./gen.sh pjax

・移動して体験に必要なファイルを用意する

$ cd pjax

app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title>pjax2</title>
    <meta charset="utf-8"/>
    <%= stylesheet_link_tag :all %>
    <%= javascript_include_tag :defaults %>
    <%= javascript_include_tag :backbone %>
    <script><%= yield :javascripts %></script>
    <%= csrf_meta_tag %>
  </head>
  <body>
    <%= content_for?(:content) ? yield(:content) : yield %>
  </body>
</html>

app/views/layouts/index.html.erb

<%= content_for :javascripts do %>
$(function() {
  var Workspace = Backbone.Router.extend({
    routes: {
      "":      "index",
      "help":  "help",
      "about": "about"
    },
    index: function() {
      $("#app").load("/");
    },
    help: function() {
      $("#app").load("/help");
    },
    about: function() {
      $("#app").load("/about");
    }
  });
  var ws = new Workspace();
  Backbone.history.start({pushState: true});

  $("#indexButton").click(function() {
    ws.navigate("", true);
  });
  $("#helpButton").click(function() {
    ws.navigate("help", true);
  });
  $("#aboutButton").click(function() {
    ws.navigate("about", true);
  });
});
<% end %>

<%= content_for :content do %>
  <div id="app"></div>
  <hr/>
  <input type="button" name="index" value="index" id="indexButton" />
  <input type="button" name="help"  value="help"  id="helpButton" />
  <input type="button" name="about" value="about" id="aboutButton" />
  最終レンダリング日時:<%= I18n.l Time.now %>
<% end %>

<%= render :file => "layouts/application" %>

app/views/index/index.html.erb

<h1>Index</h1>

app/views/index/help.html.erb

<h1>help</h1>

app/views/index/about.html.erb

<h1>about</h1>

app/controllers/index_controller.rb

class IndexController < ApplicationController
  layout "index"
  def index
    render :layout => !request.xhr?
  end
  def help
    render :layout => !request.xhr?
  end
  def about
    render :layout => !request.xhr?
  end
end

config/routes.rb

最後に
root :to      => "index#index"
match "help"  => "index#help"
match "about" => "index#about"

public/index.html <= 削除

サーバ起動!
$ rails server

2011年3月23日水曜日

backbone.jsをrails3に読み込む為におまじない

■概要

backbone.jsでの開発を始める為に、簡単なgeneratorを作っておくと、うれしいかも

■手順

・新規にgeneratorを作成
$ vim lib/generators/backbone_js_generator.rb

class BackboneJsGenerator < Rails::Generators::Base
  desc "This generator downloads and installs json2.js, underscore.js, backbone.js"
  def download_json2_js
    say_status("fetching", "json2.js", :green)
    get "https://github.com/douglascrockford/JSON-js/raw/master/json2.js",
        "public/javascripts/json2.js"
  end

  def download_underscore_js
    say_status("fetching", "underscore.js", :green)
    download_via_documentcloud("underscore")
    download_via_documentcloud("underscore", "-min")
  end

  def download_backbone_js
    say_status("fetching", "backbone.js", :green)
    download_via_documentcloud("backbone")
    download_via_documentcloud("backbone", "-min")
  end

  private
  def download_via_documentcloud(product, suffix = "")
    get "http://documentcloud.github.com/#{product}/#{product}#{suffix}.js",
        "public/javascripts/#{product}#{suffix}.js"
  end

end

・generatorを起動し必要なjsをファイルを出力する
$ rails g backbone_js

・javascript_include_tag用の設定を作成
$ vim config/initializers/backbone_js.rb

module BackboneJs
  module Rails
    class Railtie < ::Rails::Railtie
      config.before_configuration do
        config.action_view.javascript_expansions[:backbone] =
          ::Rails.env.production? ? %w(json2 underscore-min backbone-min) : %w(json2 underscore backbone)
      end
    end
  end
end
こうしておけば、application.html.erbとかで <%= javascript_include_tag :backbone %> と書けます。 defaultsに混ぜても良いかもしれませんが画面によっては不要そうなので分けてみました。

■TODO
gem化(汗)

■参考
jquery-rails

2011年1月26日水曜日

rails3とbackbone.jsの組み合わせで利用する2

■概要

前回に引き続き、backbone.jsを利用してjqueryでMVCの世界を、rails3と共に作っていこうと思います。
今回はデータのやり取りをする所までが目標です。

■モデル/コントローラ等を作成する

$ rails g scaffold post title:string body:text published:boolean
$ rake db:migrate
$ rake spec (とりあえずrspecが動くか確認しとく)
$ rake spec:rcov (ついでにrcovが動くか確認しとく)
$ rails s

ここで http://localhost:3000/posts でいつもの画面が表示されてればOK!

■json入出力用にコントローラを修正する

とりあえずjsonでやり取りできるように変更します。params.exceptはbackboneとのやり取りを考慮してます。

class PostsController < ApplicationController
  respond_to :json
  def index
    @posts = Post.all
    respond_with @posts
  end
  def show
    @post = Post.find(params[:id])
    respond_with @post
  end
  def create
    @post = Post.new(params.except(:action, :controller))
    respond_to do |format|
      if @post.save
        format.json { render :json => @post, :status => :created, :location => @post }
      else
        format.json { render :json => @post.errors, :status => :unprocessable_entity }
      end
    end
  end
  def update
    @post = Post.find(params[:id])
    respond_to do |format|
      if @post.update_attributes(params.except(:id, :action, :controller, :created_at, :updated_at))
        format.json { head :ok }
      else
        format.json { render :json => @post.errors, :status => :unprocessable_entity }
      end
    end
  end
  def destroy
    @post = Post.find(params[:id])
    @post.destroy
    respond_to do |format|
      format.json { head :ok }
    end
  end
end

■jsonのフォーマットを変更する

このままだと下記の用に"post"が付いてしまうので、backbone側の期待と異なります。

http://localhost:3000/posts.json
=> [{"post":{"body":"a","created_at":"2011-01-19T16:13:47Z","id":1,"published":false,"title":"aa","updated_at":"2011-01-19T16:13:47Z"}}]

http://localhost:3000/posts/1.json
=> {"post":{"body":"a","created_at":"2011-01-19T16:13:47Z","id":1,"published":false,"title":"aa","updated_at":"2011-01-19T16:13:47Z"}}


config/initializers/include_root_in_json.rbの様なファイルを作成し

ActiveRecord::Base.include_root_in_json = false

とすると下記の様な感じでgoodです!

http://localhost:3000/posts.json
=> [{"body":"a","created_at":"2011-01-19T16:13:47Z","id":1,"published":false,"title":"aa","updated_at":"2011-01-19T16:13:47Z"}]

http://localhost:3000/posts/1.json
=> {"body":"a","created_at":"2011-01-19T16:13:47Z","id":1,"published":false,"title":"aa","updated_at":"2011-01-19T16:13:47Z"}

■backbone用のcontorollerを作成

コントローラ/ビューを追加して必要な設定を追加します。

$ vim controllers/home_controller.rb

class HomeController < ApplicationController
  def index
  end
end

$ vim config/routes.rb
  root => "home#index"
$ rm public/index.html
$ mkdir views/home

■backbone.jsを使ってみる

$ vim views/home/index.html.erb



http://localhost:3000/ を開いて、画面に味気ないalertが表示されればOkay!!
railsのログとDB見てると少しは楽しいかも

次は画面を作っていきましょう!

2011年1月11日火曜日

rails3とbackbone.jsの組み合わせで利用する1

■概要
backendをrails3にして、backbone.jsを利用する為の手順を残しておきます。

■railsプロジェクトの作成
$ rails new demo -T -J -d mysql
demo プロジェクト名
-T testunitはいらない
-J prototype.jsはいらない
-d mysql データベースはmysql

■gemを追加
$ cd demo
$ vim Gemfile
下記を一番下に追加(本当はバージョンをつけた方が良い)
gem 'jquery-rails'
group :development, :test do
  gem 'rspec'
  gem 'rspec-rails'
  gem 'rcov'
end
$ bundle install

■コードジェネレート
$ rails g rspec:install
$ rails g jquery:install --ui

■まず使えるように編集
$ vim config/database.yml

$ vim app/views/layouts/application.html.erb
文字列エンコーディングを明確に指定する為に下記追加
<meta charset="utf-8"/>

$ vim config/application.rb
jquery-railsに、javascriptのdefaults設定はまかせる(コメントアウトする)
# config.action_view.javascript_expansions[:defaults] = %w()
これを有効にしたい

$ vim spec/spec_helper.rb

ruby1.9.2でrcovを正しく動作させる為に、下記を一番下に追加
# quick monkey patch for rcov
# http://codefluency.com/post/1023734493/a-bandaid-for-rcov-on-ruby-1-9
if defined?(Rcov)
  class Rcov::CodeCoverageAnalyzer
    def update_script_lines__
      if '1.9'.respond_to?(:force_encoding)
        SCRIPT_LINES__.each do |k,v|
          v.each { |src| src.force_encoding('utf-8') }
        end
      end
      @script_lines__ = @script_lines__.merge(SCRIPT_LINES__)
    end
  end
end

$ vim .rspec
spork等で動いてもいい様に下記を追加しておく
--drb

■backbone.jsの準備
$ cd public/javascripts
↓jsファイル取得。ここも本当はバージョンを明示すべきかな
$ wget http://documentcloud.github.com/underscore/underscore.js
$ wget http://documentcloud.github.com/underscore/underscore-min.js
$ wget http://documentcloud.github.com/backbone/backbone.js
$ wget http://documentcloud.github.com/backbone/backbone-min.js
$ cd ../..
$ vim app/views/layouts/application.html.erb
backbone.jsを読み込むようにする。下記をhead内に追加
<%= javascript_include_tag "underscore-min.js", "backbone-min.js" %>

■履歴管理開始
$ vim .gitignore (履歴管理しない最低限のものを追加)

.bundle
db/*.db
db/*.sqlite3
db/schema.rb
log/*.log
tmp/
coverage/
*.swp

$ git init
$ git add .
$ git commit -m "最初のコミット"

■DB作成
$ rake db:create:all
$ rake db:migrate

■起動
$ rails s

ここまでで準備完了!次は実際にデータの操作をしてみます

20110113 追記
http://d.hatena.ne.jp/nedate/20101004/1286183882を参考にrcovの設定も追加させてもらいました!