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.