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

时间:2012-02-11 14:42:49

标签: ruby-on-rails json cordova backbone.js client-server

背景

我用“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问题

3 个答案:

答案 0 :(得分:10)

要理解的重要一点是,Rails中的最佳实践不是使用Accept标头。有一个很好的写作here,可以用光荣的细节解释原因。摘要是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");
    }
  });
});

答案 1 :(得分:1)

您已设置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”附加到网址的末尾。例如:


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

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

答案 2 :(得分:0)

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