Lightrails
Lightrails aims to provide more modular structures for Ruby on Rails applications.
It is a utility library including Action Facade, Action Interactor and Active Representer classes.
Getting Started
Add lightrails
to your Rails project's Gemfile and bundle install
.
gem "lightrails"
Run the generator.
$ bin/rails generate lightrails:install
Action Facade
Add a simple interface for obtaining multiple data used in a view.
It uses Facade design pattern and takes responsibility for preparing data outside of the controller.
In the example below, by using MyPage::IndexFacade
and MyPage::NotificationsFacade
, Active Record methods will be called outside of the MyPageController
.
class Mypage::IndexFacade < ApplicationFacade
attr_reader :current_user
def initialize(payload)
@current_user = payload[:current_user]
end
def active_users
@active_users ||= User.active.order(login_at: :desc).limit(10)
end
def messages
@messages ||= current_user.messages.order(created_at: :desc).limit(10)
end
end
class MyPage::NotificationsFacade < ApplicationFacade
attr_reader :current_user
def initialize(payload)
@current_user = payload[:current_user]
end
def messages
@messages ||= current_user.messages.order(created_at: :desc).limit(10)
end
end
class MypageController < ApplicationController
# for using #retrieve method
include ActionFacade::Retrieval
def index
facade = Mypage::IndexFacade.new(current_user: current_user)
# assign instance variables
retrieve(facade, :active_users, :messages)
end
def notifications
# You can retrieve data from the guessed facade
# MyPageController#notifications => MyPage::NotificationsFacade
payload = { current_user: current_user }
retrieve_from(payload, :messages)
end
end
<%# in View (index.html.erb) %>
<% @active_users.each do |user| %>
...
<% end %>
<% @messages.each do |user| %>
...
<% end %>
<%# in View (messages.html.erb) %>
<% @messages.each do |user| %>
...
<% end %>
To create an facade, you can use the generator.
$ bin/rails generate facade mypage/index
Action Interactor
Add standarized data processing units to your Rails application.
It uses Command design pattern and will be usable for various business logic (ex: user registration) in Rails applications.
In the example, by using RegistrationInteractor
, user registration process will be executed outside of model and controller.
class User
attr_accessor :name
def initialize(payload)
@name = payload[:name]
end
end
class RegistrationInteractor < ApplicationInteractor
def execute
return failure! unless payload[:name]
# complicated business logic
# set results
results.add(:user, User.new(name: payload[:name]))
successful!
end
end
interactor.successful? # => true
interactor.finished? # => true
user = interactor.results[:user]
user.name # => 'John'
To create an interactor, you can use the generator.
$ bin/rails generate interactor registration
Active Representer
It provides a class for wrapping a object and used like Model. You can add custom methods to the class (using the decorator pattern). It can be used with API responses or simple decorators.
In addition, attr_field
/ attr_one
/ attr_many
can be used for attributes.
attr_field
Declare additional field and type to the objects.
You can get / set field's value (converted to corresponding).
It uses ActiveModel::Attributes
internally.
attr_one
Declare an associated object like has one association. If a representer for the object is found, the object will be wrapped by the representer.
attr_mamy
Declare associated objects like has many association. If a representer for the objects is found, the objects will be wrapped by the representer.
You can wrap hash-like objects (OpenStruct
, Hashie::Mash
etc.) like below.
class ActivityRepresenter < ApplicationRepresenter
def created_on
created_at.to_date
end
end
class UserRepresenter < ApplicationRepresenter
attr_field :first_name, :string
attr_field :last_name, :string
attr_many :activities
def full_name
"#{first_name} #{last_name}"
end
end
user = OpenStruct.new(
first_name: 'John',
last_name: 'Appleseed',
activities: [OpenStruct.new(created_at: Time.now)]
)
representer = UserRepresenter.wrap(user)
representer.full_name # => 'John Appleseed'
activity = representer.activities.first
activity.class # => ActivityRepresenter
activity.created_on # => returns current date
To create a representer, you can use the Rails generator.
$ bin/rails generate representer user
$ bin/rails g representer activity
License
MIT License. Copyright 2018-2020 Ryo Hashimoto.