Monday, July 22, 2024
HomeRuby On RailsRuby on Rails View Patterns and Anti-patterns

Ruby on Rails View Patterns and Anti-patterns


Welcome again to the third installment of the Ruby on Rails Patterns and Anti-Patterns collection. Within the earlier posts, we coated patterns and anti-patterns on the whole in addition to in relation to Rails Fashions. On this publish, we’re going to go over some patterns and anti-patterns related to Rails views.

Rails views can typically work completely and be quick, and at different instances, they will have all types of points. If you wish to improve confidence over the way you deal with your views otherwise you simply wish to study extra on the subject, then this weblog publish is for you. Let’s dive proper in.

As you in all probability know, the Rails framework follows conference over configuration. And since Rails is large on the Mannequin-View-Controller (MVC) sample, the motto naturally applies to the View code as nicely. This consists of your markup (ERB or Slim recordsdata), JavaScript and CSS recordsdata. At first look, you would possibly assume that the View layer is fairly easy and straightforward, however needless to say as of late, there’s a mixture of applied sciences residing within the View layer.

We use JavaScript, HTML, and CSS within the view. These three can result in confusion and disorganization of code — resulting in implementation that doesn’t make a lot sense in the long term. Fortunately, as we speak we’re going to undergo some frequent issues and options with the Rails View layer.

Powerlifting Views

This can be a mistake that doesn’t occur that usually, however when it does, it’s an eyesore. Typically, folks are inclined to put the area logic or querying straight contained in the View. This makes the View layer do the heavy-lifting or powerlifting. What’s attention-grabbing is that Rails really permits this to simply occur. There isn’t a ‘security web’ in terms of this, you’re allowed to do no matter you need within the View layer.

By definition, the View layer of the MVC sample ought to include presentation logic. It shouldn’t be bothered with area logic or with querying knowledge. In Rails, you get ERB recordsdata (Embedded Ruby) that let you write Ruby code that can then get evaluated into HTML. If we take into account an instance of a web site that lists songs on the index web page, then the view logic could be within the app/views/songs/index.html.erb.

As an example what “powerlifting” means and what not do to, let’s check out the next instance:

# app/views/songs/index.html.erb

<div class="songs">
  <% Tune.the place(printed: true).order(:title) do |track| %>
    <part id="song_<%= track.id %>">
      <span><%= track.title %></span>

      <span><%= track.description %></span>

      <a href="<%= track.download_url %>">Obtain</a>
    </part>
  <% finish %>
</div>

An enormous anti-pattern right here is the fetching of songs proper within the markup. The duty of fetching the info must be delegated to the controller or a service that’s being referred to as from the controller. I typically see folks put together some knowledge within the controller and later fetch extra knowledge within the views. That is unhealthy design and it makes your web site slower since you are stressing your database with queries extra typically.

What it’s best to do as an alternative is to show a @songs occasion variable from the controller motion and name that within the markup, like so:

class SongsController < ApplicationController
  ...

  def index
    @songs = Tune.all.the place(printed: true).order(:title)
  finish

  ...
finish
# app/views/songs/index.html.erb

<div class="songs">
  <% @songs.every do |track| %>
    <part id="song_<%= track.id %>">
      <span><%= track.title %></span>

      <span><%= track.description %></span>

      <a href="<%= track.download_url %>">Obtain</a>
    </part>
  <% finish %>
</div>

These examples are removed from excellent. If you wish to maintain your controller code extra readable and keep away from SQL Pasta, I urge you to take a look at the earlier weblog publish. Additionally, leaving out the logic within the View layer will increase the probabilities that different folks will attempt to construct their options off of it.

Make Use of What Rails Provides You

We’ll maintain it quick right here. Ruby on Rails as a framework comes with a variety of neat helpers, particularly contained in the view. These nifty little helpers let you construct your View layer shortly and effortlessly. As a newbie person of Rails, you may be tempted to put in writing the total HTML inside your ERb recordsdata like so:

# app/views/songs/new.html.erb

<kind motion="/songs" methodology="publish">
  <div class="subject">
    <label for="song_title">Title</label>
    <enter kind="textual content" identify="songRuby on Rails View Patterns and Anti-patterns" id="song_title">
  </div>

  <div class="subject">
    <label for="song_description">Description</label>
    <textarea identify="songWelcome again to the third installment of the Ruby on Rails Patterns and Anti-Patterns collection. Within the earlier posts, we coated patterns and…" id="song_description"></textarea>
  </div>

  <div class="subject">
    <label for="song_download_url">Obtain URL</label>
    <textarea identify="track[download_url]" id="song_download_url"></textarea>
  </div>

  <enter kind="submit" identify="commit" worth="Create Tune">
</kind>

With this HTML, it’s best to get a pleasant kind for a brand new track as seen within the screenshot under:



New song form

However, with Rails, you don’t want and also you shouldn’t write plain HTML like that since Rails has your again proper there. You should use the form_with view helper that can generate the HTML for you. form_with was launched in Rails 5.1 and it’s there to exchange form_tag and form_for that may be acquainted to some people. Let’s see how form_with can relieve us from writing further code:

<%= form_with(mannequin: track, native: true) do |kind| %>
  <div class="subject">
    <%= kind.label :title %>
    <%= kind.text_field :title %>
  </div>

  <div class="subject">
    <%= kind.label :description %>
    <%= kind.text_area :description %>
  </div>

  <div class="subject">
    <%= kind.label :download_url do %>
      Obtain URL
    <% finish %>
    <%= kind.text_area :download_url %>
  </div>

  <%= kind.submit %>
<% finish %>

Apart from producing HTML for us, form_with additionally generates an authenticity token that forestalls CSRF assaults. So in virtually all circumstances, you’re higher off utilizing designated helpers since they may play nicely with the Rails framework. In case you tried to submit a plain HTML kind, it can fail as a result of there was no legitimate authenticity token submitted with the request.

Apart from form_with, label, text_area, and submit helpers, there are a bunch extra of those view helpers that come out-of-the-box with Rails. They’re there to make your lives simpler and it’s best to get to know them higher. One of many “all-stars” is unquestionably link_to:

<%= link_to "Songs", songs_path %>

Which can generate the next HTML:

<a href="/songs">Songs</a>

I received’t go into a lot element on every helper, since this publish can be too lengthy and going by all of them isn’t a part of as we speak’s subject. I recommend you undergo Rails Motion View helpers information and choose what you want to your web site.

Reusing and Organizing View Code

Let’s think about the proper internet software. Within the excellent use-case, there aren’t any if-else statements, simply pure code that takes knowledge from the controller and places it between HTML tags. That sort of software exists possibly in hackathons and goals, however real-world functions have a bunch of branches and situations when rendering views.

What must you do when the logic for displaying elements of a web page will get too advanced? The place do you go from there? A normal reply could be to maybe attain for a contemporary JavaScript library or framework and construct one thing advanced. However, since this publish is about Rails Views, let’s have a look at the choices now we have inside them.

After-Market (Customized) Helpers

Let’s say you wish to present a call-to-action (CTA) button under a track. However, there’s a catch — a Tune can both have a obtain URL or, for no matter cause, it may be lacking. We may be tempted to code one thing much like the next:

# app/views/songs/present.html.erb

...

<div class="song-cta">
  <% if @track.download_url %>
    <%= link_to "Obtain", download_url %>
  <% else %>
    <%= link_to "Subscribe to artists updates",
                artist_updates_path(@track.artist) %>
  <% finish %>
</div>

...

If we have a look at the instance above as an remoted presentational logic, it doesn’t look too unhealthy, proper? However, if there are extra of those conditional renders, then the code turns into much less readable. It additionally will increase the possibilities of one thing, someplace not getting rendered correctly, particularly if there are extra situations.

One method to combat these is to extract them to a separate helper. Fortunately, Rails offers us a method to simply write customized helpers. Within the app/helpers we will create a SongsHelper, like so:

