【问题标题】:BackBone client with a remote Rails Server带有远程 Rails 服务器的 BackBone 客户端
【发布时间】:2012-02-11 14:42:49
【问题描述】:

背景:

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

我使用 Safari file:///Users/lg/Workspace/www/index.html 在本地打开 Backbone 客户端以测试客户端,因为我的想法是将 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)

如果我只设置 /hotels 它可以工作(但骨干客户端必须驻留在服务器上)

编辑 2:

将代码上传到github

https://github.com/RevH/backbonefails

编辑 3:

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

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

【问题讨论】:

  • 你为什么不直接向它询问json? /hotels.json
  • 因为如果我只插入 /hotels,Backbone 可以使用 REST 调用所有 CRUD 方法(这有效,但不能使用远程 url)
  • 我不关注。当然它无论如何都可以调用所有的 CRUD 方法,因为它们依赖于给定的参数和 HTTP 方法,而不是格式。
  • 我更新了我的原始帖子,并在 url 处附加了 .json 格式的示例
  • 格式放在 URL 的末尾,而不是中间。

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


【解决方案1】:

要理解的重要一点是,Rails 中的最佳实践是不要使用 Accept 标头。有一篇很好的文章here 详细解释了原因。总结是 HTTP Accept 标头的浏览器实现被破坏了。 Rails 的最佳实践是在请求中设置 :format 参数。但是,如果您喜欢接受标头,它们是受支持的,但是关于什么是 rails 中有效的接受标头的规则可能会很棘手。如果您的接受标头与以下正则表达式匹配:

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

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

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

【讨论】:

    【解决方案2】:

    您已设置 Rails 代码,因此它需要调用 /hotels.json 才能返回 json,但您的主干代码仅调用 /hotels

    解决此问题的最简单方法是为 json 数据提供单独的 api,而不是为 html 页面提供单独的 api。例如:/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;
      }
    });
    

    可能还有其他选择。这只是我想到的两个。

    【讨论】:

    • 我认为当我有响应的方法时,Rails 会使用 format.json 而不是 format.html 自动拦截请求标头设置为“application/json”的 /hotels 调用使用 format.html 和 format.json。如果这是一种预期的行为,我更喜欢为 json 制作一个单独的 api,但是如果我必须制作一个重复的控制器来仅以 RESTful 方式处理 json,这似乎不是很干。
    • 感谢 Derick,但如果您将主干客户端目录插入 Rails 公共目录并将 0.0.0.0:3000/hotels.json 更改为 /hotels 效果非常好!!但是,如果我将客户端与服务器分开并使用 Safari 打开它,它需要 .json 在 url 的末尾。 这很奇怪
    • 另一个选项是在 routes.rb 资源中将 json 设置为默认值:model_name, defaults: {format: :json}
    【解决方案3】:

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

    【讨论】:

    • 同源策略不适用于 file:// 协议 wiki.phonegap.com/w/page/16494770/FAQ
    • 那么,当您的文件托管在 Rails 服务器上时,它为什么会起作用?
    • 我在 Webbrick 本地服务器和 Heroku 上进行了尝试。我认为这是 Rails 的错误,因为如果我有一个只有 render :json => Hotel.all 的索引方法(没有 format.html 所以)它工作正常。我也在 github 上开了一张票。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-11
    • 2012-09-25
    • 1970-01-01
    • 1970-01-01
    • 2012-04-06
    • 2019-01-29
    相关资源
    最近更新 更多