jruby-rack icon indicating copy to clipboard operation
jruby-rack copied to clipboard

Session store `@env` is nil with Rails 7

Open chadlwilson opened this issue 2 years ago • 5 comments

I don't really have any deep experience with Rack or JRuby Rack - so please excuse the question if it speaks to ignorance.

After upgrading a JRuby-on-Rails application from Rails 6.1.7.6 to 7.0.8 I get the following stack traces when accessing any rails pages/controllers.

NoMethodError in StagesController#overview 
undefined method `[]' for nil:NilClass (around line/#86)
      def get_servlet_session(env, create = false)
        servlet_session = env[ENV_SERVLET_SESSION_KEY] # <--- line 86
        invalid = false
        begin
          if servlet_session.nil? ||

coming from

https://github.com/jruby/jruby-rack/blob/710c1a4cbde684f1d0bec5907ba3071d51de0a96/src/main/ruby/jruby/rack/session_store.rb#L45-L45

I'm not quite sure how the @env ends up nil, but there seems to be some Rails-version-coupled stuff here.

https://github.com/jruby/jruby-rack/blob/710c1a4cbde684f1d0bec5907ba3071d51de0a96/src/main/ruby/jruby/rack/session_store.rb#L13-L58

Does anyone know what might have changed that could perhaps break rack or jruby-rack to point me in the right direction? Something to do with autoloading?

uri:classloader:/jruby/rack/session_store.rb:86:in `get_servlet_session'
uri:classloader:/jruby/rack/session_store.rb:45:in `method_missing'
actionpack (7.0.8) lib/action_dispatch/middleware/flash.rb:63:in `commit_flash'
actionpack (7.0.8) lib/action_controller/metal.rb:189:in `dispatch'
actionpack (7.0.8) lib/action_controller/metal.rb:251:in `dispatch'
actionpack (7.0.8) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
actionpack (7.0.8) lib/action_dispatch/routing/route_set.rb:32:in `serve'
actionpack (7.0.8) lib/action_dispatch/journey/router.rb:50:in `block in serve'
org/jruby/RubyArray.java:1989:in `each'
actionpack (7.0.8) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (7.0.8) lib/action_dispatch/routing/route_set.rb:852:in `call'
rack (2.2.8) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.8) lib/rack/etag.rb:27:in `call'
rack (2.2.8) lib/rack/conditional_get.rb:27:in `call'
rack (2.2.8) lib/rack/head.rb:12:in `call'
actionpack (7.0.8) lib/action_dispatch/http/permissions_policy.rb:38:in `call'
actionpack (7.0.8) lib/action_dispatch/http/content_security_policy.rb:36:in `call'
uri:classloader:/jruby/rack/session_store.rb:79:in `context'
rack (2.2.8) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/cookies.rb:704:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (7.0.8) lib/active_support/callbacks.rb:99:in `run_callbacks'
actionpack (7.0.8) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/debug_exceptions.rb:28:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/show_exceptions.rb:29:in `call'
railties (7.0.8) lib/rails/rack/logger.rb:40:in `call_app'
railties (7.0.8) lib/rails/rack/logger.rb:27:in `call'
sprockets-rails (3.4.2) lib/sprockets/rails/quiet_assets.rb:13:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/remote_ip.rb:93:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/request_id.rb:26:in `call'
rack (2.2.8) lib/rack/method_override.rb:24:in `call'
rack (2.2.8) lib/rack/runtime.rb:22:in `call'
activesupport (7.0.8) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/server_timing.rb:61:in `block in call'
actionpack (7.0.8) lib/action_dispatch/middleware/server_timing.rb:26:in `collect_events'
actionpack (7.0.8) lib/action_dispatch/middleware/server_timing.rb:60:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/static.rb:23:in `call'
rack (2.2.8) lib/rack/sendfile.rb:110:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/host_authorization.rb:138:in `call'
railties (7.0.8) lib/rails/engine.rb:530:in `call'
uri:classloader:/rack/handler/servlet.rb:22:in `call' 

chadlwilson avatar Oct 08 '23 15:10 chadlwilson

Thanks for the report Chad, it seems JRuby-Rack's (servlet) session store isn't compatible with Rack 2.2. Honestly, I wasn't even aware that it worked with Rails 6.x given the project has not had much maintenance for a while.

In the mean-time you could switch to simply using the Rails default (cookie) session store..

kares avatar Oct 09 '23 08:10 kares

We've had it working with Rack 2.2 (somehow) via Rails 5.2, 6.0 and 6.1 for some time so not sure what changed about Rails 7 that broke this.

There's also this that might be related 😅 https://github.com/gocd/gocd/blob/c4888b585a239dd32b32a532d0de0b286c62c687/server/src/main/webapp/WEB-INF/rails/config/initializers/session_store.rb#L18

So perhaps it worked in a very limited set of circumstances/usages/hacks. Almost all auth and session 'stuff' for our app is handled in Java-land prior to getting to the RackServlet, upon which Rails is only used for a handful of pages/controllers that have proven "resistant" to migration.

chadlwilson avatar Oct 09 '23 08:10 chadlwilson

yeah, sounds like the fix should be rather simple than, but it still requires someone to do "a lot of" work (ideally getting the test suite/CI running with Rails versions we intend to support). I would be happy to keep this project going but lack time to even properly support my other oss work :disappointed: ...

There's also this that might be related 😅 https://github.com/gocd/gocd/blob/c4888b585a239dd32b32a532d0de0b286c62c687/server/src/main/webapp/WEB-INF/rails/config/initializers/session_store.rb#L18

:heavy_check_mark: that is the proper way to switch to the servlet store but only in a servlet container environment (if you simply remove that initializer this should no longer block you from running)

kares avatar Oct 09 '23 11:10 kares

There's also this that might be related 😅 https://github.com/gocd/gocd/blob/c4888b585a239dd32b32a532d0de0b286c62c687/server/src/main/webapp/WEB-INF/rails/config/initializers ✔️ that is the proper way to switch to the servlet store but only in a servlet container environment (if you simply remove that initializer this should no longer block you from running)

Our current setup is using Jetty started inline as servlet container, deploying a war into Jetty programmatically, of which RackServlet is one of a few servlets handling different routes and then splitting (with some url rewriting) across. Some routes use Java Spring FW, some use Rails/Rack via JRuby. Is that the type of servlet container usage you're referring to that could make this code appropriate?

I believe that's why that is there (not being around when this was all wired together and just taking over as defacto maintainer I'm doing some guessing as to intent and how this all works!)

Regardless, for my own curiosity I'll try removing and see what happens 😅

chadlwilson avatar Oct 09 '23 14:10 chadlwilson

Jetty "inline" (pbly aka embedded) servlet container is still a servlet container :stuck_out_tongue_winking_eye:. If the $servlet_context woud not be there you would not have ended up with jruby-rack's (servlet) session store failure as reported in this issue (assuming the initializer setup you mentioned previously).

JRuby-Rack (e.g. from a configured context-listener) starts an embedded JRuby which eventually sets the $servlet_context globa

Some routes use Java Spring FW, some use Rails/Rack via JRuby.

sounds like a fun project :wink:

kares avatar Oct 09 '23 17:10 kares