2011-01-13 34 views
5

Trong ứng dụng Rails của tôi, tôi có một hành động tạo một tài liệu XML bằng cách sử dụng một khuôn mẫu XML Builder (rxml) và render_to_string. Tài liệu XML được chuyển tiếp đến một máy chủ phụ trợ.Làm cách nào để hiển thị chế độ xem bình thường sau khi sử dụng render_to_string?

Sau khi tạo tài liệu XML, tôi muốn gửi phản hồi HTML thông thường cho trình duyệt, nhưng bằng cách nào đó Rails đang ghi nhớ cuộc gọi đầu tiên đến render_to_string.

Ví dụ:

  • Rails không thể tìm thấy giao diện mặc định show.html.erb vì nó sẽ cho một show.rxml.
  • Chỉ cần đặt render 'mycontroller/show.html.erb' ở cuối trình xử lý tác vụ của tôi khiến Rails tìm mẫu, nhưng trình duyệt không hoạt động vì loại nội dung của tiêu đề phản hồi là text/xml.

Có cách nào để sử dụng render_to_string mà không "làm mờ" phản hồi trình duyệt thực tế không?

EDIT: Dường như trong Rails 2 erase_render_results sẽ thực hiện thủ thuật, nhưng trong Rails 3 nó không còn khả dụng nữa.

+0

Thực tế 'erase_render_results' chỉ đặt cờ thành sai và xóa phản hồi_body - trong nguồn cho render_to_string, loại nội dung được đặt thành nil. Điều này có vẻ như nhiều khả năng vấn đề bạn gặp phải là do. –

Trả lời

2

Câu trả lời thực dụng là sử dụng tệp xem và hai lệnh gọi để hiển thị không phải là Đường dẫn: lượt xem thường là thứ được gửi cho khách hàng và ActionPack được thiết kế để hoạt động theo cách đó.

Điều đó nói rằng, có một cách dễ dàng để đạt được những gì bạn đang cố gắng làm. Thay vì sử dụng ActionView, bạn có thể sử dụng Builder :: XmlMarkup trực tiếp để tạo ra XML của bạn như là một chuỗi:

def action_in_controller 
    buffer = "" 
    xml = Builder::XmlMarkup.new(buffer) 

    # build your XML - essentially copy your view.xml.builder file here 
    xml.element("value") 
    xml.element("value") 

    # send the contents of buffer to your 3rd server 

    # allow your controller to render your view normally 
end 

Có một cái nhìn tại the Builder documentation để xem cách nó hoạt động.

Tính năng khác của Trình tạo mà bạn có thể tận dụng là thực tế rằng nội dung XML được nối vào bộ đệm bằng cách sử dụng <<, vì vậy mọi luồng IO đều có thể được sử dụng. Tùy thuộc vào cách bạn đang gửi nội dung đến máy chủ khác, bạn có thể gói tất cả lên khá độc đáo.

Tất nhiên, điều này có thể kết thúc rất lộn xộn và lâu dài, đó là lý do tại sao bạn muốn đóng gói bit chức năng này trong một lớp khác, hoặc như một phương thức trong mô hình của bạn.

+1

Vấn đề là dữ liệu XML cũng phải có sẵn dưới dạng chế độ xem bình thường, do đó, theo lời khuyên của bạn có nghĩa là sao chép mã (trong trường hợp của tôi) Tuy nhiên, đây là những gì tôi đã làm, cảm ơn bạn. –

2

Dường như đây có thể là lỗi trong đường ray 3 (ít nhất là so với hành vi của render_to_string 2.3.x). Trong số source for 2.3.8, họ rõ ràng thực hiện các bước bổ sung để đặt lại content_type và đặt nội dung phản hồi thành 0 (trong số những thứ khác).

def render_to_string 
    ... 
ensure 
    response.content_type = nil 
    erase_render_results 
    reset_variables_added_to_assigns 
end 

nhưng trong nguồn 3.0.3 cho AbstractController::Rendering

def render_to_string(*args, &block) 
    options = _normalize_args(*args, &block) 
    _normalize_options(options) 
    render_to_body(options) 
end 

Bạn có thể thấy không có cài đặt lại rõ ràng của các biến, render_to_body chỉ trả view_context.render. Có thể là content-type, response_body, vv được xử lý ở những nơi khác và đây là một cá trích đỏ, nhưng bản năng đầu tiên của tôi sẽ được thiết lập

response.headers['Content-Type'] = 'text/html'

sau render_to_string của bạn trước khi thực sự render.

2

Khi di chuyển đá quý actionwebservice tôi gặp phải lỗi tương tự. Trong mã của họ, họ phá vỡ ngoại lệ kép làm bằng cách gọi hàm erase_render_results.

Chức năng này không còn khả dụng trong đường ray3. May mắn là sửa chữa khá dễ dàng (nhưng phải mất một lúc để tìm).

Bên actionwebservice chức năng sau đây được gọi là bên trong một bộ điều khiển để cho phép một giây render:

def reset_invocation_response 
    erase_render_results 
    response.instance_variable_set :@header, Rack::Utils::HeaderHash.new(::ActionController::Response::DEFAULT_HEADERS.merge("cookie" => [])) 
end 

Để làm công việc này trong rails3, bạn chỉ cần phải viết:

def reset_invocation_response 
    self.instance_variable_set(:@_response_body, nil) 
    response.instance_variable_set :@header, Rack::Utils::HeaderHash.new("cookie" => [], 'Content-Type' => 'text/html') 
end 

Hope this helps .

+0

+1 cực kỳ hữu ích, bạn nhận được 5 internets! –

Các vấn đề liên quan