Async_Sinatra в Rails: асинхронные действия не могут записывать в общий сеанс - PullRequest
2 голосов
/ 14 июля 2011

У меня есть класс Sinatra в проекте Rails.Он использует eventmachine и async_sinatra для выполнения асинхронных вызовов на внешние сайты.Я хотел бы записать в объект сеанса (в идеале, тот же, который использует Rails), но пока я могу только:

  • писать в отдельный объект сеанса из Rails '(по умолчанию)Sinatra называет свой сеанс чем-то отличным от Rails)
  • запись в тот же сеанс только для только синхронные вызовы

Когда я выполняю асинхронные вызовы, сеансы записываются вКод async_sinatra не выталкивается на клиентский компьютер.Я подозреваю, что происходит одно из двух:

  • Заголовок уже отправлен клиенту, и локальная переменная, хранящая сеанс (в Синатре), будет сброшена в концедействие.Клиент никогда не увидит запрос от сервера на сохранение этих данных в cookie.

  • Заголовок отправляется клиенту , но Rails немедленно отправляет другойпоручить клиенту записать в cookie то, что Rails сохранил в его переменной session, перезаписать то, что написал Синатра.

В любом случае, я хотел бы просто получить простую функциональность сеансав Синатре и Рельсах.Было бы неплохо объяснить, что я делаю неправильно:)

Полная рабочая копия кода на github , но я считаю, что проблема именно в этом коде:

class ExternalCall < Sinatra::Base
  use ActionDispatch::Session::CookieStore
  register Sinatra::Async  

  get '/sinatra/local' do
    session[:demo] = "sinatra can write to Rails' session"
  end

  aget '/sinatra/goog' do
    session[:async_call]="async sinatra calls cannot write to Rails' session"
    make_async_req :get, "http://www.google.com/" do |http_callback|
      if http_callback
        session[:em_callback] = "this also isn't saving for me" 
      else
        headers 'Status' => '422'
      end
      async_schedule { redirect '/' }

    end
  end


  helpers do
    def make_async_req(method, host, opts={}, &block)
      opts[:head] = { 'Accept' => 'text/html', 'Connection' => 'keep-alive' }
      http = EM::HttpRequest.new(host)
      http = http.send(method, {:head => opts[:head], :body => {}, :query => {}})
      http.callback &block
    end
  end
end

РЕДАКТИРОВАТЬ 7/15 :

Изменен код на Github для включения Async-Rack.Async-sinatra может записывать сеансы, когда они не совместно используются Rails.Сравните ветки master и segmented_sessions на разницу в поведении.(Или в ветке master измените use ActionDispatch::Session::CookieStore на enable :sessions)

1 Ответ

1 голос
/ 15 июля 2011

Это потому, что async_sinatra использует throw :async по умолчанию, эффективно пропуская логику промежуточного программного обеспечения сеанса для хранения данных.Вы можете переопределить async_response так:

helpers do
  def async_response
    [-1, {}, []]
  end
end
...