rails 3 - where to put app startup initialization stuff? - ruby

In my app (jruby, rails 3, mongodb) I setup my data access objects (and other 'singletons') in an initializer /config/initializers/app_constants.rb
DATA_COLLECTION_STORE = DataCollectionStore.new(...)
SOME_OTHER_SINGLETON = SomeOtherClassTreatedLikeSingleton.new(...)
I'm new to rails (and ruby) and I realize a couple things. First, setting up these "singletons" must not be the correct approach, since those classes can be instantiated at any time anywhere else in the code (for now it's assumed that won't happen). Secondly, putting these "constants" in this initializer seems wrong b/c when I try to run tests (rake spec) or build a WAR (using warble) I can see that the initializer stuff is running so I'm creating connections to mongo, starting my "some_other_singleton", etc.
Where should this sort of stuff go?
thanks in advance for being patient with my noobness :)

You don't need to actually initialize your singletons in any config file.
Instead, you can just implement a class method in your class that will return a singleton. The following code will allow u to access the singleton using DataCollectionStore.instance
class DataCollectionStore
##instance = DataCollectionStore.new
def self.instance
##instance
end
def initialize
#intitialize you instance here
end
end
Keep in mind that you will have to set config.cache_classes to true in development.rb for this to work in your development environment. Classes are cached by default in production though.
Alternatively, you could just use the class itself as a singleton object and implement your functionality in class methods.
If your initialization is expensive, you can do it lazily using the snippet below. That way you only pay the price if your test actually invokes the instance class method.
You can test this in your app by outputting DataCollectionStore.instance in a view and using different browsers to load the page. If every thing works right, you should see the same timestamp in both browsers.
class DataCollectionStore
##instance = nil
def self.instance
##instance || ##instance = self.new
end
def initialize
#initialized_time = Time.now
end
def to_s
#initialized_time
end
end

Related

Weird Ruby class initialization logic?

Some open source code I'm integrating in my application has some classes that include code to that effect:
class SomeClass < SomeParentClass
def self.new(options = {})
super().tap { |o|
# do something with `o` according to `options`
}
end
def initialize(options = {})
# initialize some data according to `options`
end
end
As far as I understand, both self.new and initialize do the same thing - the latter one "during construction" and the former one "after construction", and it looks to me like a horrible pattern to use - why split up the object initialization into two parts where one is obviously "The Wrong Think(tm)"?
Ideally, I'd like to see what is inside the super().tap { |o| block, because although this looks like bad practice, just maybe there is some interaction required before or after initialize is called.
Without context, it is possible that you are just looking at something that works but is not considered good practice in Ruby.
However, maybe the approach of separate self.new and initialize methods allows the framework designer to implement a subclass-able part of the framework and still ensure setup required for the framework is completed without slightly awkward documentation that requires a specific use of super(). It would be a slightly easier to document and cleaner-looking API if the end user gets functionality they expect with just the subclass class MyClass < FrameworkClass and without some additional note like:
When you implement the subclass initialize, remember to put super at the start, otherwise the magic won't work
. . . personally I'd find that design questionable, but I think there would at least be a clear motivation.
There might be deeper Ruby language reasons to have code run in a custom self.new block - for instance it may allow constructor to switch or alter the specific object (even returning an object of a different class) before returning it. However, I have very rarely seen such things done in practice, there is nearly always some other way of achieving the goals of such code without customising new.
Examples of custom/different Class.new methods raised in the comments:
Struct.new which can optionally take a class name and return objects of that dynamically created class.
In-table inheritance for ActiveRecord, which allows end user to load an object of unknown class from a table and receive the right object.
The latter one could possibly be avoided with a different ORM design for inheritance (although all such schemes have pros/cons).
The first one (Structs) is core to the language, so has to work like that now (although the designers could have chosen a different method name).
It's impossible to tell why that code is there without seeing the rest of the code.
However, there is something in your question I want to address:
As far as I understand, both self.new and initialize do the same thing - the latter one "during construction" and the former one "after construction"
They do not do the same thing.
Object construction in Ruby is performed in two steps: Class#allocate allocates a new empty object from the object space and sets its internal class pointer to self. Then, you initialize the empty object with some default values. Customarily, this initialization is performed by a method called initialize, but that is just a convention; the method can be called anything you like.
There is an additional helper method called Class#new which does nothing but perform the two steps in sequence, for the programmer's convenience:
class Class
def new(*args, &block)
obj = allocate
obj.send(:initialize, *args, &block)
obj
end
def allocate
obj = __MagicVM__.__allocate_an_empty_object_from_the_object_space__
obj.__set_internal_class_pointer__(self)
obj
end
end
class BasicObject
private def initialize(*) end
end
The constructor new has to be a class method since you start from where there is no instance; you can't be calling that method on a particular instance. On the other hand, an initialization routine initialize is better defined as an instance method because you want to do something specifically with a certain instance. Hence, Ruby is designed to internally call the instance method initialize on a new instance right after its creation by the class method new.

