Using the get schwifty gem

Hey there, today I’m writing about an interesting gem I used some days ago to render some slow pages. This …

Hey there, today I’m writing about an interesting gem I used some days ago to render some slow pages. This gem has an interesting workflow. It renders a loading page that we’ve already defined while a background task makes the processes we need to display information for the user, e.g. heavy SQL queries, extended operations, or anything that makes the rendering of the pages running slow. After the background task finishes, the loading page is replaced by the page that we normally display. The author of the gem has an example app about how to use it. The gem also generates most of the configuration files that it needs to work, even when some files are required to be created manually. I’ll show you what files are needed to get schwifty to work.

Get the gem from its own repo and follow the installation instructions there, or in the link below: https://github.com/danielwestendorf/get_schwifty

Installation

  • Add to the gem file gem "get_schwifty"
  • Run in your bash the bundle command
  • Run the gem generator rails generate get_schwifty:install

Now, the following files should have already been created, but just in case something goes wrong, I’ll show you the default files content:

  • config/initializers/get_schwifty.rb

# frozen_string_literal: true # GetSchwifty configuration initializer. # Use this file to configure GetSchwifty according to your needs. GetSchwifty.configure do |config| # Configure rerendering # # By default, job parameters are stored in the Rails cache and they’re not removed after rendering. #If you're not expiring keys with a least recently used policy, your cache could get filled up with #values which will never be reaccessed. # Allow rerendering # This allows caching to the `get_schwifty` helper calls in views # config.allow_rerender = true # Default # Disable rerendering # This disables rerendering, and the cacheability of `get_schwifty` helper calls. Subscriptions # will be rejected after the first render of a cached `get_schwifty` call # config.allow_rerender = false end
  • app/controllers/get_schwifty_controller.rb

# frozen_string_literal: true # Used for rendering partials in schwifty background jobs class GetSchwiftyController < ApplicationController prepend_view_path Rails.root.join("app", "views", "cables").to_s end
  • app/channels/get_schwifty_channel.rb

# frozen_string_literal: true # Channel for handling schwifty subscriptions class GetSchwiftyChannel < ApplicationCable::Channel include GetSchwifty::Channel end
  • app/jobs/get_schwifty_runner_job.rb

  # frozen_string_literal: true # Job for running schwifty cables in the ActiveJob class GetSchwiftyRunnerJob < ApplicationJob include GetSchwifty::Job end
  • app/cables/base_cable.rb

# frozen_string_literal: true # Base cable class to inherit from when getting schwifty class BaseCable < GetSchwifty::Cable::Base include Rails.application.routes.url_helpers # Access to pundit helper methods for authorization # include Pundit # Utility method shared across cables for accessing the current user # def current_user # identifiers[:user] # end end
  • app/views/cables

This will be an empty folder where you should put the views you want to have rendered by the action cable after it finishes the tasks.
– app/assets/javascripts/channels/get_schwifty_channel.js


document.addEventListener("DOMContentLoaded", function() { GetSchwifty(App).showMeWhatYouGot(); });

These are configuration files. ,, there is no problem you copying them from the demo app, now you need to create your first cable. This is the main point of the gem, but before going there, I want to give you a general view of how the gem works and its workflow.

Gem workflow.

As you can see in the image, these are the four steps we have:

The Rails controller

First, we create the action in our controller just as all the rails applications work, nothing new here.

Loading view

Then the controller loads a partial that we had already created as the loading page. This page will be shown to the users while get schwifty does all the heavy things in a background job, and the loading page will be replaced by the final page until schwifty finishes loading. In this loading page we can send data we need to use on the cable using the get_schwifty view helper. Just be careful because all the data sent here can be visible to the user if he inspects the HTML tags, for example:

#This is the loading view, loaded by the controller

Calculating Fibonacci of, please wait...

You would see something like this in the explorer if someone inspects the element.

As you can see the params sent by the get_schwifty view helper are visible in the HTML’s tag, this is how the gem saves and recovers values, so be careful with the data you send. Try to send information that is not relevant in case the user gets to see it. The data sent by this helper will be retrieved as standard ruby objects. For example during my first attempt, I tried to send a kaminari array which was retrieved as a simple array, so I lost all the methods that kaminari provides to those objects like total_pages and current_page methods, so keep an eye on those details.

The cable

Next step, be aware of where we are, the cable is a background job, this means that you have lost all the variables and values that you had in the controllers and the views. The requested object has been lost, so you should send the data needed from the loading view using the get_schwifty view helper. These values are available here inside a hash called params. During this step we tell the cable what partial should replace the loading one, and send params if needed, we can do that with the stream helper, for example:

def fibonacci
n = params[:i] || SecureRandom.rand(20..40)
calculated = calculate_fibonacci(n)
stream partial: "dashboard/fibonacci", locals: { calculated: calculated, n: n }
end

Cable’s rendered view

This is the last step. At this point, the loading page has been replaced by the cable’s rendered view, and it should be the one requested.

 

How to create a new cable?

  • rails generate get_schwifty:cable YourCableName method_name

    That command will create two files like the following:

rails generate get_schwifty:cable Test test:

  • app/cables/test_cable.rb

class TestCable < BaseCable def test a = 1 b = 2 stream partial: "test/test", locals: { a: a, b: b } end end
  • app/views/cables/test/_test.html.erb

<!-- Slow to render HTML goes here -->

How to use the recently created cable?

First, call the loading page from your application controller.

  • app/controllers/application_controller.rb

class ApplicationController < ActionController::Base protect_from_forgery with: :exception def index render partial: 'index' render partial: 'index' end end
  • app/views/application/_index.html.erb

<%= get_schwifty "test_cable#test" do %> Loading :D <%- end %>
  • app/cables/test_cable.rb

class TestCable < BaseCable def test # Your super awesome code goes here #Please use a better name than test :D stream partial: "test/test", locals: { foo: 'foo', bar: 'bar' } end end
  • app/views/cables/test/_test.html.haml

Super awesome final page. I received the params Foo: <%= foo %> Bar: <%= bar %>

And that is it, now you should have a functional cable.

Super awesome final page. I received the params Foo: foo Bar: bar

 

I hope this post is helpful for you. Feel free to leave any comments or questions below.

Keep reading

More >