7 Gems Which Will Make Your Rails Code Look Awesome

In Rubyroid Labs we are very passionate about application architecture. Most projects we work here are long-term projects, so if you are not beeing careful about your application design at some point you will find yourself in a position where in order to add a new feature it’s just easier to rebuild the whole project from the scratch. And it’s definitely not something you want to face up with.

One of the bad signs that your project is getting sick is that new team members spend a significant amount of time just reading through the source code in order to understand the logic. Today we want share a list of different gems, which in our opinion can help you to organize your code and make your team members smile.

**1. interactor**

This library is absolutely fabulous and has always been in our shortlist when talking about writing some complex business logic. What is an interactor? As gem readme says – “an interactor is a simple, single-purpose object, used to encapsulate your application’s business logic”. You can think of that as a service-objects we all love, but it’s a way more than that. Let’s take a look on the example:

https://blog.rubyroidlabs.com/2017/10/7-gems-rails-code/

In this example you probably noticed couple absolutely great features of this gem.
The first thing is that you are able to organize your simple interactors to an executable chain, which will be executed in proper order. Special variable context is being used to share states between different interactors.
The second thing is that if one of the interactors fails for some reason, all previous will be rolled-back. You could see that rollback on CreateOrder, which will drop an order if ChargeCard or SendThankYou fails.
It is so cool, isn’t it?

**2. draper**

If you have ever used custom Rails-helpers, you know how messy they become overtime. And in most cases we use them to display some data in a more fancy way. That’s where decorator design pattern can help us. Let’s take a look at a draper syntax, which is pretty self-explanatory:

# app/controllers/articles_controller.rb
def show
@article = Article.find(params[:id]).decorate
end

# app/decorators/article_decorator.rb
class ArticleDecorator < Draper::Decorator delegate_all def publication_status if published? "Published at #{published_at}" else "Unpublished" end end def published_at object.published_at.strftime("%A, %B %e") end end # app/views/articles/show.html.erb <%= @article.publication_status %>

In the code above you can see that our goal was to show published_at attribute in specific format. In classical rails-way we have 2 options of how to do that.
First one is just to write a special helper. The problem with this is that all helpers live under the namespace and as project longs you can face up with some weird name collision, which is extremely hard to debug.
The second one is to create a new method inside the model and use that method instead. This solution also feels wrong since it breaks model class responsibility. By default models are responsible for interaction with data, other than representation of that data.
That’s why using draper in this scenario is a more elegant way to achieve our goal.

**3. virtus**

Sometimes using a simple ruby object is not enough for you. Imagine you have some complex form on a page, where different pieces form should be saved as different models in the database. That’s where virtus can help you. Let’s take a look at the example:

class User
include Virtus.model

attribute :name, String
attribute :age, Integer
attribute :birthday, DateTime
end

user = User.new(:name => 'Piotr', :age => 31)
user.attributes # => { :name => "Piotr", :age => 31, :birthday => nil }

user.name # => "Piotr"

user.age = '31' # => 31
user.age.class # => Fixnum

user.birthday = 'November 18th, 1983' # => #

# mass-assignment
user.attributes = { :name => 'Jane', :age => 21 }
user.name # => "Jane"
user.age # => 21

As you can see, virtus looks similar to standard {OpenStruct} class, but gives you many more features. You should definitely play around to explore them all.

This gem could be a good start for you, but if you are looking for more advanced techniques – definitely go and check dry-types, dry-struct and dry-validation.

**4. cells**

If you are not familiar with Nick Sutterer Ruby on Rails advanced architecture, you should definitely check that out. Not all of us ready to apply this whole concept to their existing applications. But sometimes your views become really complicated, with different conditions applied for different types of user and etc. That’s where cells gem could help. It allows moving part of you views to isolated components, which are just regular ruby-classes. Let’s take a look at code sample:

# app/cells/comment_cell.rb
class CommentCell < Cell::ViewModel property :body property :author def show render end private def author_link link_to "#{author.email}", author end end # app/cells/comment/show.html.erb

New Comment

<%= body %>

By <%= author_link %>

# app/controllers/dashboard_controller.rb
class DashboardController < ApplicationController def index @comments = Comment.recent end end # app/controllers/dashboard/index.html.erb <% @comments.each do |comment| %>
<%= cell(:comment, comment) %>
<% end %>

In this example we want to display recent comments on our dashboard. Imagine all comments should be displayed identical on our application. Rails will use some shared partial for rendering. But instead of doing that we use CommentCell object. You can think of that object as a combination of draper we talked about before with ability to render views. But of course it has many more features. Check their README to learn more about all options.

**5. retryable**

