How extend ActionController?

I have some code in ApplicationController to initialize a logging system
I use to help write new complex stuff and trace exactly what’s going on
during development. It’s just a few little extra steps added to the
basic Ruby logger.

I would like to move the code into something that can be enabled with a
command similar to how sessions or filters are used. I can’t quite
figure out how to do this. I understand the basics of modules, but only
half grasping how Rails is implementing this in its hierarchy.

By poking around and imitating what I am seeing, I have this so far:

module ActionController
module RequestTrace
def self.included(base)
base.extend(ClassMethods)
end

module ClassMethods
  def request_trace(status)
    ..... my code .....
  end
end

end
end

I then add a require statement to environment.rb to load the file, but I
keep getting the error that there’s no such method request_trace for
ApplicationController.

A few months ago I was ableto extend AR Validators with some custom
ones, but the techniques I followed to do that aren’t working for this
case either (very similar to above w/o the self.included bit).

Currently I am using 1.2.6. Any guidance much appreciated…

– gw

On 12 May 2008, at 21:11, Greg W. wrote:

command similar to how sessions or filters are used. I can’t quite
figure out how to do this. I understand the basics of modules, but
only
half grasping how Rails is implementing this in its hierarchy.

I think it would help to see more of what you’ve done. What you wrote
below seems reasonable enough, but you haven’t shown how you’re using
or exactly what errors you’re getting.

Fred

On May 12, 2008, at 1:36 PM, Frederick C. wrote:

I think it would help to see more of what you’ve done. What you wrote
below seems reasonable enough, but you haven’t shown how you’re using
or exactly what errors you’re getting.

Thanks for your time on this Fred…

This is a system adapted from a framework of my own in another
language. There may be a more idiomatic way to do the same, but it’s
something I implemented right away when I started with rails as
something already familiar to me in concept and usage to help get me
going.

Current code (distilled to essentials):

#----- environment.rb --------

require ‘init_constants’

#----- init_constants.rb --------

DISABLED = false
ENABLED = 1
CHATTY = 3
VERBOSE = 5

TRACE_FILE = ‘log/request_trace.log’
$request_trace = DISABLED

#----- application.rb --------

class ApplicationController < ActionController::Base

before_filter :initialize_response

def initialize_response
…other code…
$request_trace = ENABLED
if $request_trace
File.delete(TRACE_FILE) if FileTest::exist?(TRACE_FILE)
$request_trace = Logger.new(TRACE_FILE)
$request_trace.info(“ApplicationController.initialize_response”)
end
…other code…
end

#------------------------------

At this point, I can now do the following types of things in any code
at any time…

$request_trace.info("_SOME_MESSAGE_HERE") if $request_trace

or to control level of detail

$request_trace.info(“SOME_MESSAGE_HERE”) if $request_trace >=
CHATTY

where SOME_MESSAGE_HERE is replace by some string I want written
to the trace log.

I end up with a file which has a series of messages representing a
“trace” through my code. I use this to track which methods are being
called, states of vars after complex decisions and algorithms etc
just to keep an eye on things as I code/experiment.

Maybe there’s another way to do this (i.e. more convential
debuggers), but at this point I thought it would be an interesting
exercise to incorporate this code so it could be used like this:

#----- application.rb --------

class ApplicationController < ActionController::Base

before_filter :initialize_response
request_trace :chatty

And then supported by a more portable file with the guts of the
process…

#----- request_trace.rb --------

would still need init_constants

not sure where to relocate that just yet

module ActionController #:nodoc:
module RequestTrace #:nodoc:
def self.included(base)
base.extend(ClassMethods)
end

 module ClassMethods
   def request_trace(status)
     case status
       when :enabled
         $request_trace = ENABLED
       when :chatty
         $request_trace = CHATTY
       when :verbose
         $request_trace = VERBOSE
       else
         $request_trace = DISABLED
     end

     if $request_trace
       File.delete(TRACE_FILE) if FileTest::exist?(TRACE_FILE)
       $request_trace   = Logger.new(TRACE_FILE)
       $request_trace.info

