In a Ruby project I'm working on, I add ActiveRecord-style, MVC functionality to model classes with a mixin architecture similar to the following:
module Model
# Classes that mixin this module gain ActiveRecord-style class methods
# like Model.all, Model.first, Model.last et al.
#
# Throughout this module, @@database_bridge will contain a reference to a
# database ORM bridge, that does the dirty implementation of these methods.
def all
# Implementation stuff here, using @@database_bridge as appropriate
end
def first
...
end
# et al
end
class ExampleModel
extend Model
# Model-specific implementation goes here...
end
Calling e = ExampleModel.first
would assign the first ExampleModel
in the database to e
.
I want to use dependency injection to set @@database_bridge
at runtime, such that every class containing extend Model
uses the same, specified ORM object.
How can I do this?
If I could write some kind of helper method to set up that class variable on demand, that would be great.
I've found a better solution than the previous, and it's much simpler than I thought (d'oh!): by prefixing a method with self.
in a mixin module, a public interface to that method via Module.method
becomes available.
Thus, we simply add a setter to our module, using a self.attribute_set
statement.
In the above example, the above approach would yield the following code:
module Model
# Classes that mixin this module gain ActiveRecord-style class methods
# like Model.all, Model.first, Model.last et al.
#
# Throughout this module, @@database_bridge will contain a reference to a
# database ORM bridge, that does the dirty implementation of these methods.
def all
# Implementation stuff here, using @@database_bridge as appropriate
end
def first
...
end
def self.set_database_bridge(ref_to_new_bridge)
@@database_bridge = ref_to_new_bridge
## any additional intialisation/sanitisation logic goes here
end
# et al
end
class ExampleModel
extend Model
# Model-specific implementation goes here...
end
Calling Model.set_database_bridge
would allow us to pass in a new database bridge.
If we don't actually need any initialisation or sanitisation logic in our helper function, there is another, more elegant approach - add an attr_accessor
within a class << self
block, thus:
module Model
# ...
class << self
attr_accessor :database_bridge
end
end
This way, we can call Ruby's standard setter method: Model.database_bridge = the_new_bridge
.
Sweet.