Project

lightrails

0.0
No release in over a year
Lightrails is a utility library including Action Facade, Action Interactor, Active Representer etc. It aims to provide more modular layers for Ruby on Rails applications.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 3.3

Runtime

>= 1.3
>= 6.0, < 7.1
 Project Readme

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.