Repository or Gateway pattern in Ruby - ruby-on-rails

How can I implement the Repository or Gateway pattern in Ruby?
I come from a C# world and I usually abstract away my data access but with ActiveRecord as the default data access mechanism in Ruby, it's not obvious how to accomplish that.
What I usually would do in C# is work with abstract interfaces and then have a concrete implementation for EFCustomerRepository, NHibernateCustomerRepository and InMemoryCustomerRepository and depending on the situation I inject the matching concrete implementation.
So now, what’s the Ruby way?!
As far as I understand it, in dynamic languages you would not need something like DI (dependency injection).
And Ruby has powerful language features to allow things like mixins.
But you would define the mixin to use statically on class or module-level?
How do I write my business logic if I want to develop against an in-memory repository and in production I would switch to my ActiveRecord-Repository?
If might be on the wrong path here since I'm used to thinking in a statically typed language. How would someone tackle this task the Ruby way? Basically I want to make my persistence layer abstract and it's implementations interchangeable.
EDIT: I am referring to robert c. martins (unclebob) keynote about architecture
Thanks for any help...

I get what you are saying. I come from a .NET background as well. Abstracting away your business logic & persistance logic is imo a good idea. I haven't found a gem that does it for you yet. But you can easily roll something simple yourself. In the end a repository pattern is basically a class that delegates to your persistance layer.
Here is what I do:
require 'active_support/core_ext/module/attribute_accessors'
class GenericRepository
def initialize(options = {})
#scope = options[:scope]
#association_name = options[:association_name]
end
def self.set_model(model, options = {})
cattr_accessor :model
self.model = model
end
def update(record, attributes)
check_record_matches(record)
record.update_attributes!(attributes)
end
def save(record)
check_record_matches(record)
record.save
end
def destroy(record)
check_record_matches(record)
record.destroy
end
def find_by_id(id)
scoped_model.find(id)
end
def all
scoped_model.all
end
def create(attributes)
scoped_model.create!(attributes)
end
private
def check_record_matches(record)
raise(ArgumentError, "record model doesn't match the model of the repository") if not record.class == self.model
end
def scoped_model
if #scope
#scope.send(#association_name)
else
self.model
end
end
end
And then you could for example have a Post repository.
class PostRepository < GenericRepository
set_model Post
# override all because we also want to fetch the comments in 1 go.
def all
scoped_model.all(:include => :comments)
end
def count()
scoped_model.count
end
end
Just instantiate it in your controller in a before_filter or initialize or wherever. In this case I'm scoping it to the current_user so that it only fetches those records and automatically create posts only for the current user.
def initialize
#post_repository = PostRepository.new(:scope => #current_user, :association_name => 'posts')
end
def index
#posts = #post_repository.all
respond_with #posts, :status => :ok
end
I came across https://github.com/bkeepers/morphine which is a tiny DI framework. It could work for you :) But DI isn't a heavily used pattern in ruby. Also, I instantiate my repos in order to scope them to a current user or something else.
I'm on a quest to find the right way to do just what you ask and do a little write-up about it if I ever do find it. But for now it's already sufficient to make the clean cut between persistance & my controllers. If this is done properly it won't be a big hassle to switch to a different system later on. Or add caching etc.

Well, ActiveRecord already provides abstract persistence layer - it has several different adapters allowing it to use different database backends. Also, it's open-source so you are free to take a look at how it has been achieved.
Upon the first glance you can see that it also has an AbstractAdapter that all other adapters inherit, however, as Ruby is dynamic, duck-typing language, AbstractAdapter doesn't have to contain abstract methods which will be overridden in children classes, neither defines a "contract" that they should honour.
Edit:
Here's a simple sketch on how you could abstract away your storage in Ruby, not sure which pattern exactly it is:
# say you have an AR model of a person
class Person < ActiveRecord::Base
end
# and in-memory store of persons (simply, a hash)
IN_MEMORY_STORE = {
:Person => ['Tim', 'Tom', 'Tumb']
}
# this will abstract access
class MyAbstractModel
def initialize item, adapter
#item = item
#adapter = adapter
end
# get all elements from the store
def all
case #adapter
when :active_record
# pull from database:
Object.const_get(#item).all
when :in_memory_store
# get from in-memory store
IN_MEMORY_STORE[#item]
else
raise "Unknown adapter"
end
end
end
# get all Persons from in-memory storage...
p MyAbstractModel.new(:Person, :in_memory_store).all
# ...and from a database
p MyAbstractModel.new(:Person, :active_record).all

#serverinfo, I don't know much about C#. But when I came to Ruby from a Java/C background, I was blown away when I realized how flexible this language really is. You say that your real problem here is to "abstract away your persistence layer and make it exchangeable". You also asked "how will I write the business logic".
I suggest that you throw away your preconceptions and ask yourself: "how would I like to express data access/storage within my business logic layer"? Don't worry about what you think can or can't be done; if you can figure out how you would like the interface to work, there is probably a way it can be done in Ruby.
You will also have to decide how you want to specify the concrete implementation to be used. Is it possible you will want to use a different data store for different model objects? Might you want to switch at run-time? Would you like to specify the backend to be used in a configuration file, or in code? If you can decide what you want to do, there are lots of people on Stack Overflow who can help you figure out how to do it.

Related

How to reassign STI class to a variable within model's method?

I've got STI like this:
class Post
end
class Post::Confirmed < Post
end
class Post::Draft < Post
def confirm!
becomes Post::Confirmed
end
end
...# somewhere in controller
# POST /posts/1/confirm
# POST /posts/1/confirm.json
def confirm
#post = Post::Draft.first
#post = #post.confirm! # this is the only way I can reload #post with Post::Confrmed
end
Is it somehow possible to make:
#post.confirm! # I want this #post(Post::Draft) to become Post::Confirmed without reassigning
Or is it just nor RoR way?
Thanks in advance!
The pattern I've found that works best here is having a datetime type field that records when the record was flagged.
For example:
def confirm!
self.confirmed_at = DateTime.now
self.save!
end
Then you can tell when something was confirmed. This comes in especially handy for when you have a situation where something will be flagged but isn't yet, such as setting a publishing date in the future.
Although it might seem a little annoying to not have your STI bag of tricks available, STI is not always the appropriate tool. Generally STI is to differentiate between similar but different models that have a lot of commonality or are used in a common context. It's not supposed to be used to handle different states of a singular model.
What you want in that case is a state-machine type pattern.

Accessing object everywhere in rails app

I know this is 1001st question about global objects, but I think my situation is slightly different.
I'm working on ecommerce solution, which provides few different shops within a single rails application.
There is a class Shop which provides shop-specific logic and options. For example:
#shop.tax should be accessible in models. Tax can differ depend on shop. eg 9%, 18%.
#shop.name and #shop.layout should be accessible in controllers and views.
#shop.email.general for mailers.
I need to be able to create an instance of Shop in application controller and somehow pass it to the all application parts.
# controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_filter :set_shop
protected
def set_shop
requested_shop = if request.domain.match(/^.*shop1\.com$/)
:shop_1
elsif request.domain.match(/^.*shop2\.com$/)
:shop_2
end
#shop = Shop.new(requested_shop)
end
end
I know that request-based logic should not be used in models, but I really need shop options there. In tests I could mock this "global" object like that Shop.new(:test_shop) in spec_helper.
Is global variable my only choice? I've never used them.
I tried to use Settingslogic gem, but it defines attr_accessors for shop-specific options, and they persist between requests, which is not what I need.
One way of doing this would be something like
class Shop
def self.current=(shop)
Thread.current[:current_shop] = shop
end
def self.current
Thread.current[:current_shop]
end
end
Which allows you to maintain a separate current shop for each request.
The alternative is to pass the current shop around. It may seem tedious at first but can ultimately be simpler to reason about than global or pseudo global behaviour

rails application design: static methods

Which would be the most elegant way to define static methods such as "generate_random_string", "generate_random_user_agent", which are called from different libraries?
What are the best practices?
Best practice as I've seen would include:
Put them in a module in /lib/
Include them as mixins in the rest of your application code.
Make sure they are thoroughly tested with their own rspecs (or whatever test tool you user).
Plan them as if you may at some point want to separate them out into their own gem, or potentially make them available as a service at some point. That doesn't mean design them as separate services from the beginning, but definitely make sure they have no dependencies on any other code in your application.
Some basic code might be something like:
module App::Services
def generate_random_string
# ...
end
def generate_random_user_agent
# ...
end
end
Then in your model or controller code (or wherever), you could include them like this:
class MyModelClass < ActiveRecord::Base
include App::Services
def do_something_here
foo = random_string
# whatever...
end
def random_string
generate_random_string
end
end
Notice I isolated the generate_random_string call in its own method so it can be used in the model class, but potentially be switched out for some other method easily. (This may be a step more than you want to go.)

Rails refactoring: Where would you put hash which maps one table's fields to another

So, I have a database of people on an external system, and I want to set up the code to easily create people records internal to our sysem based on the external system. The field names, of course, are not the same, so I've written some code which maps from one table to the next.
class PeopleController < ApplicationController
...
def new
#person = Person.new
if params[:external_id] then
initialize_from_external_database params[:external_id]
end
end
private
def initialize_form_external_database(external_id)
external = External::Person.find(external_id)
if external.nil?
...
else
#person.name_last = exteral.last_name
#person.name_first = external.first_name
#...
#person.valid?
end
end
end
Okay, so the stuff in the "else" statement I can write as a loop, which would use a hash something like:
FieldMappings = {
:name_last => :last_name,
:name_first => :first_name,
:calculated_field => lambda {|external_person| ... },
...
}
But where would you put this hash? Is it natural to put it in the External::Person class because the only reason we access those records is to do this initialization? Or would it go in the controller? Or a helper?
Added: Using Rails 2.3.5.
I'd put this code in the External::Person to avoid Person even having to know it exists. Use a 'to_person' method (or maybe 'to_internal_person') on External::Person. Keep the Hash in External::Person and use it to perform the generation. Either way as JacobM says, you want this code in your model, not controller.
class PeopleController < ApplicationController
def new
if external = External::Person.find_by_id params[:external_id]
#person = external.to_person
else
#person = Person.new
end
end
end
If you're in Rails 3.x (maybe also in 2.x, I'm not sure), you can put miscellaneous classes and modules in your /extras folder which is included in the autoloader path. This is where I always put things of this nature, but I' not aware of any Rails convention for this sort of thing.
First of all, I would do that work in your (internal) Person model -- give it a class method like create_person_from_external_person that takes the external person and does the assignments.
Given that, I think it would be OK to include the hash within that Person model, or somewhere else, as Josh suggests. What would be particularly cool would be to write a generic create_person_from_external_person method that would ask the external person for a hash and then do the mapping based on that hash; that approach could support more than one type of external person. But that may be overkill if you know this is the only type you have to deal with.
I wouldn't put it in the controller, but, again, I wouldn't do that work in the controller either.
You can put it on a module on the lib directory so you don't mess any of your classes that will be full of awesome code that will probably last many years. Another good reason is you can then include/require your mapping module everywhere you need it (maybe in your tests).
module UserMapping
FIELDS = { :last_name => :name_last, .... }
end
If you drop the module on the lib and you use rails 3 you should put this on your config/application.rb file:
config.autoload_paths += %W(#{config.root}/lib)
On Rails::VERSION::MAJOR < 3 the lib directory is automatically added to the autoload_path

Tracking model changes in Rails, automatically

In my rails app I would like to track who changes my model and update a field on the model's table to reflect.
So, for example we have:
class Foo < ActiveRecord::Base
before_create :set_creator
belongs_to :creator, :class_name => "User"
protected
def set_creator
# no access to session[:user_id] here...
end
end
What's a good testable way for me to get at the user_id from my model? Should I be wacking this data in Thread.current ?
Is it a better practice to hand this information from the controller?
Best practice in MVC is to have your Models be stateless, the controller gets to handle state. If you want the information to get to your models, you need to pass it from the controller. Using a creation hook here isn't really the right way to go, because you are trying to add stateful data, and those hooks are really for stateless behavior.
You can pass the info in from the controller:
Foo.new(params[:foo].merge {:creator_id => current_user.id})
Or you can create methods on User to handle these operations:
class User
def create_foo(params)
Foo.new(params.merge! {:creator_id => self.id})
end
end
If you find yourself writing a lot of permissions code in the controller, I'd go with option 2, since it will let you refactor that code to the model. Otherwise option 1 is cleaner.
Omar points out that it's trickier to automate, but it can still be done. Here's one way, using the create_something instance method on user:
def method_missing(method_sym, *arguments, &block)
meth = method_sym.to_s
if meth[0..6] == "create_"
obj = meth[7..-1].classify.constantize.new(*arguments)
obj.creator_id = self.id
else
super
end
end
You could also override the constructor to require user_ids on construction, or create a method inside ApplicationController that wraps new.
There's probably a more elegant way to do things, but I definitely don't like trying to read state from inside Model code, it breaks MVC encapsulation. I much prefer to pass it in explicitly, one way or another.
Yeah, something like that would work, or having a class variable on your User model
cattr_accessor :current_user
Then in your controller you could have something like:
User.current_user = current_user
inside a before filter (assuming current_user is the logged in user).
You could then extend AR:Base's create/update methods to check for the existence of a created_by/updated_by field on models and set the value to User.current_user.
I'd create new save, update, etc methods that take the user_id from everything that calls them (mainly the controller).
I'd probably extend ActiveRecord:Base into a new class that handles this for all the models that need this behaviour.
I wouldn't trust Thread.current, seems a bit hackish. I would always call a custom method which takes an argument:
def create_with_creator(creator, attributes={})
r = new(attributes)
r.creator = creator
r.save
end
As it follows the MVC pattern. The obviously inherient problem with this is that you're going to be calling create_with_creator everywhere.
You might find PaperTrail useful.
Probably you could check out usertamp plugins, found two in github
http://github.com/delynn/userstamp/tree/master
http://github.com/jnunemaker/user_stamp/tree/master

Resources