Readymade
This gems contains basic components to follow ABDI architecture
Tested with ruby:
- 3.1
- 3.0
- 2.7
Installation
Add this line to your application’s Gemfile:
“by gem ‘readymade’
“
And then execute:
$ bundle install
Or install it yourself as:
$ gem install readymade
Usage
Inherit your components from: * Readymade::Response
* Readymade::Form
* Readymade::InstantForm
* Readymade::Action
* Readymade::Operation
Readymade::Response
“by response = Readymade::Response.new(:success, my_data: data) response.success? # true response = Readymade::Response.new(:fail, errors: errors) response.success? # false response.fail? # true response.status # ‘fail’ response.data # { errors: { some: ‘errors’ } }
“
Readymade::Form
Check more form features examples in lib/readymade/form.rb
“by class Orders::Forms::Create < Readymade::Form PERMITTED_ATTRIBUTES = %i[email name category country customer] REQUIRED_ATTRIBUTES = %i[email]
validates :customer, presence: true, if: args[:validate_customer] end
order_form = Orders::Forms::Create.new(params, order: order, validate_customer: false)
order_form.valid? # true
“
form_options
“by
app/forms/my_form.rb
class MyForm < Readymade::Form PERMITTED_ATTRIBUTES = %i[email name category country] REQUIRED_ATTRIBUTES = %i[email]
def form_options { categories: args[:company].categories, countries: Country.all } end end
“
“by
app/controllers/items_controller.rb
def new @form = MyForm.form_options(company: current_company) end
“
“im / app/views/items/new.html.slim
= f.select :category, collection: @form[:categories]
= f.text_field :email, required: @form.required?(:email) # true
“
Readymade::InstantForm
Permit params and validates presence inline
“by Readymade::InstantForm.new(my_params, permitted: %i[name phone], required: %i[email]) # permits: name, phone, email; validates on presence: email
“
Readymade::Action
“by class Orders::Actions::SendNotifications < Readymade::Action def call send_email send_push send_slack
response(:success, record: record, any_other_data: data)
end end
“
“by response = Orders::Actions::SendNotifications.call(order: order)
response.fail? # false response.success? # true response.data[:record] response.data[:any_other_data]
“
.call_async
- any action could we call async (using ActiveJob)
“by class Orders::Actions::SendNotifications < Readymade::Action def call send_email send_push send_slack
response(:success, record: record, any_other_data: data)
end … end
Orders::Actions::SendNotifications.call_async(order: order) Orders::Actions::SendNotifications.call_async!(order: order, queue_as: :my_queue) # job will be executed in ‘my_queue’
Important! Make sure your sidekiq configuration has ‘my_queue’ queue
“
.call!
- raise error unless response is success
(action must return Readymade::Response.new(:success))
“by class Orders::Actions::SendNotifications < Readymade::Action def call! send_email return response(:fail, errors: errors) unless email_sent? send_push send_slack
response(:success, record: record, any_other_data: data)
end … end
Orders::Actions::SendNotifications.call!(order: order) # raise error if response is fail
“
.call
+ conisder_success: true
“by class Orders::Actions::SendNotifications < Readymade::Action def call! send_email return response(:skip, consider_success: true) if skip_email? send_push send_slack
response(:success, record: record, any_other_data: data)
end … end
Orders::Actions::SendNotifications.call!(order: order) # does not raise error if skip_email? returns true
“
.call_async!
- runs in background and raise error unless response is success
(action must return Readymade::Response.new(:success))
“by class Orders::Actions::SendNotifications < Readymade::Action def call! send_email return response(:fail, errors: errors) unless email_sent? send_push send_slack
response(:success, record: record, any_other_data: data)
end … end
Orders::Actions::SendNotifications.call_async!(order: order) # job will be failed
“
Readymade::Operation
Provides set of help methods like: build_form
, form_valid?
, validation_fail
, save_record
, etc.
“by class Orders::Operations::Create < Readymade::Operation def call build_record build_form return validation_fail unless form_valid?
assign_attributes
return validation_fail unless record_valid?
save_record
success(record: record)
end end
“
Readymade::Controller::Serialization
“by class MyController < ApplicationController include Readymade::Controller::Serialization end
“
Serialization helpers for controllers. Dependencies that must be installed on your own: - blueprinter - pagy - api-pagination
Readymade::Model::ApiAttachable
Add base64 attachments format for your models
“by class User < ApplicationRecord has_one_attached :avatar has_many_attached :images include Readymade::Model::ApiAttachable # must be included after has_one_attached, has_many_attached declaration # api_file = { # base64: ‘iVBORw0KGgoAAA….’, # filename: ‘my_avatar.png’ # } # record.avatar = api_file 🎉 end
“
copy spec/support/api_attachable.rb
“by def to_api_file(file) { base64: Base64.encode64(file.read), filename: file.original_filename } end
“
“by
rspec example
let(:avatar) { Rack::Test::UploadedFile.new(Rails.root.join(‘spec/support/assets/test-image.png’), ‘image/png’) } let(:params) { { user: attributes_for(:user).merge!(avatar: to_api_file(avatar)) } }
“
Readymade::Model::Filterable
“by class User < ApplicationRecord include Readyamde::Model::Filterable
scope :by_status, ->(status) { where(status: status) } scope :by_role, ->(role) { where(role: role) } end
“
“by User.all.filter_collection({ by_status: ‘active’, by_role: ‘manager’ }) User.all.filter_collection({ by_status: ‘active’, by_role: ‘manager’ }, chain_with: :or) # active OR manager
“
Readymade::Model::ValidatableEnum
Instead of raised error when enum value is not valid, it adds error to the record
“by class User < ApplicationRecord include Readymade::Model::ValidatableEnum
enum status: { inactive: 0, active: 10 } enum role: { customer: 0, admin: 10 } validatable_enum :status, :role end
“
“by user = User.new(status: ‘archived’, role: ‘superadmin’) user.validate # false user.errors.full_messages # [Role superadmin is not a valid role, Status archived is not a valid status]
“
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/OrestF/readymade. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the Lead project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.