Dry-web-roda for Rails Developers Part I
Revised by Piotr Solnica and Andy Holland
Lately, I have been playing around and contributing to the extraordinary ecosystem of dry-rb. The community is absolutely fantastic, supportive, and eager to welcome many new contributors.
First, I will like to thank Piotr Solnica, Andy Holland, Tim Riley and Nikita Shilnikov - they have been helpful and patient with my many questions.
Yesterday I started playing with a gem called dry-web-roda. This small framework aims to provide an alternative to building web apps using ruby, using small libraries such as dry-view, dry-container, dry-transaction, roda, rom and many more; they help you build more transparent, flexible and more maintainable code.
The post tries to create a bridge for Rails developers and encourages them to try alternatives, bringing joy and fresh concepts for building web apps with Ruby.
After installing the gem, we can create a sample app by typing dry-web-roda new github_stalker --arch=flat
- this will create the file structure.
├── bin
├── config
├── db
├── lib
│ ├── github_stalker
│ │ └── views
│ └── persistence
│ ├── commands
│ └── relations
├── log
├── spec
│ └── support
│ └── db
├── system
│ ├── boot
│ └── github_stalker
├── transactions
└── web
├── routes
└── templates
└── layouts
At first, the structure is quite different from what we are used to in a typical Rails app, but I will explain it.
First, the system folder is where all the configuration lives. We can think of them as our initializers. Many small libraries are involved in making everything work, and I can not go into detail in just one post. I will cover all of them in a series of posts.
├── system
├── boot
│ ├── monitor.rb
│ ├── rom.rb
│ └── view.rb
├── boot.rb
└── github_stalker
├── application.rb
├── container.rb
├── import.rb
├── repository.rb
├── settings.rb
├── transactions.rb
├── view_context.rb
└── view_controller.rb
We will start with application.rb
. This file contains all the configuration regarding routes
, container
and plugins to be used with roda
.
require "dry/web/roda/application"
require_relative "container"
module GithubStalker
class Application < Dry::Web::Roda::Application
configure do |config|
config.container = Container
config.routes = "web/routes".freeze
end
opts[:root] = Pathname(__FILE__).join("../..").realpath.dirname
use Rack::Session::Cookie, key: "github_stalker.session", secret: GithubStalker::Container.settings.session_secret
plugin :csrf, raise: true
plugin :flash
plugin :dry_view
route do |r|
r.multi_route
r.root do
r.view "welcome"
end
end
load_routes!
end
end
What is a container? I’m going to bring the words from the official website dry-container is a simple, thread-safe container, intended to be one half of the implementation of an IoC container
or how I understand it, a container “gives you access to the objects that make up your application”.
Roda (the router) is a Routing Tree Web Toolkit.
Following is the container.rb
and import.rb
, which in my opinion, is where all the magic happens, thanks to dry-container
and dry-auto_inject
. These files hold the configuration for loading the files for our application, more or less like auto_load_path
of Rails.
require "dry/web/umbrella"
require_relative "settings"
module GithubStalker
class Container < Dry::Web::Umbrella
configure do
config.name = :github_stalker
config.default_namespace = "github_stalker"
config.settings_loader = GithubStalker::Settings
config.listeners = true
config.auto_register = %w[
lib/github_stalker
]
end
load_paths! "lib", "system"
def self.settings
config.settings
end
end
end
At first sight, we see some configuration for name, namespace and some auto_register
. This will register all the files inside our lib/github_stalker
folder in your container, following the convention from the file structure, so for example
├── lib
├── github_stalker
├── github
│ ├── client.rb # will register inside our container under the name github.client
│ ├── fetch_gists.rb # github.fetch_gists
│ └── fetch_info.rb # github.fetch_info
└── users
└── validate_input.rb # users.validate_input
And thanks to dry-auto_inject
, all these files will be lazily loaded as required, making it efficient.
require "github_stalker/import"
module GithubStalker
module Github
class FetchGists
include GithubStalker::Import['github.client'] # at the instance level we will have access to `client`
def call(input)
client.gists(input)
end
end
end
end
This post is getting too long, and I don’t want to take more of your time. Thank you for reading it. I will keep creating more posts explaining the rest of the structure and libraries involved in dry-rb
- they are great and bring a new view in the ruby world.
All the above examples were taken from an example app I built using dry-web-roda
; if you want to check the code, check this repo
If you have any thoughts or questions, please share, and I’ll be happy to answer in the comments.