Creating facade idiomatically in Ruby

I'm trying to implement a Facade in idiomatic Ruby while coming from Java. I can see that Rails' ActiveRecord is fond of using class methods for things like find_by(criteria) and does not use Repository pattern for that task.
My Facade wraps a specific webservice with several methods. My original idea was to make it's API similar to ActiveRecord (learning by imitation):
class MyEntity
# ....
def get_name
#loaded_name + #loaded_surname
end
def delete
#entity_access_service.delete(#id)
end
def save
#entity_access_service.save(#id, #loaded_name , #loaded_surname)
end
def self.find(id)
data = #entity_access_service.get_data_for(id)
MyEntity.new(data) #Or whatever way to populate my entity
end
end
This, in theory, would work great:
e = MyEntity.find(10)
p e.get_name
e.delete
Or:
e = MyEntity.new(some stuff)
e.save
Question:
For save and delete instance methods to work, I need to somehow get an instance of EntityAccessService. This instance should be mockable to test it in isolated environment. What is the correct way to do it?
I'm expecting my tests to look as simple as possible and without some weird hacks, as what I'm trying to implement seems fairly trivial.
I have thought of several options to do that:
Having a class-level variable holding entity_access_service used by all of the entities created in application. In this case, where should I initialize this field? For example:
class MyEntity
##entity_access_service = nil
end
# Somewhere else (where?):
MyEntity.entity_access_service = MyEntityService.new(some_params_from_env)
This way, in my tests I would have to initialize/mock it at start.
Similar to 1 but initialize it in the class. This looks weird, especially if I know that my tests do not have required ENV params populated at all.
Have an extra constructor/attribute to set the entity_service. This won't work, as save would not have this field initialized.
Create a Repository class. This would work pretty ok, but seems to be not what Ruby people do.
Following ActiveRecord's example, you can create a method on your class itself, or on the base class from which your other classes are derived.
ActiveRecord provides a method ActiveRecord::Base.connection which returns the connection object which all models use to access the database. You can do something similar:
class MyEntity
....
def self.entity_access_service
# return your service object
end
def self.find(id)
MyEntity.entity_access_service.get_data_for(id)
MyEntity.new(data) # Or whatever way to populate my entity
end
def save()
MyEntity.entity_access_service.save(#id, #loadedName, #loadedSurname)
end
end
As far as initialization goes, you either have to have a initialization step in your app (and test suite) where service credentials are read from config files and passed into your MyEntity object, or your entity_access_service method can lazily create the object it returns on first access using a very common Ruby idiom:
def self.entity_access_service
#entity_access_service || = # build entity_access_service object
end
Note that, by wrapping your class-level instance variables in class-level accessor methods, you can avoid the use of ## which is a recommended best practice.

Configuring fixture_path in ActiveRecord test fixtures

I'm using ActiveRecord with Sinatra instead of Rails, and I want to use fixtures in my tests. The documentation for ActiveRecord's FixtureSet says that you have to use fixture_path to tell it where the fixture files are:
placed in the directory appointed by ActiveSupport::TestCase.fixture_path=(path)
How can I write to that setting? I tried #fixture_path and ##fixture_path, but both of them left the value nil when FixtureSet tried to read it.
Here's the only thing I could get to work, but it can't possibly be right:
# test_helper.rb
require_relative '../app'
require 'minitest/autorun'
require 'active_record'
ActiveRecord::Base.establish_connection(:test)
#Set up fixtures and such
class ActiveSupport::TestCase
include ActiveRecord::TestFixtures
include ActiveRecord::TestFixtures::ClassMethods
class << self
def fixtures(*fixture_set_names)
self.fixture_path = 'test/fixtures'
super *fixture_set_names
end
end
self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
end
The full source code is posted as a small demo project for ActiveRecord and Sinatra.
I tried to leave this as a comment on your answer, but it got too long so I thought I might as put it in an answer.
The reason #fixture_path and ##fixture_path didn't work is that fixture_path is an ActiveSupport class attribute, which is like a Ruby attr_accessor except it's defined as a singleton method on the class. You can see where the fixture_path attribute is defined with class_attribute :fixture_path in the ActiveRecord::TestFixtures module source.
Class attributes are part of ActiveSupport and not native to Ruby. You can read more about them in the Active Support Core Extensions Rails Guide and in the API docs, and see how class_attribute works in the Rails source. As you can see,
the value is stored in the instance variable "##{name}" (e.g. #fixture_path), but that happens inside a singleton method, which means it's an instance variable on the singleton class and you can only access it from within the singleton class.
That's all a little bit moot, though, because the point of attributes (and feel free to disregard this if it's old news to you) is that they allow you to keep instance variables private and change your implementation without breaking code that subclasses or includes your code. When an attribute reader or writer exists, you should always use it instead of accessing the instance variable directly, because at some point the implementation might change and the attribute methods could be replaced by methods with more complex logic, and accessing the instance variable directly will no longer produce the same results as using the attribute reader and writer.
As you discovered, you need to use self.fixture_path = instead of fixture_path = because in the latter case Ruby assumes you want to assign to a local variable.
I can't believe I didn't see this, but I didn't. I had to use self, just like the settings for transactional fixtures and instantiated fixtures.
# test_helper.rb
require_relative '../app'
require 'minitest/autorun'
require 'active_record'
ActiveRecord::Base.establish_connection(:test)
#Set up fixtures and such
class ActiveSupport::TestCase
include ActiveRecord::TestFixtures
include ActiveRecord::TestFixtures::ClassMethods
self.fixture_path = 'test/fixtures'
self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
end
The trick is understanding the meaning of self in a class definition; it refers to the class, not an instance of the class. I guess when I'm monkey patching ActiveSupport::TestCase, that's the only way to set a class variable. For some reason #fixture_path and ##fixture_path don't work.

Use application class instance variable inside get block

I am using sinatra and I have the code:
class App < Sinatra::Base
configure do
#logger = Logger.new "./log"
end
#logger.info "App started" #this line works
get "/info" do
#logger.info "/info inquired" #this does not work and complain #logger is nilClass
end
end
Why #logger inside get block gives a nil object? How can I use #logger in this case?
PS. If I use a class variable like ##logger, the code above works. But why the instance variable is not working in this case?
Instance variables attach themselves to whatever object is self at the time the instance variables spring into existence.
On the face of things, these are the values for self:
class App < Sinatra::Base
#In here, self=App
#When a block executes, it sees the value for self that existed in
#the surrounding scope at the time the block was CREATED:
configure do #a block
#So...in here self=App
#logger = Logger.new "./log"
end
#logger.info "App started" #this line works
get "/info" do #a block
#Similarly, in here self=App
#logger.info "/info inquired" ##logger is NilClass
end
end
Based on that state of things, you are right to be confused: it looks like when configure() executes the block that is passed to it, #logger will spring into existence and attach itself to App, then when get() calls the block that is passed to it, the #logger instance variable will refer to the instance variable attached to App.
But...ruby offers ways to change the value of self that a block sees when the block EXECUTES. Here is an example:
p = Proc.new { puts self }
p.call
class Dog
def initialize(a_proc)
#In here, self is a Dog instance
instance_eval &a_proc
end
end
Dog.new p
--output:--
main
#<Dog:0x000001009b6080>
Based on your error, you have to suspect that Sinatra must be employing some ruby tricks to change self when it executes the block passed to get().
How can we know this?
Ruby is the wild west of programming languages, so you can't ever know what is going to happen unless you look at the source code or good docs if they exist. The source code is pretty convoluted. I found this in the docs:
Some knowledge of Sinatra’s internal design is required to write good
extensions. This section provides a high level overview of the classes
and idioms at the core of Sinatra’s design.
Sinatra has two distinct modes of use that extensions should be aware
of:
The “Classic” style, where applications are defined on main / the
top-level – most of the examples and documentation target this usage.
Classic applications are often single-file, standalone apps that are
run directly from the command line or with a minimal rackup file. When
an extension is required in a classic application, the expectation is
that all extension functionality should be present without additional
setup on the application developers part (like included/extending
modules).
The “Modular” style, where Sinatra::Base is subclassed explicitly and
the application is defined within the subclass’s scope. These
applications are often bundled as libraries and used as components
within a larger Rack-based system. Modular applications must include
any desired extensions explicitly by calling register ExtensionModule
within the application’s class scope.
Most extensions are relevant to both styles but care must be taken by
extension authors to ensure that extensions do the right thing under
each style. The extension API (Sinatra.register and Sinatra.helpers)
is provided to help extension authors with this task.
Important: The following notes on Sinatra::Base and
Sinatra::Application are provided for background only - extension
authors should not need to modify these classes directly.
Sinatra::Base The Sinatra::Base class provides the context for all
evaluation in a Sinatra application. The top-level DSLish stuff exists
in class scope while request-level stuff exists at instance scope.
Applications are defined within the class scope of a Sinatra::Base
subclass. The “DSL” (e.g., get, post, before, configure, set, etc.) is
simply a set of class methods defined on Sinatra::Base. Extending the
DSL is achieved by adding class methods to Sinatra::Base or one of its
subclasses. However, Base classes should not be extended with extend;
the Sinatra.register method (described below) is provided for this
task.
Requests are evaluated within a new Sinatra::Base instance – routes,
before filters, views, helpers, and error pages all share this same
context. The default set of request-level helper methods (e.g, erb,
haml, halt, content_type, etc.) are simple instance methods defined on
Sinatra::Base or within modules that are included in Sinatra::Base.
Providing new functionality at the request level is achieved by adding
instance methods to Sinatra::Base.
As with DSL extensions, helper modules should not be added directly to
Sinatra::Base by extension authors with include; the Sinatra.helpers
method (described below) is provided for this task.
http://www.sinatrarb.com/extensions.html
You can define your own logger in your Sinatra::Base and use it in your get block by doing:
class App < Sinatra::Base
set :logger, Logger.new("./log")
helpers do
def logger; self.class.logger; end
end
logger.info self
get "/info" do
logger.info self
end
# ...
end
Or by using the class variable as you note in your edit. The log file from the above configuration shows why:
I, [2014-06-01T16:36:51.593033 #16144] INFO -- : App
I, [2014-06-01T16:36:59.438078 #16144] INFO -- : #<App:0x9aa919c #default_layout=:layout, #app=nil ...
In the first case, self is the application class, while in the get block, self is the instance of the class.
To clarify, in your example: Ruby interprets the first #logger.info (called from the context of your class) to be a class instance variable, while the second #logger.info is interpreted as an instance variable (which has not been defined). The variable you define in your configure block is set in the class context.

Calling a Sinatra app instance method from TestCase

I have an util method into a Sinatra application and I would like to tested from my TestCase.
The problem is that I don't know how to invoke it, if I just use app.util_method I have the error NameError: undefined local variable or method 'util_method' for #<Sinatra::ExtendedRack:0x007fc0c43305b8>
my_app.rb:
class MyApp < Sinatra::Base
# [...] routes methods
# utils methods
def util_method
return "hi"
end
end
my_app_test.rb:
require "my_app.rb"
require "test/unit"
require "rack/test"
class MyAppTest < Test::Unit::TestCase
include Rack::Test::Methods
def app
MyApp.new
end
# [...] routes methods tests
def test_util_method
assert_equal( "hi", app.util_method )
end
end
Sinatra aliases the new method to new! before redefining it, so the simplest solution is to use that instead:
def app
MyApp.new!
end
Of course I only noticed that after I’d come up with the following, which I’ll leave in as it could be useful/informative.
A possible way to get round Sinatra redefining the new method and returning a complete Rack app a get hold of an instance your actual base class is to do what the “real” new method does yourself:
def app
a = MyApp.allocate
a.send :initialize
a
end
This is a bit of a hack, but it might be useful for testing.
Another technique would be to “walk” the middleware stack until you got to your class. The following is a little fragile, as it depends on all the middleware involved to use the name #app to refer to the next app in the stack, but this is fairly common.
def app
a = MyApp.new
while a.class != MyApp
a = a.instance_variable_get(:#app)
end
a
end
That won’t work on the yet to be released Sinatra 1.4 though (at least not on the current master, which is commit 41840746e866e8e8e9a0eaafc53d8b9fe6615b12), as new now returns a Wrapper class and the loop never ends. In this case you can grab the base class directly from the #instance variable:
def app
MyApp.new.instance_variable_get :#instance
end
(note this last technique may well change before the final 1.4 release).
The problem you are encountering is, that MyApp.new does not return an instance of MyApp but an instance of the middleware wrapping your App (usually Rack::Head or Sinatra::ShowExceptions). A good explanation can be found in the thread Sinatra Usage Question / Rack App.
The only solution I can think of is to change your instance method to a class method which can be called without the instance itself. As the instance of your App may be freshly instantiated for every request, an instance method probably doesn't have much advantages over a class method in your scenario.
Edit:
In the upcoming Sinatra 1.4 the initialization will change. Sinatra::Base.new will return a Sinatra::Wrapper instance, which exposes #settings and #helpers. This may help solve the problem of accessing Sinatra::Base instance methods. See the Sinatra Changelog for more information.

Resources