Ruby Report is a simple and flexible tool for generating reports in various formats (Hash, CSV, XLSX). The library supports custom headers, data formatting, decorators, and the ability to combine multiple reports.
Add the following lines to your application's Gemfile:
gem "ruby_report"
# optional gems
gem "csv" # for CSV
gem "caxlsx" # for XLSXThen run:
bundle install- Create a report class by inheriting from
RubyReport::Report:
class UserReport < RubyReport::Report
columns :name, :age, :role
end- Initialize the report object with data (ActiveRecord or an array of objects):
report = UserReport.new(data: User.all)- Generate the report in the desired format:
# Hash
report.to_h
# => {header: ["Name", "Age", "Role"], rows: [["Sasha", 18, "Student"]]}
# CSV
report.to_csv
# => IOString
# XLSX
report.to_xlsx(worksheet_name: "Worksheet")
# => IOStringRuby Report supports multiple output formats:
- Hash: Returns a structure with headers and rows.
- CSV: Generates a CSV file.
- XLSX: Creates an Excel file.
report.to_h
report.to_csv
report.to_xlsx(worksheet_name: "My Worksheet")Headers are fetched from I18n by default:
I18n.t("ruby_reports.user_report.headers.name") # => "Name"You can override headers using a custom builder:
UserReport.new(
data: data,
header_builder: ->(key, _report) { "Custom #{key}" }
)Select only the necessary columns:
report = UserReport.new(data: data, columns: [:name, :age])
report.headers # => ["Name", "Age"]
report.rows # => [["Sasha", 18], ["Jack", 30]]Use row_resolver to modify row data:
UserReport.new(
data: data,
row_resolver: ->(row) { row.user }
)Or use row_builder for full customization:
UserReport.new(
data: data,
row_builder: ->(_row, key, _report) { key.upcase }
)Decorators allow you to modify data before output:
class UserDecorator < RubyReport::Decorator
def role
I18n.t("roles.#{object.role}")
end
end
class UserReport < RubyReport::Report
columns :name, :age, :role, decorators: [UserDecorator]
endFormatters transform values into the desired format:
class TimeFormatter < RubyReport::Formatter
def format(value)
return value unless [::Time, ActiveSupport::TimeWithZone].include?(value.class)
value.utc.to_formatted_s(:report)
end
end
class UserReport < RubyReport::Report
columns :name, :age, :role, :created_at, formatters: [TimeFormatter]
endPass additional data through scope:
class UserDecorator < RubyReport::Decorator
def role
I18n.t("roles.#{object.role}", account_name: scope[:account].name)
end
end
report = UserReport.new(data: users, scope: { account: account }, decorators: [UserDecorator])Combine multiple reports into one:
class AccountReport < RubyReport::Report
columns :name
end
class AddressReport < RubyReport::Report
columns :street
end
user_report.prepend_report(account_report)
user_report.add_report(address_report)Create an XLSX file with multiple sheets:
require "ruby_report/generator/xlsx"
generator = RubyReport::Generator::Xlsx.new
generator.add_report(report, worksheet_name: "Worksheet 1")
generator.add_report(other_report, worksheet_name: "Worksheet 2")
generator.generate # => IOString