Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save RobAWilkinson/eb2ced8167d4674f951b to your computer and use it in GitHub Desktop.
Save RobAWilkinson/eb2ced8167d4674f951b to your computer and use it in GitHub Desktop.

#Rails Helpers and Helper Spec

LEARNING OBJECTIVES

  • Understand and explain what helper methods are.
  • How to create custom helper methods.
  • Learn how to test helpers and create them using TDD.

Definition: is a module which contains methods that are vital for the simplification and the dryness of your views.

Benefits

  1. Extract some complexity out of the view
  2. Make view logic easier to test

####Example

VIEW:

<% if @user && @user.email.present? %>
  <%= @user.email %>
<% end %>

TRANSFER TO HELPER:

module SiteHelper
  def user_email(user)
    user.email if user && user.email.present?
  end
end

NEW VIEW:

<%= user_email(@user) %>

We have all used built in rails helpers. Everyone take 5 minutes and pick a rails helper that you have used and explain it to the class.

What helpers were not covered by students?

Before we begin making helpers lets talk about where to put our code...

##Sorting our code

Models: For code about your database, the model is your first stop in Rails. Models are powerful, easy to test , reusable across applications and more like non-Rails code than most of Rails. If there's a good way to put the code in your model, that's usually a safe bet and a good idea.

Controllers: It's easy to put lots of code in your controllers, but it's almost always a mistake. Business logic for your app should get out of the controller and into the model as quickly as possible. Logic about how things are show to the user should go into the view. In general, the controller should be a tiny, thing glue layer putting together your other components.

Views: Having lots of logic in your views is a huge anti-pattern. Don't do it! It's hard to test, it's hard to find, it's hard to write sandwiched in between the HTML...Just don't. Instead your views should contain HTML, variables that turn into HTML, and calls to helper methods to generate HTML or whatever the final output is. There should be no logic in there to test.

Helpers: Rails "helpers" are very specifically view helpers. They're automatically included in views, but not in controllers or models. That's on purpose! Code in the application helper is included in all the views in your application. If you find yourself writing big loops, method calls or other logic in the view, move it into a method in the helper.

/lib directory: remember that helpers are specifically view helpers. What if you wanted a controller helper or model helper? Put them in this directory. The app controller could get large quick.

##TDD

Lets create the tests for the helper example given above:

require 'rails_helper'
RSpec.describe SiteHelper, :type => :helper do
  describe "#user_email" do
    context "when the user exists and has an email" do
      it "returns the user's email" do
        user = double("user", :email => "foo")
        expect(helper.user_email(user)).to eq("foo")
      end
    end
    context "when the user exists and has no email" do
      it "returns nil" do
        user = double("user", :email => nil)
        expect(helper.user_email(user)).to eq(nil)
      end
    end
    context "when the user doesn't exist" do
      it "returns nil" do
        expect(helper.user_email(nil)).to eq(nil)
      end
    end
  end
end

The second benefit listed above for using helpers is the fact that you can isolate the view logic and test it as a unit, I personally find this one very attractive. By using a helper as opposed to dumping everything in the view, you can isolate pieces that make up the view and test each one separately (edge cases and all). hat's really nice. You'll find the use of helpers really useful if you have a ton of view setup code like instance variables and such that you'd have to setup if you were to test the view instead.

###Code Along

*** Generate App***

   rails new helperApp
   cd helperApp

Add rspec-rails to gemfile

   echo 'gem "rspec-rails", :group => [:development, :test]' >> Gemfile

RSpec

   rails generate rspec:install

Generate a scaffold

  rails generate scaffold Widgets name:string

Run migrations

    rake db:migrate && rake db:test:prepare

Run RSpec

    rspec spec --format documentation

Lets begin by using the below scenarios

SCENARIOS: create spec and helper methods for each.

  • Helper method that returns a value
  • Helper method that accesses an instance variable
  • Application helper is included in helper object
  • Url helpers are defined

###Helper Spec

Helper specs are marked by :type => :helper or if you have set config.infer_spec_type_from_file_location! by placing them in spec/helpers.

Helper specs expose a helper object, which includes the helper module being specified, the ApplicationHelper module (if there is one) and all of the helpers built into Rails. It does not include the other helper modules in your app.

To access the helper methods you're specifying, simply call them directly on the helper object.

NOTE: helper methods defined in controllers are not included.

I will create the first scenario then for the remainder of the time everyone must complete as many specs as possible. I will give the answer 20 min till break.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment