Lintity
Training gem (Engine) that shows list of entities
Installation
Add this line to your application's Gemfile:
gem "lintity", "~> 0.2.0"And then execute:
$ bundleOr install it yourself as:
$ gem install lintitySystem Requirements
- Ruby >= 3.4
- Ruby On Rails >= 8.0
- gem 'importmap-rails'
- gem 'stimulus-rails'
- gem 'pagy'
- bootstrap 5
- ActiveRecord
Entity List Usage
Create your controller
class CustomersController < Lintity::EntityListController #inherit
layout 'application' #use own main layout
before_action :set_customer, only: [:edit]
def index
@search_path = customers_path
@records =
if @filter_field && valid_filter_field?
Customer.where(Customer.arel_table[@filter_field].public_send(valid_filter_sign, @filter_value)) #implementing filter result
else
Customer.all
end
@pagy, @records = pagy(:offset, @records)
@entity_list_header_caption, @entity_list_new_path = "Customers List", new_customer_path
end
def edit; end
private
def init_fields #your fields from model
@fields_settings = [
{ field: 'name', name: 'Name', type: 'edit', path: Proc.new { |customer_id| edit_customer_path(id: customer_id) } }, # Add path for edit a record
{ field: 'phone', name: 'Phone', type: 'info' },
{ field: 'address', name: 'Address', type: 'info' },
{ field: 'ordered', name: 'Ordered', type: 'numeric_filter' },
{ field: 'no_of_orders', name: 'No Of Orders', type: 'numeric_filter' },
{ field: 'total_amount', name: 'Total Amount', type: 'numeric_filter' },
]
end
def set_customer
@customer = Customer.find(params[:id])
end
endOr implement the pagination by default
class CustomersController < Lintity::EntityListController
...
def index
@search_path = items_path
@entity_list_header_caption, @entity_list_new_path = "Items List", new_item_path
end
...
private
...
# Pagination is automatically handled by the controller
# @records will be paginated using pagy if it responds to paginate
def init_records
@records =
if @filter_field && valid_filter_field?
Customer.where(Customer.arel_table[@filter_field].public_send(valid_filter_sign, @filter_value))
else
Customer.all
end
endCouple useful methods implementation
def valid_filter_field?
@fields_settings.map { |f| f[:field] }.include?(@filter_field) && %(= <= >=).include?(@filter_sign)
end
def valid_filter_sign
case @filter_sign
when "="
"eq"
when "<="
"lteq"
when ">="
"gteq"
else
nil
end
endResults
Entity Report Usage
Create your controller
class StockBalanceReportsController < Lintity::EntityReportController
layout "application"
before_action :set_entity_filter_header, only: [ :index ]
def index
storage_id = params[:storage_id]
item_id = params[:item_id]
balance_time = params[:balance_time] || Time.current
@records = InventoryTransaction.stock_balance_by_batches_calculation(
storage_id: storage_id,
item_id: item_id,
to_time: balance_time,
fields_info: {
items: { include: :item, field: :name },
storages: { include: :storage, field: :name }
}
)
@entity_report_header_caption, @entity_report_pdf_path = "Stock Balance Report", stock_balance_reports_path(format: :pdf, storage_id: storage_id, item_id: item_id, balance_time: balance_time)
respond_to do |format|
format.html
format.pdf do
render pdf: "stock_balance_report_#{Time.current.to_i}", # The name of the downloaded file
template: "lintity/entity_report/index",
layout: "layouts/pdf", # Optional: Use a specific layout
disposition: "attachment" # Optional: Force download instead of inline view
end
end
end
# Show a form to select an Item and a Storage before displaying the report
def new
@items = Item.all
@storages = Storage.all
end
private
def set_entity_filter_header
filter_parts = []
if params[:storage_id].present?
storage_name = Storage.find_by(id: params[:storage_id])&.name
filter_parts << "Storage: #{storage_name}" if storage_name.present?
end
if params[:item_id].present?
item_name = Item.find_by(id: params[:item_id])&.name
filter_parts << "Item: #{item_name}" if item_name.present?
end
if params[:balance_time].present?
filter_parts << "Balance time: #{params[:balance_time]}"
end
@entity_filter_header_caption = "Filters: #{filter_parts.join(', ')}" if filter_parts.present?
end
def init_fields
@fields_settings = [
{ field: "item", caption: "Storage/Item/Batch", type: "info" },
{ field: "qty", type: "number" },
{ field: "cost", type: "number" }
]
end
endResults
Demo application:
License
The gem is available as open source under the terms of the MIT License.



