带有远程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,一切都会好的。