I have a case where I’m trying to leverage a database configuration file used by Padrino for a custom worker I’m writing without having to load the Padrino environment and without having to modify the existing database configuration. In short, I want to write my code to work with the existing database configuration code rather than modifying the existing configuration.
The database configuration file in question looks like the following:
# This is just here for right now so I can test
# to see if logger is set to anything in DB config
puts "Logger in DB config: #{logger}"
ActiveRecord::Base.configurations[:development] = {
:adapter => 'sqlite3',
:database => Padrino.root('db', "app_development.db") }
ActiveRecord::Base.logger = logger
ActiveRecord::Base.include_root_in_json = true
ActiveRecord::Base.store_full_sti_class = true
ActiveSupport.use_standard_json_time_format = true
ActiveSupport.escape_html_entities_in_json = false
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[Padrino.env])
My custom worker looks like the following:
ROOT = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift(ROOT)
require 'active_record'
require 'logger'
# Mock Padrino module with methods used by database config file
module Padrino
def self.root(*args)
return File.expand_path(File.join("#{ROOT}/..", *args))
end
def self.env
return :development
end
end
module Worker
class << self
attr_accessor :logger
def init
@logger = Logger.new(STDOUT)
@logger.level = Logger::DEBUG
require "#{ROOT}/../config/database"
end
end
end
Worker.init
When I require the database configuration file in my worker I get an error saying the following:
/home/user/devel/app/config/database.rb:3:in `<top (required)>': undefined local variable or method `logger' for main:Object (NameError)
from /home/user/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:55:in `require'
from /home/user/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:55:in `require'
from worker.rb:26:in `init'
from worker.rb:31:in `<main>'
Given this, I modified the Worker#init function to be the following:
def init
@logger = Logger.new(STDOUT)
@logger.level = Logger::DEBUG
Object.send(:define_method, :logger, lambda { @logger })
puts "Logger in Worker module: #{logger}"
require "#{ROOT}/../config/database"
end
This change resulted in the following output:
Logger in Worker module: #<Logger:0x9505088>
Logger in DB config:
I take this to mean the @logger is not in scope in the database configuration file, even though I’m using a lambda when I define the logger method on Object.
Oddly enough, if I pull the Object.send line of code out of the Worker#init function and instead call it right before I call Worker.init like below, I get the following result.
Object.send(:define_method, :logger, lambda { Worker.logger })
Worker.init
results in
Logger in Worker module: #<Logger:0x81bc8b4>
Logger in DB config: #<Logger:0x81bc8b4>
Can someone explain to me why if I make the Object.send call inside the Worker#init function it doesn’t work like it does if I make it outside the Worker module?
In your first example, you try to use undefined variable ‘logger’, as you can see from error message. Try to use the logger feature this way: