2012-08-22 32 views
6

Tôi cố gắng tạo một ứng dụng trang đơn với Rails 3.2 và Backbone.js với tùy chọn pushState nhưng phải đối mặt với một cái gì đó mà tôi không hiểu.Làm cách nào để xử lý các URL không phải root trong ứng dụng một trang?

Nếu tôi tải URL gốc của ứng dụng (/), mọi thứ diễn ra đúng: Rails trả về bố cục HTML với JS khởi động Backbone để tạo một số XHR cho các thực thể JSON và hiển thị nội dung.

Nhưng nếu tôi bắt đầu sử dụng ứng dụng từ URL không phải là gốc (ví dụ: bằng cách nhập thủ công trong thanh địa chỉ của trình duyệt) thì Rails sẽ cố gắng xử lý yêu cầu này bằng quy tắc định tuyến của họ từ các tuyến đường. đó là tuyến đường "Backbone". Làm cách nào để tải trang và bootstrap Backbone để xử lý URL này trong trường hợp đó?

Trả lời

14

Cuối cùng tôi tìm thấy giải pháp.

tôi đặt đoạn mã sau vào routes.rb tôi

class XHRConstraint 
    def matches?(request) 
    !request.xhr? && !(request.url =~ /\.json$/ && ::Rails.env == 'development') 
    end 
end 

match '(*url)' => 'home#index', :constraints => XHRConstraint.new 

Với khớp này tất cả những yêu cầu không XHR được chuyển đến HomeController mà trả về một trang HTML. Và các yêu cầu XHR sẽ được xử lý bởi các bộ điều khiển khác trả về các phản hồi JSON. Ngoài ra tôi còn yêu cầu kết thúc bằng ".json" là hợp lệ trong môi trường phát triển để gỡ lỗi.

+0

Đàn ông! Điều này nên được upvoted 1000 lần. – wuliwong

+0

Hoạt động hoàn hảo cho tôi! – jordancooperman

+0

Tôi cũng tìm thấy [viết tuyệt vời này bởi nghệ thuật] (http://artsy.github.com/blog/2012/06/25/replacing-hashbang-routes-with-pushstate/) mô tả cách tạo liên kết toàn cầu xử lý với Backbone pushState để tránh làm mới trang, mà tôi cảm thấy là rất nhiều kết hợp với câu trả lời này và có thể giúp một số người. – jordancooperman

1

Đây là một vấn đề khá phức tạp, nhưng về cơ bản, bạn cần trả lời tất cả các yêu cầu (HTML) hợp lệ trong đường ray với cùng một trang (gốc), từ đó xương sống sẽ tiếp quản và định tuyến chính xác xử lý (trong bộ định tuyến bakckbone của bạn).

Tôi đã thảo luận vấn đề này chi tiết hơn ở đây: rails and backbone working together

Về cơ bản những gì tôi làm là tạo ra hành động cho mỗi trang mà tôi muốn để xử lý, và quan điểm trống. Tôi sử dụng respond_with trở lại trang (đó là như nhau trong từng trường hợp) và bởi vì tôi xử lý GET hành động chỉ cho các yêu cầu HTML, tôi thêm dòng này ở phía trên cùng của bộ điều khiển:

respond_to :html, :only => [ :show, :new ] 

yêu cầu JSON là cũng được xử lý với respond_with, nhưng không giống như yêu cầu HTML thực sự trả về tài nguyên được yêu cầu (và thực hiện tác vụ được yêu cầu trong trường hợp PUT, POSTDELETE).

+0

Đã cập nhật câu trả lời của tôi với thông tin thêm một chút. –

+0

Điều đó sẽ thực hiện thủ thuật nhưng nó không phải là cách quá thanh lịch khiến tất cả các tuyến đường của Backbone phải chịu trách nhiệm của Rails. Vì vậy, bạn phải cập nhật các tuyến máy chủ khi bạn thay đổi tuyến đường của khách hàng.Có thực sự không có cách nào để đại biểu tất cả các yêu cầu html đến bộ điều khiển gốc? – fey

+1

Tôi không đồng ý: nếu bạn ủy quyền * tất cả * yêu cầu tới bộ điều khiển gốc thì bạn đang nói rằng tất cả các yêu cầu đều hợp lệ, trong khi thực tế hầu hết là không. Rails * cần * để biết các tuyến đường nào là hợp lệ và không phải là để trả lại mã trạng thái cho các tuyến đường không chính xác, vv Đây là sự trùng lặp nhưng nó là sự trùng lặp quan trọng. Đó là không thể tránh khỏi khi bạn bắt đầu sử dụng pushState. –

1

Xương sống sẽ không được thông báo về thay đổi url của bạn nếu bạn thực hiện thủ công. Thay đổi này sẽ được trình duyệt bắt và nó sẽ thực hiện công việc gửi yêu cầu tới máy chủ như thường lệ.

Tương tự nếu bạn nhấp vào liên kết thông thường, nó sẽ theo sau href mà không thông báo cho Backbone.

Nếu bạn muốn Backbone chịu trách nhiệm về thay đổi url, bạn phải thực hiện nó thông qua các công cụ Backbone bạn có sẵn và đây là Bộ định tuyến riêng.

Vì vậy, nếu bạn muốn thực hiện một sự thay đổi URL trong cách Backbone bạn phải làm điều đó một cách rõ ràng, cái gì đó như:

app.router.navigate("my/route", {trigger: true}); 
Các vấn đề liên quan