All modern web application do have different types of integrations. Sometimes it’s made through solid API calls, sometimes you have to upload a file to FTP or even use some binary protocol. Problem with all integrations is that sometimes their calls just fail. In some cases – it fails without any reasons. And the best thing you can do is just to try again. Thumbs up if you have ever had to do something like this:

begin
result = YetAnotherApi::Client.get_info(params)
rescue YetAnotherApi::Exception => e
retries ||= 0
retries += 1
raise e if retries > 5
retry
end

Here is where retryable can help you. Let’s take a look at how we can rewrite the example above using that gem:

Retryable.retryable(tries: 5, on: => YetAnotherApi::Exception) do
result = YetAnotherApi::Client.get_info(params)
end

It looks much nicer, doesn’t it? Check that gem out for other scenarios it supports.

**6. decent_exposure**

If you are not a big fan of using magic – this library is not for you. But in some applications we definitely have a lot of duplications for very simple and standard CRUD actions. That’s where decent_exposure could help you. Let’s imagine that we are creating new controllers to manage things. That’s how scaffold will look for us:

class ThingsController < ApplicationController before_action :set_thing, only: [:show, :edit, :update, :destroy] def index @things = Thing.all end def show end def new @thing = Thing.new end def edit end def create @thing = Thing.new(thing_params) respond_to do |format| if @thing.save format.html { redirect_to @thing, notice: 'Thing was successfully created.' } else format.html { render :new } end end end def update respond_to do |format| if @thing.update(thing_params) format.html { redirect_to @thing, notice: 'Thing was successfully updated.' } else format.html { render :edit } end end end def destroy @thing.destroy respond_to do |format| format.html { redirect_to things_url, notice: 'Thing was successfully destroyed.' } end end private def set_thing @thing = Thing.find(params[:id]) end def thing_params params.require(:thing).permit(:for, :bar) end end We can’t say that 60 lines of code is not too much. But as rubyists we always want it to be as minimalistic as possible. Let’s take a look at how it could be transformed using decent_exposure: class ThingsController < ApplicationController expose :things, ->{ Thing.all }
expose :thing

def create
if thing.save
redirect_to thing_path(thing)
else
render :new
end
end

def update
if thing.update(thing_params)
redirect_to thing_path(thing)
else
render :edit
end
end

def destroy
thing.destroy
redirect_to things_path
end

private

def thing_params
params.require(:thing).permit(:foo, :bar)
end
end

Yakes! Now it’s a little more than 30 lines of code without losing any functionality. As you could notice – all magic is brought by expose method. Check this gem documentation for a better understanding of how things work under the hood.

**7. groupdate**

Every developer knows that dealing with different time zones is a hard thing. Especially when you are trying to write some aggregation on your database. It always gave me hard time when someone asked: “Could I get how many users we are getting every day this month excluding free users” or similar. Now you can stop worrying about such requests and just use gem. Here is an example:

User.paid.group_by_week(:created_at, time_zone: "Pacific Time (US & Canada)").count
# {
# Sun, 06 Mar 2016 => 70,
# Sun, 13 Mar 2016 => 54,
# Sun, 20 Mar 2016 => 80
# }

Hope you enjoyed some of these libraries. Let us know if you have any other tools in your mind which can help to write more expressive and awesome code.

4 thoughts on “7 Gems Which Will Make Your Rails Code Look Awesome”

  1. Instead of Draper, I just use the built-in Ruby `SimpleDelegator`… nearly identical code as your example, except it’s a subclass of SimpleDelegator (and no additional dependency).

    class ArticleDecorator < SimpleDelegator def publication_status if published? "Published at #{published_at}" else "Unpublished" end end def published_at object.published_at.strftime("%A, %B %e") end end In your controller, you would do this instead: @article = ArticleDecorator.new(Article.find(params[:id])) All methods are delegated for free (so no delegate_all macro needed). I'm sure Draper has some more options, but `SimpleDelegator` does what I need! I can wrap decorators with other decorators (think wrappers) and use different decorator classes in different parts of my application. For instance, I have a `UserProfileDecorator` and a `UserCustomerDecorator`, both used to wrap a `User` but in different contexts. Not sure if Draper has this flexibility (maybe it does) Here's a blog post on `SimpleDelegator`: https://hashrocket.com/blog/posts/using-simpledelegator-for-your-decorators

    Good list – I do use Virtus for my FormObjects.

    Reply
  2. right now we’re trying to get rid of interactor in our codebase. Mostly because of “context” concept, it makes things really hard to trace. Plain ruby objects with initializers look so much better.

    Also Virtus becomes ugly very fast when your needs to cleanup or convert data become more specialized. It tries to be ActiveModel-y, but is different enough to cause some frustration. But we still don’t have anything better, though.

    Reply

Leave a Comment