Repositor
Installation & Setup
Manual:
gem install 'repositor'
For gemfile:
gem 'repositor'
And run in console:
bundle install
Description
This gem is an implementation of Repository Pattern described in book Fearless Refactoring Rails Controllers by Andrzej Krzywda 2014 (c). Awesome book, recommend read for all who are scary open own controller files ;)
The main reason to user RepoObject is that your controller don't communicate with ORM layer (ActiveRecord or Mongoid). It must communicate with Repo layer so you are not stricted about your database adapter. If in future you will want to change it, you will need just to reconfigure your Repository layer. Sounds nice. Let's try it..
With some helps of helper method your controller can be only 30-40 lines of code. Nothing more.
With RepoObject you controller could look something like this:
class ProductsController < ApplicationController
# you are free from any action callbacks...
# but define this 2 helper methods:
helper_method :product, :products
def create
@product = repo.create(product_params)
@product.valid? ? redirect_to(default_redirect) : render(:new)
end
def update
@product = repo.update(product, product_params)
@product.valid? ? redirect_to(default_redirect) : render(:edit)
end
def destroy
repo.destroy(product) and redirect_to default_redirect
end
private
def product_params
params.require(:product).permit(:name, :price, :dscription)
end
def default_redirect
products_path
end
# Helper method that find or init new instance for you and cache it in ivar
# You can use it for at view show action just `product` method
# or for _form partial also `product`
def product
@product ||= repo.find(params[:id])
end
# Second helper that allow to cache all collection
# At view method `products` allows you access to the colelction
# No any @'s anymore!
def products
@products ||= repo.all
end
# Declaration if repo object:
def repo
@products_repo ||= ProductRepo.new
end
# By default repositor will try to find `Product` model and communicate with it
# if you need specify other model, pass in params
# ProductRepo.new(model: SaleProduct)
end
How to use
In app directory you need to create new repos directory . Recomended to create application_repo.rb and inherit from it all repos, so you could keep all your repos under single point of inheritance.
class ApplicationRepo
# include ORM submodule
# now supported only ActiveRecord
# more will be added soon
include Repositor::ActiveRecord
end
Than you need to create product_repo.rb:
class ProductRepo < ApplicationRepo
# here you will have default methods for repo actions
# if you want communicate with model class,
# just can use model method to send it any method you need
def all_with_name_john
model.where(name: 'John')
end
end
and that's all... magic already happened (no)
If check what exactly was done, including Repository module in base ApplicationRepo will add default CRUD methods to all repos that will be inherited from it. That's all. No magic.
Repositor did for you a lot of dry work. In other case for each repo you must make identical methods, like this:
class ProductRepo
def all
Product.all
end
def new
Product.new
end
def find(product_id)
Product.find(product_id)
end
def create(product_params)
Product.create(product_params)
end
def update(params)
product.update(params)
end
def destroy(product)
product.destroy
end
end
If you need to add new method for model, just define it in repo file. Keep your model skinny.
TODO
- Add mongoid support
- Add generators that generate repo folder and some
application_repo.rb - Some improvements ? =)