ITKeyword,专注技术干货聚合推荐

注册 | 登录

解决ruby - How do I access the Rack environment from within Rails?

itPublisher 分享于

2020腾讯云双十一活动,全年最低!!!(领取3500元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1073

2020阿里云最低价产品入口,含代金券(新老用户有优惠),
地址https://www.aliyun.com/minisite/goods

推荐:什么是Rack rails的中间件?

Introducing Rack Tue Feb 20 18:26:03 CET 2007 Dabbling in my own web framework experiments, I noticed that there is a lot of code duplication among fr

I have a Rack application that looks like this:

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

After hooking my Rack application into Rails, how do I get access to env["hello"] from within Rails?

Update: Thanks to Gaius for the answer. Rack and Rails let you store things for the duration of the request, or the duration of the session:

# 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
ruby-on-rails ruby rack middleware
|
  this question
edited May 12 '09 at 14:51 asked May 11 '09 at 15:16 Michael Gundlach 26.3k 11 28 36      Are you certain that Rack::Request.new(env)["foo"] = "bar" changes anything on Rails' end? From what I can see from the source, all that should change is an instance variable on the the Rack::Request object itself. Even the docs for that method say: "Note that modifications will not be persisted in the env. Use update_param or delete_param if you want to destructively modify params." –  Ajedi32 May 29 '14 at 19:52

 | 

2 Answers
2

解决方法

I'm pretty sure you can use the Rack::Request object for passing request-scope variables:

# 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

Alternatively, you can get at that "env" object directly:

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

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

|
  this answer
edited Jun 10 '09 at 19:36 answered May 11 '09 at 21:33 James A. Rosen 34.1k 48 158 239      (I know it's old) I believe the first statement isn't true any more (Rails 4+). Rack::Request.new(env) returns new object each time, therefore you can't persist anything inside it. sources –  Pavel Bulanov Jun 28 '16 at 10:47

 | 

Short answer: Use request.env or env inside a controller.

Long answer:

According to the Rails Guide on Rails controllers, ActionController provides a request method that you can use to access information about the current HTTP request your controller is responding to.

Upon further inspection of the docs for ActionController::Base#request, we see that it "Returns an ActionDispatch::Request instance that represents the current request."

If we look at the docs for ActionDispatch::Request, we see that it inherits from Rack::Request. Aha! Here we go.

Now, in case you're not familiar with the docs for Rack::Request, it's basically a wrapper around the Rack environment. So for most cases, you should just be able to use it as-is. If you really do want the raw environment hash though, you can get it with Rack::Request#env. So within the Rails controller, that would just be request.env.

推荐:Ruby On Rails How to do文章汇总

1、如何利用Passenger配置Ruby on Rails应用程序 http://www.modrails.com/documentation/Users%20guide.html http://www.uhleeka.com/blog/2009/02/ruby-on-rai

Digging deeper:

After further examining the instance methods of ActionController::Base, I noticed there's not a whole lot there to look at. In particular, I noticed the params and session variables seem to be missing. So, I moved up one level to ActionController::Metal, which ActionController::Base inherits from.

In ActionController::Metal, I discovered a method env which had no documentation as to what it did - but I could guess. Turns out I was right. That variable was being assigned to request.env.

ActionController::Metal also contained the params method, which, according to the source, was set to request.parameters by default. As it turns out, request.parameters isn't from Rack::Request, but ActionDispatch::Http::Parameters, which is included by ActionDispatch::Request. This method is very similar to the Rack::Request#params method, except that altering it modifies a Rails-specific Rack environment variable (and therefore changes will remain persistent across instances of ActionDispatch::Request).

However, I still couldn't seem to find the session method. Turns out, it's not in the documentation at all. After searching the source code for ActionController::Metal, I finally found it on this line. That's right, it's just a shortcut for request.session.

To summarize:

In the controller...

  • Use request.env or env to get at the raw environment object
  • Use params to read Rack query strings and post data from the rack input stream. (E.g. Rack::Request#params)
  • Use session to access the value of rack.session in the rack environment

In the middleware...


|
  this answer
edited Aug 19 '16 at 13:27 answered May 29 '14 at 17:34 Ajedi32 17.2k 5 61 104      Was helpful to read Digging Deeper portion, especially about params –  Pavel Bulanov Jun 28 '16 at 11:41

 | 

推荐:使用Rack进行Rails测试

Testing Rails with Rack::Test The biggest news in Rails 2.3 is its support for Rack, the WSGI inspired Ruby web server interface. Of all the Rack good


相关阅读排行


相关内容推荐

最新文章

×

×

请激活账号

为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。

您的注册邮箱: 修改

重新发送激活邮件 进入我的邮箱

如果您没有收到激活邮件,请注意检查垃圾箱。