복붙노트

[RUBY-ON-RAILS] 레일 3 루비 : 클라이언트에 레일을 통해 스트리밍 데이터

RUBY-ON-RAILS

레일 3 루비 : 클라이언트에 레일을 통해 스트리밍 데이터

나는 루비 레일에 응용 프로그램 일하고 그 랙 스페이스의 cloudfiles와 통신 (아마존 S3와 유사하지만 일부 기능을 결여).

때문에 당 오브젝트 액세스 권한의 가용성 및 쿼리 문자열 인증의 부족으로, 사용자가 다운로드하는 응용 프로그램을 통해 중재해야합니다.

레일 2.3에서는 다음과 같이 동적 응답을 구축 할 수 있습니다 같다 :

# Streams about 180 MB of generated data to the browser.
render :text => proc { |response, output|
  10_000_000.times do |i|
    output.write("This is line #{i}\n")
  end
}

(행 http://api.rubyonrails.org/classes/ActionController/Base.html#M000464)

대신 10_000_000.times의 ... 나는 거기에 내 cloudfiles 스트림 생성 코드를 덤프 수 있습니다.

문제는 내가 레일 3에서이 기술을 사용하려고 할 때 내가 얻을 출력이다.

#<Proc:0x000000010989a6e8@/Users/jderiksen/lt/lt-uber/site/app/controllers/prospect_uploads_controller.rb:75>

같은 외모는 어쩌면 시저 객체의 호출 메서드가 호출되지 않는? 어떤 다른 아이디어?

해결법

  1. ==============================

    1.이 레일에서 사용할 수없는 것 같습니다 3

    이 레일에서 사용할 수없는 것 같습니다 3

    https://rails.lighthouseapp.com/projects/8994/tickets/2546-render-text-proc

    이것은 내 컨트롤러에서 나를 위해 일에 출연 :

    self.response_body =  proc{ |response, output|
      output.write "Hello world"
    }
    
  2. ==============================

    2.응답이 #each에 개체를 response_body에 할당 :

    응답이 #each에 개체를 response_body에 할당 :

    class Streamer
      def each
        10_000_000.times do |i|
          yield "This is line #{i}\n"
        end
      end
    end
    
    self.response_body = Streamer.new
    

    당신이 1.9.x 또는 백 포트 보석을 사용하는 경우, 당신은 더 많은 콤팩트 Enumerator.new를 사용하여이 쓸 수 있습니다 :

    self.response_body = Enumerator.new do |y|
      10_000_000.times do |i|
        y << "This is line #{i}\n"
      end
    end
    

    데이터가 플러시 될 경우 랙 핸들러 기반 서버에 의존 할 때 사용되는 것을 유의해야한다. 나는 잡종은, 예를 들어, 데이터를 스트리밍 것을 확인했지만, 다른 사용자에 WEBrick은, 예를 들어, 버퍼를 응답이 닫힐 때까지보고있다. 플러시에 대한 응답을 강제 할 수있는 방법은 없습니다.

    레일 3.0.x 버전에서 몇 가지 추가 망 가지고있다 :

    이 두 문제는 HTTP 스트리밍 윤곽 기능입니다 레일 3.1에 고정되어 있습니다.

    참고 다른 일반적인 제안, self.response_body = PROC {| 응답, 출력 | ...}, 레일 3.0.x 버전에서 작업을 수행하지만, 사용되지 않습니다 (더 이상 실제로 데이터를 스트리밍하지 않습니다) 3.1. 응답 모든 레일 3 버전에서 작품을 #each하는 것을 객체를 할당.

  3. ==============================

    3.모든 게시물에 대한 감사 위, 여기에 완벽하게 코드를 작동하는 것은 큰 CSV를 스트리밍합니다. 이 코드 :

    모든 게시물에 대한 감사 위, 여기에 완벽하게 코드를 작동하는 것은 큰 CSV를 스트리밍합니다. 이 코드 :

    컨트롤러 방법 :

    def csv_export
      respond_to do |format|
        format.csv {
          @filename = "responses-#{Date.today.to_s(:db)}.csv"
          self.response.headers["Content-Type"] ||= 'text/csv'
          self.response.headers["Content-Disposition"] = "attachment; filename=#{@filename}"
          self.response.headers['Last-Modified'] = Time.now.ctime.to_s
    
          self.response_body = Enumerator.new do |y|
            i = 0
            Model.find_each do |m|
              if i == 0
                y << Model.csv_header.to_csv
              end
              y << sr.csv_array.to_csv
              i = i+1
              GC.start if i%500==0
            end
          end
        }
      end
    end
    

    설정 / unicorn.rb

    # Set to 3 instead of 4 as per http://michaelvanrooijen.com/articles/2011/06/01-more-concurrency-on-a-single-heroku-dyno-with-the-new-celadon-cedar-stack/
    worker_processes 3
    
    # Change timeout to 120s to allow downloading of large streamed CSVs on slow networks
    timeout 120
    
    #Enable streaming
    port = ENV["PORT"].to_i
    listen port, :tcp_nopush => false
    

    Model.rb

      def self.csv_header
        ["ID", "Route", "username"]
      end
    
      def csv_array
        [id, route, username]
      end
    
  4. ==============================

    4.경우에 당신은 응답이 닫힐 때까지 #each 방법에 응답하고 그것의 버퍼링이, 액션 컨트롤러에서 보는 것이 객체를 response_body에 할당된다 :

    경우에 당신은 응답이 닫힐 때까지 #each 방법에 응답하고 그것의 버퍼링이, 액션 컨트롤러에서 보는 것이 객체를 response_body에 할당된다 :

    self.response.headers [ '마지막으로 수정'] = Time.now.to_s

  5. ==============================

    5.그냥 기록을 위해,> = 3.1 개체를 할당하여 데이터를 스트리밍 할 수있는 쉬운 방법이 레일 컨트롤러의 응답 #each 방법에 대한 응답이.

    그냥 기록을 위해,> = 3.1 개체를 할당하여 데이터를 스트리밍 할 수있는 쉬운 방법이 레일 컨트롤러의 응답 #each 방법에 대한 응답이.

    모든 것이 여기에 설명 : http://blog.sparqcode.com/2012/02/04/streaming-data-with-rails-3-1-or-3-2/

  6. ==============================

    6.예, response_body는 잠시 동안이 일의 레일 3 방법은 다음과 같습니다 https://rails.lighthouseapp.com/projects/8994/tickets/4554-render-text-proc-regression

    예, response_body는 잠시 동안이 일의 레일 3 방법은 다음과 같습니다 https://rails.lighthouseapp.com/projects/8994/tickets/4554-render-text-proc-regression

  7. ==============================

    7.이뿐만 아니라 내 문제를 해결 - 나는 GzipReader를 사용하여 한 번에 그들에게 선을 읽을 수 있도록 나는, 압축을 푼 CSV로 사용자에게 보내려면, CSV 파일을 gzip으로 압축했다.

    이뿐만 아니라 내 문제를 해결 - 나는 GzipReader를 사용하여 한 번에 그들에게 선을 읽을 수 있도록 나는, 압축을 푼 CSV로 사용자에게 보내려면, CSV 파일을 gzip으로 압축했다.

    당신은 다운로드로 큰 파일을 제공하려는 경우이 라인도 도움이됩니다 :

    self.response.headers [ "의 Content-Type"] = "응용 프로그램 / octet-stream을" self.response.headers [ "콘텐츠 - 처리"= "첨부 파일, 파일 이름 = #} {파일명"

  8. ==============================

    8.또한, 당신은 당신의 자신에 의해 '콘텐츠 길이'헤더를 설정해야합니다.

    또한, 당신은 당신의 자신에 의해 '콘텐츠 길이'헤더를 설정해야합니다.

    그렇지 않은 경우, 랙의 길이를 결정합니다 (메모리에 본문 데이터를 버퍼링) 기다려야 할 것이다. 그리고 위에서 설명한 방법을 사용하여 당신의 노력을 파괴 할 것이다.

    내 경우, 나는 길이를 결정할 수있다. 경우에 당신은, 당신은 '콘텐츠 길이'헤더없이 몸을 보내기 시작 랙을 만들 필요가 없습니다. '실행'하기 전에 '필요'후 config.ru에 "사용 랙 : 청크 분할"을 추가하려고합니다. (감사 arkadiy)

  9. ==============================

    9.난 그냥 성공 대신에 WEBrick의 잡종을 사용하는 데 필요한 불구하고 self.response_body = PROC의 접근 방식은 나를 위해 일한 말하고 싶었다, 등대 티켓에 댓글을 달았습니다.

    난 그냥 성공 대신에 WEBrick의 잡종을 사용하는 데 필요한 불구하고 self.response_body = PROC의 접근 방식은 나를 위해 일한 말하고 싶었다, 등대 티켓에 댓글을 달았습니다.

    남자 이름

  10. ==============================

    10.나를 위해 일한 Exequiel의 제안과 함께 요한의 솔루션을 적용.

    나를 위해 일한 Exequiel의 제안과 함께 요한의 솔루션을 적용.

    self.response.headers['Last-Modified'] = Time.now.to_s
    

    마크 랙에 캐시 할 수없는 응답.

    추가 조사 후, 나는 하나가이 사용할 수 생각 :

    headers['Cache-Control'] = 'no-cache'
    

    이것은 나에게, 단지 약간 더 직관적이다. 그것은 내 코드를 읽을 수 있습니다 다른 any1에 메시지를 전달한다. 또한, 경우에 랙의 미래 버전이 마지막으로 수정 검사 중지, 많은 코드가 깨질 수 있으며, 그 이유를 알아 내기 위해 사람들을위한 잠시 동안 할 수있다.

  11. from https://stackoverflow.com/questions/3507594/ruby-on-rails-3-streaming-data-through-rails-to-client by cc-by-sa and MIT license