Backbone.jsãRailsã§ä½¿ã£ãéã®ãåæè¨å®ã¨ã«ã¼ã«
ããªãã ã¾ã§Railsã¨Backbone.jsã使ã£ãWEBãµã¼ãã¹ãä½ã£ã¦ã¾ãããæè§ãªã®ã§ããã®éã®åæè¨å®ã¨ã¡ãã£ã¨ããã«ã¼ã«ãã¾ã¨ãã¦ããã¾ããã¡ãªã¿ã«ãè¦æ¨¡æã¯ä»¥ä¸ã®ãããªæãã§ãã
ã»Modelã¨Collection åç´10å
ã»Viewã¨Template åç´30å
ã»Routerã¯ä½¿ããªãï¼SinglePageApplicationã§ã¯ãªãã®ã§ï¼
ãã¼ã¸ã§ã³ã¯
ã»backbone.js: 1.1.0
ã»rails: 3.2.13
ã§ã
ã©ã¤ãã©ãªã®é ç½®
ä¾åã©ã¤ãã©ãªã¯ä»¥ä¸ã®ããã«é ç½®ãã
// vendor/assets/javascripts/é ä¸ . |-- backbone/ | |-- backbone-min.js | `-- backbone-min.map |-- json2/ | `-- json2.js |-- underscore/ | |-- underscore-min.js | `-- underscore-min.map ...
ãã£ã¬ã¯ããªæ§æ
jsã³ã¼ãã®ãã£ã¬ã¯ããªæ§æã¯ä»¥ä¸ã®ããã«ãããcollectionsã¨modelsã¯ç´ä¸ã«ãã¡ã¤ã«ããããviewsã¨templatesã¯ã¢ãã«ã«å¯¾ãã¦ãã£ã¬ã¯ããªãä½ã£ã¦ãã®ä¸ã«ãã¡ã¤ã«ãç½®ãã¦è¡ã£ãï¼ãã®æ§é ã«åããªããã¡ã¤ã«ã沢山åºã¦ããã®ã§ãããç¨åº¦èªç±ã«ãã£ã¬ã¯ããªãåã£ã¦ãã£ãï¼
// app/assets/javascripts/é ä¸ . |-- collections/ | `-- users.js |-- models/ | `-- user.js |-- templates/ | `-- users/ | `-- xxx.hbs |-- views/ | `-- users/ | `-- xxx.js
ãã³ãã¬ã¼ã
ãã³ãã¬ã¼ãã«ã¯handlebarã使ã£ããrailsç¨ã®gemã§handlebars_assetsã¨ããã®ããã£ãã®ã§ããããå©ç¨
https://github.com/leshill/handlebars_assets
gemãã¤ã³ã¹ãã¼ã«
group :assets do gem 'handlebars_assets' end
ãã³ãã¬ã¼ãã¯ãããªæãã«ãªã
// app/assets/javascripts/templates/users/user-detail.hbs <span>åå:</span><span>{{name}}</span> <span>ã¡ã¼ã«:</span><span>{{mail}}</span>
ãã³ãã¬ã¼ãé¢æ°ã®ããã©ã«ãåã¯ãHandlebarsTemplatesãã ããæ°ã«å ¥ããªããã°å¤ãããããä¾ãã°ãJSTãã¨ããååã«ããããã°ãconfig/initializers/handlebars.rbã¨ãããã¡ã¤ã«ãæ°è¦ä½æãããã®ä¸èº«ã以ä¸ã®ããã«ãã
HandlebarsAssets::Config.template_namespace = 'JST'
ããã¨Viewããã¯ãã®ããã«ãã³ãã¬ã¼ãã使ããããã«ãªã
// app/assets/javascripts/views/users/user_detail.js MYAPP.UserDetailView = Backbone.View.extend({ template: JST['users/user-detail'], render: function() { this.$el.html(this.template({ name: this.model.get('name'), mail: this.model.get('mail') })); return this; } });
application.js
以ä¸ãåããããã®application.jsã¯ä»¥ä¸ã®ããã«ãªããrequire_treeã§ãã£ã¬ã¯ããªãåèµ·çã«èªã¿è¾¼ãããã«ãã
//= require jquery //= require jquery_ujs //= require json2/json2 //= require underscore/underscore-min //= require backbone/backbone-min //= require handlebars.runtime //= require_tree ./templates //= require application //= require_tree ./models //= require_tree ./collections //= require_tree ./views //= require_tree .
åå空é
ååã®è¡çªãé¿ããããã«ãã¢ããªã±ã¼ã·ã§ã³ã«é¢ããåå空éãä½ãï¼ã¨ãã£ã¦ãã°ãã¼ãã«ãªãªãã¸ã§ã¯ããï¼ã¤ä½ãã ãï¼ãapplication.jsã«ä»¥ä¸ãè¨è¼ã
window.MYAPP = window.MYAPP || {};
ã¯ã©ã¹åè¦å
ä¸è¨ã®åå空éã®ä¸ã«ã¯ã©ã¹ã¨ãªããªãã¸ã§ã¯ããä½ã£ã¦ããã®ã ãããã®éã®ã¯ã©ã¹åã¯ä»¥ä¸ã®ããã«ãããå ¨ã¦å¤§æåã§ã¯ããããCollectionã¯Modelã®è¤æ°å½¢ãViewã¯Model/Collectionã¨1対1ã§ããã°é ã«Modelåãã¤ããï¼ãã®ãããªé¢ä¿ã«ãªããªãå ´åãå¤ãã®ã§ããã®å ´åã¯èªç±ã«å½åããï¼ã
// Model MYAPP.User = Backbone.Model.extend({ /* ... */ }); // Collection MYAPP.Users = Backbone.Collection.extend({ /* ... */ }); // View MYAPP.UserListView = Backbone.View.extend({ /* ... */ });
ã¢ããªã±ã¼ã·ã§ã³å ¨ä½ã§ã®å ±éåå¦ç
ã¢ããªã±ã¼ã·ã§ã³å ¨ä½ã§å¿ ãå®è¡ãããå ±éã®åå¦çãåå¨ããã®ã§ãBackboneãªãã¸ã§ã¯ãèªä½ã®ã¤ãã³ããå©ç¨ãããapplication.jsã«å ±éåå¦çãæ¸ãããããçµãã£ããBackbone.triggerã§ã«ã¹ã¿ã ã¤ãã³ãï¼ä»¥ä¸ã®ä¾ã§ã¯initï¼ãçºç«ãããåãã¼ã¸ã®javascriptã§ã¯ãã®ã¤ãã³ããè³¼èªãã¦ããã¨ããå½¢ã
application.js
$(function() { // å ±éåå¦ç // ... Backbone.trigger('init'); });
åãã¼ã¸
Backbone.on('init', function() { // åãã¼ã¸ã®å¦ç });
ãµã¼ãã¼ãµã¤ãã§çæããjsonã®ãã³ããªã³ã°
ãµã¼ãã¼ãµã¤ãã§çæããjsonã®ãã³ããªã³ã°ã¯ãåºæ¬çã«ã¯as_jsonã¡ã½ãããç¨ããã使ãæ¹ã¯ãã¡ãã®ããã°ã詳ãã
http://d.hatena.ne.jp/gutskun/20130409/1365518684
ãã£ã¨ç´°ãããã³ããªã³ã°ããããå ´åã«ã¯gemã使ã£ãæ¹ãããã¨æããRails4ããã¯ããã©ã«ãã§çµã¿è¾¼ã¾ãã¦ããJbuilderãRABLããããæå
http://railscasts.com/episodes/320-jbuilder?language=ja&view=asciicast
http://railscasts.com/episodes/322-rabl?language=ja&view=asciicast
åæãã¼ã¿æå ¥
大ãã2ã¤ã®æ¹æ³ãããããã«æããï¼ã¤ã¯ãã¼ã¿ã空ã®ãªãã¸ã§ã¯ããä½ã£ã¦ãããµã¼ãã¼ã«fetchãããã®ãããï¼ã¤ã¯htmlã¬ã³ããªã³ã°æã«ãã¼ã¿ãå ¥ãã¦ãã¾ããã®ã
ï¼ã¤ç®ã®æ¹æ³
<div id="user-list-container"></div> <%= javascript_tag do %> Backbone.on('init', function() { var users = new MYAPP.Users(); var userListView = new MYAPP.UserListView({collection: users}); $('#user-list-container').html(userListView.render().el); users.fetch({reset: true}); }); <% end %>
ãã®å ´åã®æµãã¯
ã»ãã¼ã¿ã空ã®ç¶æ
ã§Viewã¬ã³ããªã³ã°
ã» model/collectionããµã¼ãã¼ã¸ãã¼ã¿ãfetch
ã» model/collectionã®resetã¤ãã³ãçºç«
ã» viewãresetã¤ãã³ããã£ãããã¦ãå度ã¬ã³ããªã³ã°
ï¼ã¤ç®ã®æ¹æ³
<div id="user-list-container"></div> <%= javascript_tag do %> Backbone.on('init', function() { var users = new MYAPP.Users(JSON.parse('<%= j @users.to_json.html_safe %>')); var userListView = new MYAPP.UserListView({collection: users}); $('#user-list-container').html(userListView.render().el); }); <% end %>
ãã®å ´åã®æµãã¯
ã»ã¢ãã«ã®jsonãã¼ã¿ããµã¼ãã¼å´ã§jsã³ã¼ãã¨ãã¦åºå
ã»ãã¼ã¿ãããç¶æ
ã§Viewãã¬ã³ããªã³ã°
2ã¤ç®ã®æ¹æ³ã®æ¹ãã¬ã³ããªã³ã°ãéãã®ã§ãç¹ã«çç±ããªããã°2ã¤ç®ã®æ¹æ³ã使ãã
ã¯ã©ã¤ã¢ã³ããµã¤ãã§ã¬ã³ããªã³ã°ãããããµã¼ãã¼ãµã¤ãã§ã¬ã³ããªã³ã°ããã
åè¿°ã³ã¼ãã¯ãbackbone管çä¸ã®è¦ç´ ãã¯ã©ã¤ã¢ã³ããµã¤ãã§çæãããããªã³ã¼ãã ã£ããããã©ãããããã¨ãã®é¨åã®è¦ç´ ã«é¢ãã¦ã¯SEOãæ»ã¬ããã®åé¡ã¯å¥ã«backboneã«éã£ã話ã§ã¯ãªããangularã®ãããªä»ã®ã©ã¤ãã©ãªã使ã£ã¦ãã¦ããã¯ã©ã¤ã¢ã³ããµã¤ãã§ã¬ã³ããªã³ã°ããéãèµ·ããåé¡ã対çæ³ã¯ãã¡ãã®ãµã¤ããªã©ã詳ãã
http://info.appdirect.com/blog/solving-the-javascript-seo-conundrum-part-one
http://www.ng-newsletter.com/posts/serious-angular-seo.html
ããã©ãä»åã¯ããã¾ã§å¤§æãããªãã¨ãããã«å±æçã«å¯¾çããã°ããç¨åº¦ã ã£ãã®ã§ãSEO対çãªå¿ è¦ãªãã¼ã¸ã¯ãµã¼ãã¼ãµã¤ãã§ã¬ã³ããªã³ã°ããã¯ã©ã¤ã¢ã³ããµã¤ãã§ã¯ãµã¼ãã¼ãµã¤ãã§ã¬ã³ããªã³ã°ãããhtmlã«å¯¾ãã¦backbone.jsã®ãªãã¸ã§ã¯ããã¢ã¿ããããããã«ãããåèã«ããã®ã¯ãã¡ãã®stackoverflowã®ãã¹ã
http://stackoverflow.com/questions/7549306/single-page-js-websites-and-seo
ã³ã¼ãã¯ãããªæãã
<div id="user-list-container"> <% @users.each do |user| %> <div class="user-detail" data-id="<%= user.id %>"> <span>åå:</span><span><%= user.name %></span> <span>ã¡ã¼ã«:</span><span><%= user.mail %></span> </div> <% end %> </div> <%= javascript_tag do %> Backbone.on('init', function() { var users = new MYAPP.Users(JSON.parse('<%= j @users.to_json.html_safe %>')); var userListView = new MYAPP.UserListView({el: $('#user-list-container'), collection: users}); userListView.$('div.user-detail').each(function(i, el) { var el = $(el); var id = el.attr('data-id'); var user = users.get(id); new MYAPP.UserDetailView({el: el, model: user}); }); }); <% end %>
ãã®ã¢ããã¼ãã ã¨ããã³ãã¬ã¼ããã¯ã©ã¤ã¢ã³ãå´ã§ã使ãããå ´åã«ã³ã¼ãã®éè¤ãçºçããããä»åã¯ãã®ãããªç®æãããã»ã©å¤ããªãã£ãã®ã§ãããã¨ããã
åèã«ãªã£ãã½ã¼ã¹
https://github.com/documentcloud/documentcloud
Backbone.jsã®æ¬å®¶æ¬å
ãdocumentcloudããã®ã½ã¼ã¹ã³ã¼ããGithubã§å
¬éããã¦ãããµã¼ãã¼ãµã¤ãã¯Railsãã¡ãã£ã¨ãã¼ã¸ã§ã³ãå¤ãã®ã§ãæ¸ãæ¹ãã¬ã¬ã·ã¼ãªã¡ã½ããã使ã£ã¦ããããããã©ãTodoã¢ããªã¿ãããªãµã³ãã«ã¨ã¯éã£ã¦å®éç¨ããã¦ãã大ããªã¢ããªã±ã¼ã·ã§ã³ãªã®ã§å¤ãã«åèã«ãªã£ãã
https://github.com/samuelclay/NewsBlur
SinglePageApplicationã®RSSãªã¼ãã¼NewsBlurããã¡ããdocumentcloudã®ã¡ã³ãã¼ãä½ã£ã¦ããã£ã½ãããµã¼ãã¼ãµã¤ãã¯Djangoã media/js/newsblur/é
ä¸ã«backboneã使ã£ãjsã³ã¼ãã沢山ããã
çµãã
ããããSinglePageApplicationã¨ãã£ããããªãã»ã¨ãã©ç»é¢é·ç§»ãããªãã¢ããªã±ã¼ã·ã§ã³ã«ããå ´åãã¾ãã¡ãã£ã¨ãã¤ã³ããå¤ãã£ã¦ããã¨ã¯æãã¾ãï¼Routerã®å½¹å²ã大ãããªãã®ã§ï¼ãããã©ããã¾ã§ãããªãã¢ããªã±ã¼ã·ã§ã³ã§ããã°ãä¸è¨ã®ãããªæ§æï¼ã«ã¼ã«ã§ç ´ç¶»ããã«ãããããªæãã§ããã¼