(“ApplicationController.initialize_response”)
end
end
end
end
end

When I implement the above code, I get the following error:

NoMethodError
undefined method `request_trace’ for ApplicationController:Class

– gw

On 13 May 2008, at 01:40, Greg W. wrote:

before_filter :initialize_response
request_trace :chatty

You don’t seem to be actually including your RequestTrace module into
your controller at all, you’ve just got this module hanging around on
its own.
For starters you could include your module into ApplicationController.
It’s still not doing what your first example is doing (since
request_trace will only run once, when the class is loaded (in
development mode that will be on each request, but that’s a red
herring - it won’t happen in production). You probably want your
request_trace function to create the appropriate before_filter or
something like that. You could also use class_inheritable_accessor
instead of a global if you want different controllers to have
different settings.

Fred

On May 12, 2008, at 5:50 PM, Frederick C. wrote:

#----- application.rb --------

class ApplicationController < ActionController::Base

before_filter :initialize_response
request_trace :chatty

You don’t seem to be actually including your RequestTrace module into
your controller at all, you’ve just got this module hanging around on
its own.

I thought that’s what that self.included/base.extend business was
trying to do. I guess I just need to spend more time studying why the
extensions to ActionController are different from the ones in
ActiveRecord. Still voodoo to me.

Probably too detailed to spend time dissecting this now, but…

I’m now confused by the lack of paralellism to what I did to write
custom validations. For that, I created a file called validators.rb,
I “require” it in environment.rb, and it just works. No need for an
include statement in my models, and it is structured like this:

module ActiveRecord
module Validations
module ClassMethods

… lots of code …
#------------------------------------------------------------
def validates_as_alpha_numeric_underscore(*attr_names)
configuration = {
:message => @@is_alpha_numeric_underscore_msg,
:with => @@is_alpha_numeric_underscore }
do_as_format_of(attr_names, configuration)
end
… lots of code …

 end

end
end

Description of the validations and full source code is here:
http://www.railsdev.ws/blog/11/custom-validations-in-rails/

I was hoping it was an easy detail I was missing, but sounds like I
need a slightly different approach, so I’ll keep digging.

Thx.

– greg

On 13 May 2008, at 02:20, Greg W. wrote:

using
your controller at all, you’ve just got this module hanging around on
its own.

I thought that’s what that self.included/base.extend business was
trying to do. I guess I just need to spend more time studying why the
extensions to ActionController are different from the ones in
ActiveRecord. Still voodoo to me.
They’re not different.
self.included is called when you do

class SomeClass
include SomeModule
end
Until you do that (or SomeClass.send :include etc…) nothing will
happen (just creating the module in the ‘right’ namespace has no
influence either.

Probably too detailed to spend time dissecting this now, but…

I’m now confused by the lack of paralellism to what I did to write
custom validations. For that, I created a file called validators.rb,
I “require” it in environment.rb, and it just works. No need for an
include statement in my models, and it is structured like this:

The difference there is that you were adding to an existing module,
which someone else had already included in the right place. Here
you’ve got a new module, so you need to do the including.

Fred

On May 13, 2008, at 1:18 AM, Frederick C. wrote:

I’m now confused by the lack of paralellism to what I did to write
custom validations. For that, I created a file called validators.rb,
I “require” it in environment.rb, and it just works. No need for an
include statement in my models, and it is structured like this:

The difference there is that you were adding to an existing module,
which someone else had already included in the right place. Here
you’ve got a new module, so you need to do the including.

Ah, that makes sense. And, I’ve come across a couple simple examples
while research session timeout plugins where I see the Include is
written into the init file – which for me I added to environment.rb
after my require statement, and voila, my system works.

Thanks for your tutoring… much clearer now.

– greg