tom_302
2012-Jul-28 03:20 UTC
run :before_filter before loading controller''s ActiveRecord model?
Hello, I''m creating a Rails app on top of a legacy document management system. I''m looking for a way to force an ApplicationController''s :before_filter method to execute before the ActiveRecord model is evaluated: class *Document* << ActiveRecord::Base acts_as_controlled end My acts_as_controlled() method generates different SQL criteria & bindings for scopes and finders based on the state of the Document and whether it''s checkout out by the current user (MGR.user) vs checked out by another user, vs checked in. The model''s default_scope matches the check in, checked out, or working copy accordingly to provide the correct records. The legacy application uses basic http auth and my rails application is deployed in the same context, so I obtain MGR.user from the http request using :before_filter: class *ApplicationController* < ActionController::Base before_filter :authenticate def authenticate auth_data = Base64.decode64(request.authorization.split('' '', 2).last || '''').split(/:/, 2) MGR.user=auth_data[0] MGR.pass=auth_data[1] end end class *DocumentsController* < ApplicationController def index @documents = Document.all respond_to do |format| format.html # index.html.erb format.json { render :json => @documents } end end end This authentication works only if the first request goes to a controller that doesn''t use an ActiveRecord model that acts_as_controlled. If the initial request goes to DocumentController, the Document model is loaded and acts_as_controlled is called *before* ApplicationController''s :before_filter can set MGR.user: Started GET "/MyApp/documents" for 127.0.0.1 at Thu Jul 26 18:05:52 -0700 2012 NativeException ([from a java method of the legacy application]): config/initializers/myapp.rb:169:in `current_user'' config/initializers/myapp.rb:351:in `define_model_scope'' config/initializers/myapp.rb:625:in `acts_as_controlled'' app/models/document.rb:2:in `Document'' app/models/document.rb:1:in `(root)'' app/models/document.rb:456:in `load_file'' app/controllers/documents_controller.rb:1:in `(root)'' * app/controllers/documents_controller.rb:456:in `load_file''* Rendered vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb (27.0ms) Rendered vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (3.0ms) Rendered vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (46.0ms) One solution would be to short-circuit acts_as_controlled if MGR.user isn''t set, store a reference to the model, and finally execute acts_as_controlled on all referenced models at the end of the :before_filter method, but that approach would mean evaluating each model twice. Is there a better way to make ApplicationController :before_filter execute before the Document model is evaluated by DocumentController? PS: Also, is it even safe to store the user id in a constant like MGR? I haven''t seen any warnings about it being redefined so far, but I''m not quite sure how rails instances are managed across requests & sessions with JRuby and Tomcat. Thanks in advance for your advice. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/W6C4BcdlFB0J. For more options, visit https://groups.google.com/groups/opt_out.
Frederick Cheung
2012-Jul-28 15:06 UTC
Re: run :before_filter before loading controller''s ActiveRecord model?
On Saturday, July 28, 2012 4:20:36 AM UTC+1, tom_302 wrote:> > NativeException ([from a java method of the legacy application]): > > config/initializers/myapp.rb:169:in `current_user'' > > config/initializers/myapp.rb:351:in `define_model_scope'' > > config/initializers/myapp.rb:625:in `acts_as_controlled'' > > app/models/document.rb:2:in `Document'' > > app/models/document.rb:1:in `(root)'' > > app/models/document.rb:456:in `load_file'' > > app/controllers/documents_controller.rb:1:in `(root)'' > > * app/controllers/documents_controller.rb:456:in `load_file''* > > > Rendered > vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb > (27.0ms) > > Rendered > vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb > (3.0ms) > > Rendered > vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb > within rescues/layout (46.0ms) > > > One solution would be to short-circuit acts_as_controlled if MGR.user > isn''t set, store a reference to the model, and finally execute > acts_as_controlled on all referenced models at the end of the > :before_filter method, but that approach would mean evaluating each model > twice. > > > Is there a better way to make ApplicationController :before_filter execute > before the Document model is evaluated by DocumentController? > > >This sounds horribly brittle (and in production mode the whole application is loaded at boot time, so I think you''ll have problems too). I think you''d be better off rethinking how your acts_as_controlled method works (for example generate the scopes using lambda so that they can change their conditions at runtime)> PS: Also, is it even safe to store the user id in a constant like MGR? I > haven''t seen any warnings about it being redefined so far, but I''m not > quite sure how rails instances are managed across requests & sessions with > JRuby and Tomcat. >That depends entirely on what MGR.user= does. That could be implemented in a threadsafe way (eg using Thread.current) or in a thread dangerous way Fred>-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/T4iiB805qRMJ. For more options, visit https://groups.google.com/groups/opt_out.
tom_302
2012-Jul-29 17:54 UTC
Re: run :before_filter before loading controller''s ActiveRecord model?
Thanks - and good call on the lambda for delaying evaluation of the user_id. Unfortunately, I also need the user_id to authenticate with the legacy application in order to load its codebase; I''m defining my ActiveRecord models dynamically from this codebase. I''ve been able to use AR scopes to hide all of the checkin/checkout/version control. And I can pull the http authentication off any request. I just wish the controller could evaluate my :before_filter before it evaluates its AR models. I''m looking into alternatives, but I''d have to give up the dynamic model definition and loose some flexibility there. Regarding storing the user_id in a constant, i thought rails doesn''t share any information between requests; Isn''t it up to the server to keep variable states separate however it loads/shares instances of the rails application? Please explain. On Saturday, July 28, 2012 11:06:27 AM UTC-4, Frederick Cheung wrote:> > > > On Saturday, July 28, 2012 4:20:36 AM UTC+1, tom_302 wrote: > >> >> NativeException ([from a java method of the legacy application]): >> >> config/initializers/myapp.rb:169:in `current_user'' >> >> config/initializers/myapp.rb:351:in `define_model_scope'' >> >> config/initializers/myapp.rb:625:in `acts_as_controlled'' >> >> app/models/document.rb:2:in `Document'' >> >> app/models/document.rb:1:in `(root)'' >> >> app/models/document.rb:456:in `load_file'' >> >> app/controllers/documents_controller.rb:1:in `(root)'' >> >> * app/controllers/documents_controller.rb:456:in `load_file''* >> >> >> Rendered >> vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb >> (27.0ms) >> >> Rendered >> vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb >> (3.0ms) >> >> Rendered >> vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb >> within rescues/layout (46.0ms) >> >> >> One solution would be to short-circuit acts_as_controlled if MGR.user >> isn''t set, store a reference to the model, and finally execute >> acts_as_controlled on all referenced models at the end of the >> :before_filter method, but that approach would mean evaluating each model >> twice. >> >> >> Is there a better way to make ApplicationController :before_filter >> execute before the Document model is evaluated by DocumentController? >> >> >> > This sounds horribly brittle (and in production mode the whole application > is loaded at boot time, so I think you''ll have problems too). I think you''d > be better off rethinking how your acts_as_controlled method works > > (for example generate the scopes using lambda so that they can change > their conditions at runtime) > > > >> PS: Also, is it even safe to store the user id in a constant like MGR? >> I haven''t seen any warnings about it being redefined so far, but I''m not >> quite sure how rails instances are managed across requests & sessions with >> JRuby and Tomcat. >> > > That depends entirely on what MGR.user= does. That could be implemented in > a threadsafe way (eg using Thread.current) or in a thread dangerous way > > Fred > > >>-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/tva2wr1jnLMJ. For more options, visit https://groups.google.com/groups/opt_out.
Frederick Cheung
2012-Jul-29 18:26 UTC
Re: run :before_filter before loading controller''s ActiveRecord model?
On Sunday, July 29, 2012 6:54:50 PM UTC+1, tom_302 wrote:> Thanks - and good call on the lambda for delaying evaluation of the user_id. > > > Unfortunately, I also need the user_id to authenticate with the legacy application in order to load its codebase; I''m defining my ActiveRecord models dynamically from this codebase. > > > I''ve been able to use AR scopes to hide all of the checkin/checkout/version control. And I can pull the http authentication off any request. I just wish the controller could evaluate my :before_filter before it evaluates its AR models. > > > I''m looking into alternatives, but I''d have to give up the dynamic model definition and loose some flexibility there. >I really think that anything that depends on class load order is fatally flawed (and as I said before, in production mode rails will load your app classes before the first request arrives.> > Regarding storing the user_id in a constant, i thought rails doesn''t share any information between requests; Isn''t it up to the server to keep variable states separate however it loads/shares instances of the rails application? Please explain. > >Rails doesn''t enforce anything like this. Controller instances only last the length of the corresponding request, so anything set there ''disappears'' but (except in development mode) classes aren''t reloaded between requests : class variables, constants etc. are shared across requests, and will obviously trigger weird behaviour if you run rails in threadsafe modd Fred> > On Saturday, July 28, 2012 11:06:27 AM UTC-4, Frederick Cheung wrote: > > On Saturday, July 28, 2012 4:20:36 AM UTC+1, tom_302 wrote: > > > > > NativeException ([from a java method of the legacy application]): > > config/initializers/myapp.rb:169:in `current_user'' > > config/initializers/myapp.rb:351:in `define_model_scope'' > > config/initializers/myapp.rb:625:in `acts_as_controlled'' > > app/models/document.rb:2:in `Document'' > > app/models/document.rb:1:in `(root)'' > > app/models/document.rb:456:in `load_file'' > > app/controllers/documents_controller.rb:1:in `(root)'' > > app/controllers/documents_controller.rb:456:in `load_file'' > > > > > Rendered vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb (27.0ms) > > Rendered vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (3.0ms) > > Rendered vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (46.0ms) > > > > > One solution would be to short-circuit acts_as_controlled if MGR.user isn''t set, store a reference to the model, and finally execute acts_as_controlled on all referenced models at the end of the :before_filter method, but that approach would mean evaluating each model twice. > > > > > Is there a better way to make ApplicationController :before_filter execute before the Document model is evaluated by DocumentController? > > > > > > > This sounds horribly brittle (and in production mode the whole application is loaded at boot time, so I think you''ll have problems too). I think you''d be better off rethinking how your acts_as_controlled method works > > > (for example generate the scopes using lambda so that they can change their conditions at runtime) > > > > > > PS: Also, is it even safe to store the user id in a constant like MGR? I haven''t seen any warnings about it being redefined so far, but I''m not quite sure how rails instances are managed across requests & sessions with JRuby and Tomcat. > > > That depends entirely on what MGR.user= does. That could be implemented in a threadsafe way (eg using Thread.current) or in a thread dangerous way > > > Fred-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/teVdCdeyJFkJ. For more options, visit https://groups.google.com/groups/opt_out.
tom_302
2012-Jul-29 19:10 UTC
Re: run :before_filter before loading controller''s ActiveRecord model?
What''s the best place to keep the user_id from the request, so it can be referenced from the scope''s lambda method? Rather than store it in MGR.user_id, is there a safer place to store it? (or is there a way to access the request object outside of the controller?) On Sunday, July 29, 2012 2:26:30 PM UTC-4, Frederick Cheung wrote:> > On Sunday, July 29, 2012 6:54:50 PM UTC+1, tom_302 wrote: > > Thanks - and good call on the lambda for delaying evaluation of the > user_id. > > > > > > Unfortunately, I also need the user_id to authenticate with the legacy > application in order to load its codebase; I''m defining my ActiveRecord > models dynamically from this codebase. > > > > > > I''ve been able to use AR scopes to hide all of the > checkin/checkout/version control. And I can pull the http authentication > off any request. I just wish the controller could evaluate my > :before_filter before it evaluates its AR models. > > > > > > I''m looking into alternatives, but I''d have to give up the dynamic model > definition and loose some flexibility there. > > > > I really think that anything that depends on class load order is fatally > flawed (and as I said before, in production mode rails will load your app > classes before the first request arrives. > > > > > Regarding storing the user_id in a constant, i thought rails doesn''t > share any information between requests; Isn''t it up to the server to keep > variable states separate however it loads/shares instances of the rails > application? Please explain. > > > > > Rails doesn''t enforce anything like this. Controller instances only last > the length of the corresponding request, so anything set there ''disappears'' > but (except in development mode) classes aren''t reloaded between requests : > class variables, constants etc. are shared across requests, and will > obviously trigger weird behaviour if you run rails in threadsafe modd > > Fred > > > > > On Saturday, July 28, 2012 11:06:27 AM UTC-4, Frederick Cheung wrote: > > > > On Saturday, July 28, 2012 4:20:36 AM UTC+1, tom_302 wrote: > > > > > > > > > > NativeException ([from a java method of the legacy application]): > > > > config/initializers/myapp.rb:169:in `current_user'' > > > > config/initializers/myapp.rb:351:in `define_model_scope'' > > > > config/initializers/myapp.rb:625:in `acts_as_controlled'' > > > > app/models/document.rb:2:in `Document'' > > > > app/models/document.rb:1:in `(root)'' > > > > app/models/document.rb:456:in `load_file'' > > > > app/controllers/documents_controller.rb:1:in `(root)'' > > > > app/controllers/documents_controller.rb:456:in `load_file'' > > > > > > > > > > Rendered > vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb > (27.0ms) > > > > Rendered > vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb > (3.0ms) > > > > Rendered > vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb > within rescues/layout (46.0ms) > > > > > > > > > > One solution would be to short-circuit acts_as_controlled if MGR.user > isn''t set, store a reference to the model, and finally execute > acts_as_controlled on all referenced models at the end of the > :before_filter method, but that approach would mean evaluating each model > twice. > > > > > > > > > > Is there a better way to make ApplicationController :before_filter > execute before the Document model is evaluated by DocumentController? > > > > > > > > > > > > > > This sounds horribly brittle (and in production mode the whole > application is loaded at boot time, so I think you''ll have problems too). I > think you''d be better off rethinking how your acts_as_controlled method > works > > > > > > (for example generate the scopes using lambda so that they can change > their conditions at runtime) > > > > > > > > > > > > PS: Also, is it even safe to store the user id in a constant like MGR? > I haven''t seen any warnings about it being redefined so far, but I''m not > quite sure how rails instances are managed across requests & sessions with > JRuby and Tomcat. > > > > > > That depends entirely on what MGR.user= does. That could be implemented > in a threadsafe way (eg using Thread.current) or in a thread dangerous way > > > > > > Fred > >-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/nGb2d39nwaAJ. For more options, visit https://groups.google.com/groups/opt_out.
Frederick Cheung
2012-Jul-29 20:51 UTC
Re: run :before_filter before loading controller''s ActiveRecord model?
On Sunday, July 29, 2012 8:10:11 PM UTC+1, tom_302 wrote:> > What''s the best place to keep the user_id from the request, so it can be > referenced from the scope''s lambda method? Rather than store it in > MGR.user_id, is there a safer place to store it? (or is there a way to > access the request object outside of the controller?) > > MGR.user_id isn''t necessarily a bad thing - it just depends how that isimplemented: #Unsafe class MGR class << self attr_accessor :user_id end end #Safe class MGR class << self def user_id Thread.current[:mgr_user_id] = value end def user_id Thread.current[:mgr_user_id] end end end If you''re concerned about polluting the Thread.current namespace you can also use a hash keyed by the id of the current thread although that does require that you cleanup old values from the hash Fred> On Sunday, July 29, 2012 2:26:30 PM UTC-4, Frederick Cheung wrote: >> >> On Sunday, July 29, 2012 6:54:50 PM UTC+1, tom_302 wrote: >> > Thanks - and good call on the lambda for delaying evaluation of the >> user_id. >> > >> > >> > Unfortunately, I also need the user_id to authenticate with the legacy >> application in order to load its codebase; I''m defining my ActiveRecord >> models dynamically from this codebase. >> > >> > >> > I''ve been able to use AR scopes to hide all of the >> checkin/checkout/version control. And I can pull the http authentication >> off any request. I just wish the controller could evaluate my >> :before_filter before it evaluates its AR models. >> > >> > >> > I''m looking into alternatives, but I''d have to give up the dynamic >> model definition and loose some flexibility there. >> > >> >> I really think that anything that depends on class load order is fatally >> flawed (and as I said before, in production mode rails will load your app >> classes before the first request arrives. >> >> > >> > Regarding storing the user_id in a constant, i thought rails doesn''t >> share any information between requests; Isn''t it up to the server to keep >> variable states separate however it loads/shares instances of the rails >> application? Please explain. >> > >> > >> Rails doesn''t enforce anything like this. Controller instances only last >> the length of the corresponding request, so anything set there ''disappears'' >> but (except in development mode) classes aren''t reloaded between requests : >> class variables, constants etc. are shared across requests, and will >> obviously trigger weird behaviour if you run rails in threadsafe modd >> >> Fred >> >> > >> > On Saturday, July 28, 2012 11:06:27 AM UTC-4, Frederick Cheung wrote: >> > >> > On Saturday, July 28, 2012 4:20:36 AM UTC+1, tom_302 wrote: >> > >> > >> > >> > >> > NativeException ([from a java method of the legacy application]): >> > >> > config/initializers/myapp.rb:169:in `current_user'' >> > >> > config/initializers/myapp.rb:351:in `define_model_scope'' >> > >> > config/initializers/myapp.rb:625:in `acts_as_controlled'' >> > >> > app/models/document.rb:2:in `Document'' >> > >> > app/models/document.rb:1:in `(root)'' >> > >> > app/models/document.rb:456:in `load_file'' >> > >> > app/controllers/documents_controller.rb:1:in `(root)'' >> > >> > app/controllers/documents_controller.rb:456:in `load_file'' >> > >> > >> > >> > >> > Rendered >> vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb >> (27.0ms) >> > >> > Rendered >> vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb >> (3.0ms) >> > >> > Rendered >> vendor/bundle/jruby/1.8/bundler/gems/rails-80f6547f5b25/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb >> within rescues/layout (46.0ms) >> > >> > >> > >> > >> > One solution would be to short-circuit acts_as_controlled if MGR.user >> isn''t set, store a reference to the model, and finally execute >> acts_as_controlled on all referenced models at the end of the >> :before_filter method, but that approach would mean evaluating each model >> twice. >> > >> > >> > >> > >> > Is there a better way to make ApplicationController :before_filter >> execute before the Document model is evaluated by DocumentController? >> > >> > >> > >> > >> > >> > >> > This sounds horribly brittle (and in production mode the whole >> application is loaded at boot time, so I think you''ll have problems too). I >> think you''d be better off rethinking how your acts_as_controlled method >> works >> > >> > >> > (for example generate the scopes using lambda so that they can change >> their conditions at runtime) >> > >> > >> > >> > >> > >> > PS: Also, is it even safe to store the user id in a constant like >> MGR? I haven''t seen any warnings about it being redefined so far, but I''m >> not quite sure how rails instances are managed across requests & sessions >> with JRuby and Tomcat. >> > >> > >> > That depends entirely on what MGR.user= does. That could be implemented >> in a threadsafe way (eg using Thread.current) or in a thread dangerous way >> > >> > >> > Fred >> >>-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/-kDFhm9CJ1YJ. For more options, visit https://groups.google.com/groups/opt_out.