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, assave
would not have this field initialized.Create a
Repository
class. This would work pretty ok, but seems to be not what Ruby people do.