This new Lotus release is an important step towards 1.0!
In the past months we talked with people at conferences, meetups, events, you all are eagerly looking for a production ready version. This makes us proud of Lotus and we are determined to get there.
That's why we have decided to postpone a few announced features like WebSocket and experimental code reloading.
Features
Let's have a look at what is shipped with this version.
Mailers
Inês & Rosa (aka DEIGirls), are the Rails Girls Summer of Code students who worked on mailers.
During these three months, mentored by Trung Lê, they learned about Ruby, Lotus and they shipped their first gem: lotus-mailer
.
This is a huge achievement for all of us!
We have introduced a generator, which creates a mailer, the test code and two associated templates for multipart delivery.
% bundle exec lotus generate mailer forgot_password
create spec/bookshelf/mailers/forgot_password_spec.rb
create lib/bookshelf/mailers/forgot_password.rb
create lib/bookshelf/mailers/templates/forgot_password.txt.erb
create lib/bookshelf/mailers/templates/forgot_password.html.erb
For simplicity, each mailer can handle only one use case (feature).
If in our application we need to send emails for several features like: "confirm your email address" or "forgot password", we will have Mailers::ConfirmEmailAddress
and Mailers::ForgotPassword
instead of a generic UserMailer
that manages all these use cases.
# lib/bookshelf/mailers/forgot_password.rb
class Mailers::ForgotPassword
include Lotus::Mailer
from 'noreply@lotusrb.org'
to 'user@example.com'
subject 'Hello'
end
# Usage
Mailers::ForgotPassword.deliver
Lotus::Mailer is built on top of the rock solid mail
gem by Mikel Lindsaar.
Custom Data Mapper Coercions
Lotus data mapper supports the most common Ruby data type such as String
, Integer
, or DateTime
.
Sometimes, this simple approach is not enough to solve the database impedance mismatch on types.
Imagine we have a Book#tags
, a collection of strings that we want to store as a Postgres array.
If we use Array
builtin type, our tags aren't properly translated into a format that is compatible with our column type.
The solution to this problem is to define a custom coercer.
# lib/ext/pg_array.rb
require 'lotus/model/coercer'
require 'sequel/extensions/pg_array'
class PGArray < Lotus::Model::Coercer
def self.dump(value)
::Sequel.pg_array(value, :varchar)
end
def self.load(value)
::Kernel.Array(value) unless value.nil?
end
end
# lib/bookshelf.rb
require_relative './ext/pg_array'
# ...
Lotus::Model.configure do
# ...
mapping do
# ...
collection :articles do
attribute :id, Integer
attribute :tags, PGArray
end
end
end.load!
Command / Query Separation
When the powerful repositories API doesn't fit our needs, we can send raw command and queries to the database.
Until now there was a generic .execute
to use. Both the signature and the semantic of this method, became too complex, so we decided to add .fetch
.
It returns a raw dataset from the database.
# lib/bookshelf/repositories/book_repository.rb
class BookRepository
include Lotus::Repository
def self.raw_all
fetch("SELECT * FROM books")
end
def self.find_all_titles
fetch("SELECT title FROM books").map do |book|
book[:title]
end
end
end
We changed .execute
send a raw command and return nil
.
# lib/bookshelf/repositories/book_repository.rb
class BookRepository
include Lotus::Repository
def self.reset_download_count
execute("UPDATE books SET download_count = 0")
end
end
Minor Changes
Thanks to Theo Felippe for the MIME type detection work and to Wellington Santos for a better exception handling.
To Pascal Betz, José Mota, Alex Wochna and Khải Lê for their form helper enhancements, while Leonardo Saraiva wrote an expanded version of #link_to
.
Alfonso Uceda added SQL joins, Bohdan V. and Manuel Corrales fixed small Lotus::Model issues, while Brenno Costa worked on JRuby support!
We're thankful for the improvements and fixes that Ben Lovell, Rodrigo Panachi, Derk-Jan Karrenbeld, Cẩm Huỳnh and Andrii Ponomarov did on lotusrb
.
Deprecations
Default Format
We deprecated default_format
in favor of default_request_format
.
We also introduced default_response_format
to force a MIME Type, without the need of specify it for each action.
It defaults to :html
, but if you are building a JSON API, you may find useful to set it to :json
.
# apps/web/application.rb
# ...
module Web
class Application < Lotus::Application
configure do
# If you are using this:
default_format :xml
# Please rename into:
default_request_format :xml
end
end
end
Hack Day
Did you always wanted to play with Lotus but you keep saying: "I don't have time"?
As Lotus will approach to 1.0, we'll need your help, your feedback.. and your fun! So, here's the deal.. we're organizing a Hack Day later this year!
⬇️ If you want to get alerted, please consider to subscribe to our mailing list using the form below. ⬇️
Until then, happy hacking!