Как получить доступ к среде Rack из Rails? - PullRequest
31 голосов
/ 11 мая 2009

У меня есть приложение 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?

Обновление : Спасибо Gaius за ответ. Rack и 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

Ответы [ 2 ]

26 голосов
/ 12 мая 2009

Я почти уверен, что вы можете использовать объект 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
21 голосов
/ 29 мая 2014

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

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

Согласно Руководство по Rails для контроллеров 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 :: Parameters , который включается в ActionDispatch::Request , Этот метод очень похож на метод Rack::Request#params, за исключением того, что его изменение изменяет специфичную для Rails переменную среды Rack (и, следовательно, изменения останутся постоянными во всех случаях ActionDispatch::Request) .

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

Подведем итог:

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

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

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

...