Подтвердить что ты не робот

Как получить доступ к среде Rack из Rails?

У меня есть приложение Rack, которое выглядит так:

class Foo
  def initialize(app)
    @app = app
  end
  def call(env)
    env["hello"] = "world"
    @app.call(env)
  end
end

После подключения моего приложения Rack в Rails, как мне получить доступ к env["hello"] из Rails?

Обновить. Спасибо Гаю за ответ. Rack and Rails позволяют хранить вещи на время запроса или продолжительность сеанса:

# in middleware
def call(env)
  Rack::Request.new(env)["foo"] = "bar"  # sticks around for one request

  env["rack.session"] ||= {}
  env["rack.session"]["hello"] = "world" # sticks around for duration of session
end

# in Rails
def index
  if params["foo"] == "bar"
    ...
  end
  if session["hello"] == "world"
    ...
  end
end
4b9b3361

Ответ 1

Я уверен, вы можете использовать объект Rack::Request для передачи переменных области запроса:

# middleware:
def call(env)
  request = Rack::Request.new(env) # no matter how many times you do 'new' you always get the same object
  request[:foo] = 'bar'
  @app.call(env)
end

# Controller:
def index
  if params[:foo] == 'bar'
    ...
  end
end

В качестве альтернативы вы можете напрямую обратиться к этому объекту "env":

# middleware:
def call(env)
  env['foo'] = 'bar'
  @app.call(env)
end

# controller:
def index
  if request.env['foo'] == 'bar'
    ...
  end
end

Ответ 2

Краткий ответ: Используйте request.env или env внутри контроллера.

Длинный ответ:

В соответствии с Rails Guide on Rails-контроллеры, ActionController предоставляет метод request, который можно использовать для доступа к информации о текущем HTTP-протоколе запрос, на который ваш контроллер отвечает.

После дополнительной проверки документов для ActionController::Base#request мы видим, что он "возвращает экземпляр ActionDispatch:: Request, который представляет текущий запрос".

Если мы посмотрим на документы для ActionDispatch::Request, мы увидим, что он наследует от Rack::Request. Ага! Здесь мы идем.

Теперь, если вы не знакомы с документами для Rack::Request, это в основном оболочка вокруг среды Rack. Поэтому в большинстве случаев вы должны просто использовать его как есть. Если вы действительно хотите хеш-память исходной среды, вы можете получить ее с помощью Rack::Request#env. Поэтому в контроллере Rails это будет request.env.

Копаем глубже:

После дальнейшего изучения методов экземпляра ActionController::Base я заметил, что там не так много всего, на что можно посмотреть. В частности, я заметил, что переменные params и session, кажется, отсутствуют. Итак, я поднялся на один уровень до ActionController::Metal, который ActionController::Base наследует от.

В ActionController::Metal я обнаружил метод env, у которого не было документации о том, что он сделал, но я мог догадаться. Оказывается, я был прав. Эта переменная была назначена request.env.

ActionController::Metal также содержал params, который, согласно источник, был установлен в request.parameters по умолчанию. Как оказалось, request.parameters не от Rack::Request, но ActionDispatch:: Http:: Параметры, который включен ActionDispatch::Request. Этот метод очень похож на метод Rack::Request#params, за исключением того, что его изменение изменяет переменную среды Rack, специфичную для Rails (и поэтому изменения останутся постоянный через экземпляры ActionDispatch::Request).

Однако мне все еще не удалось найти метод session. Оказывается, это совсем не в документации. После поиска исходного кода ActionController::Metal я наконец нашел его на этой строки. Это правильно, это просто ярлык для request.session.

Подводя итог:

В контроллере...

  • Используйте request.env или env для доступа к объекту исходной среды
  • Используйте params для чтения строк строк в стойке и отправки данных из входного потока стойки. (Например, Rack::Request#params)
  • Используйте session для доступа к значению rack.session в среде стойки

В промежуточном программном обеспечении...