module SongsHelper
  def song_cta_link
    content_tag(:div, class: 'song-cta') do
      if @track.download_url
        link_to "Obtain", @track.download_url
      else
        link_to "Subscribe to artists updates",
                artist_updates_path(@track.artist)
      finish
    finish
  finish
finish

If we open up the present web page of a track, we’ll nonetheless get the identical outcomes. Nonetheless, we will make this instance a bit higher. Within the instance above, we used an occasion variable @track. This may not be accessible if we resolve to make use of this helper at a spot the place @track is nil. So to chop off an exterior dependency within the type of an occasion variable, we will cross in an argument to the helper like so:

module SongsHelper
  def song_cta_link(track)
    content_tag(:div, class: 'song-cta') do
      if track.download_url
        link_to "Obtain", track.download_url
      else
        link_to "Subscribe to artists updates",
                artist_updates_path(track.artist)
      finish
    finish
  finish
finish

Then, within the view, we will name the helper like under:

# app/views/songs/present.html.erb

...

<%= song_cta_link(@track) %>

...

With that, we must always get the identical leads to the view as we did earlier than. The advantage of utilizing helpers is that you could write assessments for them making certain that no regression occurs relating to them sooner or later. A con is that they’re globally outlined and you must make sure that helper names are distinctive throughout your app.

In case you are not an enormous fan of writing Rails customized helpers, you may at all times opt-in for a View Mannequin sample with the Draper gem. Or you may roll your personal View Mannequin sample right here, it shouldn’t be that sophisticated. In case you are simply beginning out along with your internet app, I recommend beginning slowly by writing customized helpers and if that brings ache, flip to different options.

DRY up Your Views

What I actually favored once I began with Rails was the power to simply DRY up your markup that it was virtually unbelievable to me. Rails provides you the power to create partials — reusable code items that you could embrace anyplace. For instance, in case you are rendering songs in a number of locations, and you’ve got the identical code throughout a number of recordsdata, it is smart to create a track partial.

Let’s say you present your track as proven under:

# app/views/songs/present.html.erb

<p id="discover"><%= discover %></p>

<p>
  <sturdy>Title:</sturdy>
  <%= @track.title %>
</p>

<p>
  <sturdy>Description:</sturdy>
  <%= @track.description %>
</p>

<%= song_cta_link %>

<%= link_to 'Edit', edit_song_path(@track) %> |
<%= link_to 'Again', songs_path %>

However, you additionally wish to present it on one other web page with the identical markup. Then you may create a brand new file with an underscore prefix like app/views/songs/_song.html.erb.

# app/views/songs/_song.html.erb

<p>
  <sturdy>Title:</sturdy>
  <%= @track.title %>
</p>

<p>
  <sturdy>Description:</sturdy>
  <%= @track.description %>
</p>

<%= song_cta_link(@track) %>

After which wherever you wish to embrace the track partial, you simply do the next:

...

<%= render "track" %>

...

Rails will do an auto-lookup of whether or not the _song partial exists and it’ll render it. Much like an instance with customized helpers, it’s best if we eliminate the occasion variable @track in our partial.

# app/views/songs/_song.html.erb

<p>
  <sturdy>Title:</sturdy>
  <%= track.title %>
</p>

<p>
  <sturdy>Description:</sturdy>
  <%= track.description %>
</p>

<%= song_cta_link(track) %>

Then, we might want to cross within the track variable to the partial, making it extra reusable and appropriate to being included in different places.

...

<%= render "track", track: @track %>

...

Closing Ideas

That’s all of us for this publish. To summarize, we went by a couple of patterns and anti-patterns that you could come throughout within the Rails View realm. Listed here are a couple of takeaways:

  • Keep away from advanced logic within the UI (don’t make the View do a lot of powerlifting)
  • Be taught what Rails provides you out-of-the-box when it comes to View helpers.
  • Construction and reuse your code with customized helpers and partials
  • Don’t depend upon occasion variables an excessive amount of.

Within the subsequent publish, we’ll cowl Rails Controller patterns and anti-patterns the place issues can get fairly messy. Keep tuned for that.

Till the following one, cheers!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments