Journal
My Ruby and Rails Cheatsheet
I’m no Ruby engineer however even as a front-end developer I’m sometimes called upon to work on Rails applications that require me to know my way around. Here are my notes and reminders.
This is not intended to be an authoritative guide but merely my notes from various lessons. It’s also a work-in-progress and a living, changing document.
Table of contents
- The Rails Console
- Rspec
- Debugging
- Helpers
- blank? vs empty?
- frozen_string_literal
- Class-level methods
- Constants
- Symbols
- Hashes
- ViewComponent
- Instance Variables
- Methods
- Empty-checking arrays
- The Shovel Operator
- Require
- Blocks
- Rendering HTML
- Generating random IDs or strings
- Views
- Policies
- Start local Rails server
- Miscellaneous
- Web fonts location
- Working with the Database
- Routing
- References
The Rails Console
The console command lets you interact with your Rails application from the command line.
# launch a console (short version)
rails c
# long version
bundle exec rails consoleQuickly find where a method is located:
Myobj.method(:methodname).source_location
# Returns a file and line which you can command-click
=> ["/local/path/to/mymodelname/model.rb", 99]See an object’s methods:
Myobj.methods
# Search for a method using a search string
# this returns all of the object methods containing string “/pay/“
Myobj.methods.grep(/pay/)Rspec
Run it like so:
bin/rspec spec/path/to/foo_spec.rb
# Run a particular line/method
bin/rspec spec/path/to/foo_spec.rb:195If adding data variables to use in tests, declare them in a let block so as to keep them isolated and avoid them leaking elsewhere.
let(:example_data_obj) {
  {
    foo: "bar",
    baz: "bat",
    …
  }
}Note: if you need multiple data variables so as to handle different scenarios, it’s generally more readable to define the data being tested right next to the test.
Debugging
I’ll cover debugging related to more specific file types later but here’s a simple tip. You can check the value of a variable or expression at a given line in a method by:
- add byebugon a line of its own at the relevant place in your file, then save file
- switch to the browser and reload your page
- in the terminal tab that’s running the Rails server (which should now be stopped at the debugging breakpoint), at the bottom type the variable name of interest. You won’t see any text but just trust that your typing is taking effect. Press return
- you’ll now see the value of that variable as it is at the debugging breakpoint
- When you’re done, remove your byebug. You may need to type continue (orcfor short) followed by return at the command prompt to get the server back on track.
Helpers
Helper methods are to there to support your views. They’re for extracting into methods little code routines or logic that don’t belong in a controller and are too complex or reusable to be coded literally into your view. They’re reusable across views because they become available to all your views automatically.
Don’t copy and reuse method names from other helpers. You’ll get conflicts because Helpers are leaky. Instead, start your helper methods with an appropriate namespace.
Unlike object methods (e.g. myobj.do_something) helper methods (e.g. render_something) are not available for us to use in the Rails console.
Helper specs
Basic format:
# frozen_string_literal: true
require "rails_helper"
RSpec.describe Foos::BarHelper do
  let(:foo) { FactoryBot.create(:foo) }
  describe "#foo_bars_sortable_link" do
    context "when bat is not true" do
      it "does a particular thing" do
        expect(helper.foo_bars_sortable_link(foo, bat: "false")).to have_link(
          # …
        )
      end
    end
    context "when bat is true" do
      it "does something else" do
        expect(helper.foo_bars_sortable_link(foo, bat: "true")).to have_link(
          # …a different link from previous test
        )
      end
    end
  end
endNotes:
- start with describe: it’s a good top-level.
- describe a helper method using hash (describe "#project_link" do)
- Helper methods should not directly access controller instance variables because it makes them brittle, less reusable and less maintainable. If you find you’re doing that you might see it as an opportunity to refactor your helper method.
Debugging Helper methods
If you want to debug a helper method by running it and stepping through it at the command line you should lean on a test to get into the method’s context.
# in foo_helper.rb, insert above line of interest
binding.pry # or byebug
# at command line, run helper’s spec (at relevant line/assertion)
bin/rspec spec/path/to/foo_helper_spec.rb:195
# the “debugger” drops you in at the line where you added your breakpoint
# and shows the body of the function being run by the line of the spec we requested.
From: /path/to/app/helpers/foo_helper.rb:26 FooHelper#render_foo:
# you’re now debugging in the context of the running helper method…
# with the arguments passed in by the test available to manipulate.
# this means you can run constituent parts of the method at the debugger prompt…
# for example…
# run this to get back the HTML being rendered.
render_user_profile(user)blank? versus empty?
If you want to test whether something is “empty” you might use empty? if you’re testing a string, however it’s not appropriate for testing object properties (such as person.nickname) because objects can be nil and the nil object has no empty? method. (Run nil.empty? at the console for proof.) Instead use blank? e.g. person.nickname.blank?.
frozen_string_literal: true
I’ll often see this at the top of files, for example Ruby classes. This is just a good practice. It makes things more efficient and thereby improves performance.
frozen_string_literal: trueClass-level methods
They’re called class-level methods because they are methods which are never called by the instance, i.e. never called outside of the class. They are also known as macros.
Examples include attr_reader and ViewComponent’s renders_one.
Constants
Here’s an example where we define a new constant and assign an array to it.
ALLOWED_SIZES = [nil, :medium, :large]Interestingly while the constant cannot be redefined later—i.e. it could not later be set to something other than an array—elements can still be added or removed. We don’t want that here. The following would be better because it locks things down which is likely what we want.
ALLOWED_SIZES = [nil, :medium, :large].freezeSymbols
They’re not variables. They’re more like strings than variables however Strings are used to work with data whereas Symbols are identifiers.
You should use symbols as names or labels for things (for example methods). They are often used to represent method & instance variable names:
# here, :title is a symbol representing the @title instance variable
attr_reader :title
# refer to the render_foo method using a symbol
Myobj.method(:render_foo).source_location
# you can also use symbols as hash keys
hash = {a: 1, b: 2, c: 3}From what I can gather, colons identify something as a Symbol and the colon is at the beginning when its a method name or instance variable but at the end when its a hash key.
Hashes
A Hash is a dictionary-like collection of unique keys and their values. They’re also called associative arrays. They’re similar to Arrays, but where an Array uses integers as its index, a Hash allows you to use any object type.
Example:
hash =
The fetch method for Hash
Use the fetch method as a neat one-liner to get the value of a Hash key or return something (such as false) if it doesn’t exist in the hash.
@options.fetch(:flush, false)ViewComponents
ViewComponents (specifically the my_component.rb file) are just controllers which do not access the database.
They use constructors like the following:
def initialize(size: nil, full_height: false, data: nil)
  super
  @size = allowed_value?(ALLOWED_CARD_SIZES, size)
  @full_height = full_height
  @data = data
end(Note that you would never include a constructor in a Rails controller or model.)
ViewComponents in the Rails console
view = ActionView::Base.new
view.render(CardComponent.new)Instance variables
def initialize(foo: nil)
  super
  @foo = foo
endIn the above example @foo is an instance variable. These are available to an instance of the controller and private to the component. (This includes ViewComponents, which are also controllers.)
In a view, you can refer to it using @foo.
In a subsequent method within the controller, refer to it simply as foo. There’s no preceding colon (it’s not a symbol; in a conditional a symbol would always evaluate to true) and no preceding @.
def classes
  classes = ["myThing"]
  classes << "myThing-foo" if foo
  classes
endMaking instance variables publicly available
The following code makes some instance variables of a ViewComponent publicly available.
attr_reader :size, :full_height, :dataUsing attr_reader like this automatically generate a “getter” for a given instance variable so that you can refer to that instead of the instance variable inside your class methods. My understanding is that doing so is better than accessing the instance variable direct because, among other benefits, it provides better error messages. More about using attr_reader.
The ViewComponent docs also use attr_reader.
Methods
Every method returns a value. You don’t need to explicitly use return, because without it it will be assumed that you’re returning the last thing in the method.
def hello
  "hello world”
endDefine private methods
Add private above the instance methods which are only called from within the class in which they are defined and not from outside. This makes it clear for other developers that they are internal and don’t affect the external interface. This lets them know, for example, that these method names could be changed without breaking things elsewhere.
Also: keep your public interface small.
Naming conventions
The convention I have worked with is that any method that returns a boolean should end with a question mark. This saves having to add prefixes like “is-” to method names. If a method does not return a boolean, its name should not end with a question mark.
Parameters
The standard configuration of method parameters (no colon and no default value) sets them as required arguments that must be passed in order when you call the method. For example:
def write(file, data, mode)
  …
end
write("cats.txt", "cats are cool!", "w")By setting a parameter to have a default value, it becomes an optional argument when calling the method.
def write(file, data, mode = "w")
  …
end
  
write("shopping_list.txt", "bacon")Named Parameters
Configuring your method with named parameters makes the method call read a little more clearly (via the inclusion of the keywords in the call) and increases flexibility because the order of arguments is not important. After every parameter, add a colon. Parameters are mandatory unless configured with a default value.
Here’s an example.
def write(file:, data:, mode: "ascii")
  …
end
  
write(data: 123, file: "test.txt")And here’s how you might do things for a Card ViewComponent.
def initialize(size: nil, full_height: false, data: nil)
  …
end
  
<%= render(CardComponent.new(size: :small, full_height: true)) do %>Check if thing is an array and is non-empty
You can streamline this to:
thing.is_a?(Array) && thing.present?The shovel operator
The shovel operator (<<) lets you add elements to an array. Here’s an example where we build up an HTML class attribute for a BEM-like structure:
def classes
  classes = []
  classes << "card--#{size}" if size
  classes << "card--tall" if full_height
  classes.join(" ")
endDouble splat operator
My understanding is that when you pass **foo as a parameter to a method call then it represents the hash that will be returned from a method def foo elsewhere. The contents of that hash might be different under different circumstances which is why you’d use the double-splat rather than just specifying literal attributes and values. If there are multiple items in the hash, it’ll spread them out as multiple key-value pairs (e.g. as multiple HTML attribute name and attribute value pairs). This is handy when you don’t know which attributes you need to include at the time of rendering a component and want the logic for determining that to reside in the component internals. Here’s an example, based on a ViewComponent for outputting accessible SVG icons:
In the icon_component.html.erb template:
<%= tag.svg(
  class: svg_class, 
  fill: "currentColor", 
  **aria_role
) do %>
  …
<% end %>In IconComponent.rb:
def aria_role
  title ? { role: "img" } : { aria: { hidden: true } }
endThe **aria_role argument resolves to the hash output by the aria_role method, resulting in valid arguments for calling Rails’s tag.svg.
require
require allows you to bring other resources into your current context.
Blocks
The do…end structure in Ruby is called a “block”, and more specifically a multi-line block.
  <%= render CardComponent.new do |c| %>
  Card stuff in here.
  <% end %>Blocks are essentially anonymous functions.
When writing functions where we want a block passed in, we can specify that the block is required. For example:
def do_something(param, &block)Here, the ampersand (&) means that the block is required.
yield
When you have a method with a yield statement, it is usually running the block that has been passed to it.
You can also pass an argument to yield e.g. yield(foo) and that makes foo available to be passed into the block.
See the yield keyword for more information.
Single-line block
Sometimes we don’t need to use a multiline block. We can instead employ a single-line block. This uses curly braces rather than do…end.
For example in a spec we might use:
render_inline(CardComponent.new) { "Content" }
expect(rendered_component).to have_css(".fe-CardV2", text: "Content")The above two lines really just construct a “string” of the component and let you test for the presence of things in it.
Rendering HTML
We have the content_tag helper method for rendering HTML elements. However you are arguably just as well coding the actual HTML rather than bothering with it, especially for the likes of div and span elements.
link_to is a little more useful and makes more sense to use.
Multi-line HTML string
Return a multi-line HTML string like so:
output = "<p>As discussed on the phone, the additional work would involve:</p>
<ol>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ol>
<p>This should get your historic accounts into a good shape.</p>".html_safe
output
Interpolation
Here’s an example where we use interpolation to return a string that has a text label alongside an inline SVG icon, both coming from variables.
"#{link[:text]} #{icon_svg}".html_safe
tag.send()
send() is not just for use on tag. It’s a means of calling a method dynamically i.e. using a variable. I’ve used it so as to have a single line create either a th or a td dymamically dependent on context.
Only use it when you are in control of the arguments. Never use it with user input or something coming from a database.
Random IDs or strings
object_id gives you the internal ruby object id for what you’re working on. I used this in the past to append a unique id to an HTML id attribute value so as to automate an accessibility feature. However don’t use it unintentionally like I did there.
It’s better to use something like rand, or SecureRandom or SecureRandom.hex.
Views
If you have logic you need to use in a view, this would tend to live in a helper method rather than in the controller.
Policies
You might create a method such as allowed_to? for purposes of authorisation.
Start (local) Rails server
Note: the following is shorthand for bin/rails server -b 0.0.0.0.
rails sMiscellaneous
Use Ruby to create a local web server.
# to serve your site at localhost:5000 run this in the project’s document root
ruby -run -e httpd . -p 5000Web fonts: where to put them in the Rails file structure
See https://gist.github.com/anotheruiguy/7379570.
The Database
Reset/wipe the database.
bundle exec rake db:resetRouting
Get routes for model from terminal
Let’s say you’re working on the index page for pet_foods and want to create a sort-by-column anchors where each link’s src points to the current page with some querystring parameters added. You’re first going to need the route for the current page and in the correct format.
To find the existing routes for pet_foods you can run:
rails routes | grep pet_foodsReferences
Loading and Templating JSON Responses in Stimulus.js (by John Beatty)
Just because Stimulus.js is designed to work primarily with existing HTML doesn’t mean it can’t use JSON APIs when the need arises.
Here, John pimps up his Stimulus controller to get and use JSON from a remote API endpoint.
He triggers a fetch() from the connect() lifecycle callback, then iterates the returned JSON creating each HTML list item using a JavaScript template literal before finally rendering them into an existing <ul> via a Stimulus target.
Easy when you know how!
Building an accessible show/hide disclosure component with vanilla JS (Go Make Things)
A disclosure component is the formal name for the pattern where you click a button to reveal or hide content. This includes things like a “show more/show less” interaction for some descriptive text below a YouTube video, or a hamburger menu that reveals and hides when you click it.
Chris’s article provides an accessible means of showing and hiding content at the press of a button when the native HTML details element isn’t suitable.
The new dot com bubble is here: it’s called online advertising (The Correspondent)
Is online advertising working? We simply don’t know
This article reveals that despite $273bn being spent on digital ads globally (figures from 2018) the effectiveness of digital advertising is actually borderline impossible to measure. It is highly likely that any favourable figures suggested by marketers owe more to a combination of the “selection effect” and blind faith.
I don’t particularly enjoy being followed around the web by “targeted ads” – especially having discovered that the intrusion is relatively pointless!
(via @clearleft)
Subgrid for CSS Grid launches in Firefox 71
Subgrid for CSS Grid Layout has arrived in Firefox and it looks great. Here’s how I wrapped my head around the new concepts.
While MDN has some nice examples, I generally find I need a little extra time, trial and error and note-making in order to fully grasp CSS Grid concepts.
For example, I always need to remind myself that parts of the syntax – such as grid-template-columns selectors – refer to grid lines rather than columns.
So I created a Subgrid example pen with guideline notes for future reference. Note: make sure to open the pen in Firefox rather than any other browser, because at the time of writing only Firefox supports Subgrid!
Using CSS Custom Properties to streamline animation
Thanks to a great tip from Lucas Hugdahl on Twitter, here’s how to use CSS custom properties (variables) in your transforms so you don't need to rewrite the whole transform rule in order to transition (animate) a single property.
Let’s take the simple example of a button that we want to increase in size when hovered.
By using a custom property for the scale value, we can keep things DRYer in our :hover rule by only updating that variable rather than rewriting the entire transform rule.
The button HTML:
<button>Hover over me</button>CSS:
button {
  transition: transform .5s ease-in-out;
  transform: translateX(-50%) translateY(-50%) scale(var(--scale, 1));
}
button:hover {
  --scale: 2;
}IndieWeb Link Sharing | Max Böck
A pain point of the IndieWeb is that it's sometimes not as convenient to share content as it is on the common social media platforms… That’s why I wanted to improve this process for my site.
This was a fantastic walkthrough by Max. And based on this, I’ve just finished implementing an easy-bookmarking feature on my own website.
I already use this site to save Bookmarks so I’m hooking into that. For the bookmark-saving form, I’ve used Stimulus rather than Preact. But otherwise this is very much based on Max’s superb tutorial.
Here’s my bookmarklet code so that future-me can create a new browser bookmark, edit it and paste this in.
javascript:(function(){var title = document.getElementsByTagName('title')[0].innerHTML;title = encodeURIComponent(title);var selection = '';if (window.getSelection) {selection = window.getSelection().toString();} else if (document.selection && document.selection.type != 'Control') {selection = document.selection.createRange().text;}selection = encodeURIComponent(selection);new_window=window.open('https://fuzzylogic.me/bookmarker/?title='+title+'&body='+selection+'&url='+encodeURIComponent(document.location.href),'Sharer','resizable,scrollbars,status=0,toolbar=0,menubar=0,titlebar=0,width=680,height=700,location=0');})();Incidentally, this process also provided a great way to dip my toes into the world of Netlify Functions and their supporting tools, netlify-dev and netlify-lambda.
There’s more to be done but I wanted the first bookmark created with my shiny new system to be a link to Max’s original tutorial – and this post is it.
Many thanks, Max!
Who Can Use
It's a tool that brings attention and understanding to how color contrast can affect different people with visual impairments.
What’s interesting about this resource is that sheds light on the many different types of visual impairment, from Protanomaly (trouble distinguishing reds) to Achromatopsia (complete colour blindness; only being able to see shades) and how your website’s colour scheme fares for each. (via paddyduke.com)
FS Split Sans and FS Split Serif (fontsmith.com)
Although FS Split started out as a project to create a fresh, modern new sans, it has developed into a broad type family that can bring so much variety to everything from magazines and packaging to websites and branding. The conflicting yet harmonising nature of sans and serif should give designers the tools they need to be both bold and subtle, eclectic and ordinary, contemporary and classic.