You probably don't need these gems
Tags: ruby, ror, rails, beginners
Published: 2020-06-29 11:29:25

---
title: You probably don't need these gems
published: true
description: Sometimes programmers bundle their project with gems they even don't need. Simple snippets for popular gems.
tags: ruby, ror, rubyonrails, beginners
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/8h88tfummn60qd22c1lm.png
---

Gems are fun! They simplify your development process a lot. But sometimes programmers bundle their project with gems they even don't need. I often see projects where complexity is increasing dramatically by trying to solve simple problem using heavy gems. This article is devoted to beginner Rails developers, who copy-paste gems to their Gemfile without any doubt.

## You probably don't need config gem

```
https://github.com/rubyconfig/config
```

Popular gem for handling configuration of your app and global data. This gem in very cool and is maintained regularly. It's included in many project bundles. But maybe you can replace whole gem with 3 lines of code?

```ruby
# Ensure file has lodash before filename to be loaded before other initializers
# which can use settings data.
# config/initializers/_settings.rb
settings_file = File.join(Rails.root, "config", "settings", "#{Rails.env}.yml")
settings_string = File.read(settings_file)
SETTINGS = YAML.safe_load(settings_string).deep_symbolize_keys
```

And now just create folder with different environments
```
/config
  /settings
    development.yml
    production.yml
    test.yml
```

```yaml
# config/settings/development.yml
site:
  title: "My awesome site"
  contact_mail: "tpepost@gmail.com"
```

Now you can use `SETTINGS` in any part of your project.
```ruby
SETTINGS[:site][:title] #=> My awesome site
```

Of course it's not a full functionality that config gem provides, but in many cases people use it in this way, nothing more.

## You probably don't need local_time gem

```
https://github.com/basecamp/local_time
```

Despite the official support of Basecamp, it is not supported anymore as I'm aware. Gem has been updated last time 2 years ago. Also the included strftime JavaScript implementation is not 100% complete. And finally it requires sprockets. And you remember that Webpack is now default for Rails.

I think it is better to use popular JS library for this. You can use date-fns (I try to avoid moment.js due to it's large size (329KB)). The whole replacement of locale_time gem are two files: rails helper and in `app/helpers`, which creates necessary tag, which is then used by a small JS file.

First of all, install date-fns via yarn/npm or whichever you prefer. Rails expects you to use yarn (so am I).

```bash
yarn add date-fns
```

Then create helpers for your view. When you call the helper, it will create `span` tag with all required data for date-fns to convert its text to proper format. If JS is disabled, default Rails date string will appear.

```ruby
# app/helpers/time_helper.rb
module TimeHelper
  def format_time(time, format = "yyyy-MM-dd'T'HH:mm:ss.SSSxxx")
    content_tag(
      :span,
      time,
      data: { "time-format": format, "time-value": time.to_json }
    )
  end

  def relative_time(time)
    format_time(time, :relative)
  end

  def year(time)
    format_time(time, "yyyy")
  end
end
```

Finaly add appropriate JS file to find all timehelpers in your views and set time to requested format.

```js
// app/javascript/your/custom/path/timeHelper.js
// Don't forget to import into your pack

import formatDistance from "date-fns/formatDistance";
import format from "date-fns/format";

// Ensure it works with turbolinks
document.addEventListener("turbolinks:load", function() {
  const timeHelpers = document.querySelectorAll("[data-time-format]");
  
  Array.from(timeHelpers).forEach(function(timeHelper) {
    

    const timeFormat = timeHelper.getAttribute("data-time-format");
    const value = timeHelper.getAttribute("data-time-value");
    const datetime = Date.parse(JSON.parse(value));

    if (timeFormat === "relative") {
      timeHelper.textContent = formatDistance(datetime, new Date());
    }
    else {
      timeHelper.textContent =  format(datetime, timeFormat);
    }
  });
});
```

Now you can use it in your views

```html
  <p>Posted <%= relative_time(@post.created_at) %><p>
  <p>Created at: <%= format_time(@post) %><p>
  <p>Year: <%= year(@post) %><p>
  <p>Custom format: <%= year(@format_time, "MMMM") %><p>

  <!-- Custom formating: https://date-fns.org/v2.14.0/docs/format -->
```

As you can see, the workaround is very simple. Now you can expand this functionality further and forget about Sprockets.

## You probably don't need devise + devise-jwt gems

```
https://github.com/heartcombo/devise
https://github.com/waiting-for-dev/devise-jwt
```

Rails is a popular solution as the API server only. And when you need authentication, developers bundle monstrous devise to their project. Often in API workflow people use JWT authentication process. This causes them to add devise-jwt to empower devise functionality, which is huge even without any plugins. In API mode developers use only small part of devise, they need only encrypting, JWT issuing and sign-in/sign-up functionality. For this purpose it's better to use a simple gem - `knock`.

It provides everything you need for JWT authentication process. It's very thin and simple. It doesn't have view generators, included ready-to-use controllers, recovering letters and many other staff. Of course such functionality is very important for many apps, but when you act only as API server, you probably will write your custom logic anyway, that will have conflict with devise.

You need to add `has_secured_password` to your model

```ruby
class User < ActiveRecord::Base
  has_secure_password
end
```

Include `knock` logic to controller

```
class ApplicationController < ActionController::API
  include Knock::Authenticable
end
```

And `before_action` everywhere you need.

```ruby
class SecuredController < ApplicationController
  before_action :authenticate_user

  def index
    # etc...
  end
end
```

That is all. Now you have `current_user` - same as in Devise. Simple and fast.

## Your probably need these gems!

This article is not about proving that gems we discussed are bad or not suitable for your project. They solve specific problems in a convenient way. Moreover, I insist on using them to reduce onboarding pain for new developers, because they are most likely familiar with these gems and not familiar with your custom codebase. You don't need to write your own code everywhere, you just need to ask yourselves a question before `bundle install` command: "Do I really need this gem? Maybe I can solve it in a simple way without bloating my dependency graph?".

Be wise, use gems in a smart way!