带有远程Rails服务器的BackBone客户端

背景:

我使用“rails g scaffold hotel name stars:integer”来快速启动(并在数据库中插入一些记录),并在rails app之外编写一个Backbone客户端。

我使用Safari文件在本地打开Backbone客户端:///Users/lg/Workspace/www/index.html用于测试客户端,因为我的想法是将rails服务器放在主机上(例如Heroku)并插入Backbone客户端进入PhoneGap应用程序。

我的骨干客户端只有几行:

Hotel = Backbone.Model.extend({ initialize: function(){ console.log("initialize Hotel") } }); Hotels = Backbone.Collection.extend({ model: Hotel, url: 'http://0.0.0.0:3000/hotels' }); 

但是当我获取带有主干的酒店时,rails会使用format.html进行响应,而不是Backbone可以解析的format.json

hotels_controller.rb

 # GET /hotels # GET /hotels.json def index @hotels = Hotel.all respond_to do |format| format.html # index.html.erb format.json { render json: @hotels } end end 

Safari检查器控制台:

 hotels = new Hotels() Object hotels.fetch() Object hotels.length 0 Request URL:http://0.0.0.0:3000/hotels Request method:GET Status code:200 OK Request Headers Accept:application/json, text/javascript, */*; q=0.01 User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.53.11 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10 Response Headers Cache-Control:max-age=0, private, must-revalidate Connection:Keep-Alive Content-Length:2233 Content-Type:text/html; charset=utf-8 Date:Sat, 11 Feb 2012 14:31:52 GMT Etag:"606da2b7c21ca96c9d71aabccdd439e9" Server:WEBrick/1.3.1 (Ruby/1.9.2/2011-07-09) 

编辑:更新了url设置为url:“http://0.0.0.0:3000/hotels.json

它可以捕获但不能使其他人CRUD(示例PUT)

 hotels = new Hotels() Object hotels.fetch() Object hotels.length 5 hotel = hotels.get(2) Object hotel.set({name: "name 2"}) Object hotel.save() Object PUT http://0.0.0.0:3000/hotels.json/2 404 (Not Found) 

相反,如果我只设置/酒店它工作(但骨干客户端必须驻留在服务器上)

编辑2:

在github上传了代码

https://github.com/RevH/backbonefails

编辑3:

另一个细节是,如果您将backboneclient目录插入Rails公共目录并将0.0.0.0:3000/hotels.json更改为/ hotels它非常棒!! 但是如果我将客户端与服务器分开并用Safari打开它,则需要在URL的末尾使用.json。 这很奇怪。

我在https://github.com/rails/rails/issues/5005上打开github上的rails问题

需要了解的重要一点是,Rails中的最佳实践不是使用Accept标头。 这里有一篇很好的文章,它解释了为什么要有光荣的细节。 摘要是HTTP Accept标头的浏览器实现已损坏。 Rails的最佳实践是在请求中设置:format参数。 但是,如果您喜欢它们受支持的接受标题,但有关rails中有效接受标头的规则可能会非常棘手。 如果您的接受标头与以下正则表达式匹配:

 BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ 

然后rails将其抛弃并默认为text / html mime类型。 我知道,对吧? 您的标题恰好与此匹配。 大多数人没有这个问题的原因是rails“修复”了rails jquery-ujs中的默认jquery行为。 他们在JQuery中设置了ajaxSetup之前的回调,它将*/*放在标题的开头,这就是魔术乐队正则表达式想要看到的,虽然我无法真正说出原因,除了他们知道未经修改的浏览器请求将会总是把它放在那里。 以下是如何在JQuery中修复接受标头的方法。

 $(function() { $.ajaxSetup({ 'beforeSend': function(xhr) { xhr.setRequestHeader("accept", "application/json"); } }); }); 

你已经设置了rails代码,所以它需要调用/hotels.json才能返回json,但你的骨干代码只是调用/hotels

解决这个问题的最简单方法是为json数据提供一个单独的api,而不是html页面。 例如: /hotels返回html和/api/hotels返回json。 请参阅Ryan Bate的Railscasts以获取此示例(付费) http://railscasts.com/episodes/323-backbone-on-rails-part-1

另一种选择是更改Backbone模型/集合,以便将“.json”附加到url的末尾。 例如:

 Backbone.Model.extend({ url: function(){ var url; if (this.isNew()){ url = "/hotels/" + this.id + ".json"; } else { url = "/hotels.json"; } return url; } }); 

还有其他选择。 这些只是我头脑中的两个。

当您的javascript应用程序在与您的服务器不同的域,端口或协议上运行时,会发生奇怪的事情。 这称为同源策略。 只需从rails服务器加载javascript,一切都会好的。