Rails: Accessing strong parameters

Rails wraps your parameters into an interface called StrongParameters. In most cases your form submits you data in a nested structure, which goes hand in hand with strong parameter interface.

Example:

curl -X POST -d "user[name]=bob" https://example.com/users
class UsersController
  def create
    User.create!(params.expect(user: [:name]) # Or User.create!(params.require(:user).permit(:name)
  end
end

Most of the time you are using the `para...

How to write a good image alt text

This decision tree describes how to use the alt attribute of the element in various situations. For some types of images, there are alternative approaches, such as using CSS background images for decorative images or web fonts instead of images of text.

Questions asked:

  • Does the image contain text?
  • Is the image used in a link or a button, and would it be hard or impossible to understand what the link or the button does, if the image wasn’t there?
  • Does the image contribu...

CSS & a11y: When hiding with opacity, also set visibility:hidden (transitions supported)

Elements can be hidden and shown by toggling the display property. However, this is not animatable, so we often turn to opacity. At opacity: 0, the element is hidden, and with a nice transition on that property, it can be faded in and out smoothly.

Yet, opacity only hides visually, not technically: the element is still focusable and visible to screen readers. So, how can we fade an element while maintaining accessibility?

Enter visibility. It also hides elements, bu...

Enumerators in Ruby

Starting with Ruby 1.9, most #each methods can be called without a block, and will return an enumerator. This is what allows you to do things like

['foo', 'bar', 'baz'].each.with_index.collect { |name, index| name * index }
# -> ["", "bar", "bazbaz"]

If you write your own each method, it is useful to follow the same practice, i.e. write a method that

  • calls a given block for all entries
  • returns an enumerator, if no block is given

How to write a canonical each method

To write a m...

ActiveSupport includes Timecop-like helpers

ActiveSupport (since 4.1) includes test helpers to manipulate time, just like the Timecop gem:

  • To travel a relative amount of time, use travel:

    travel 1.day
    
  • To travel to a specific moment in time, use travel_to:

    travel_to 1.hour.from_now
    
  • To freeze the current time, use freeze_time (ActiveSupport 5.2+):

    freeze_time
    

All those methods may also receive a block to call and restore time afterwards. If you don't provide a block, you must call travel_back or `unfreeze...

Heads up: pg_restore --clean keeps existing tables

When restoring a PostgreSQL dump using pg_restore, you usually add the --clean flag to remove any existing data from tables.

Note that this only removes data from tables that are part of the dump and will not remove any extra tables. You need to do that yourself.

Specify Gemfile for bundle

Bundler allows you to specify the name of the Gemfile you want to bundle with the BUNDLE_GEMFILE environment variable.

BUNDLE_GEMFILE=Gemfile.rails.7.2 bundle

By default, bundler will look for a file called Gemfile in your project, but there may be cases where you want to have multiple Gemfiles in your project, which cannot all be named Gemfile. Let's say for example, you maintain a gem and want to run automated tests against multiple rails versions. When you need to bundle one of your secondary Gemfiles, the solution above ...

Rails console tricks

Also see the list of IRB commands.

Switching the context

Changes the "default receiver" of expressions. Can be used to simulate a "debugger situation" where you are "inside" an object. This is especially handy when needing to call private methods – just invoke them, no need to use send.

  • Switch to an object: chws $object
  • Reset to main: chws
  • Show current context: cwws (usually shown in IRB prompt)

[Technical details](https://technology.doximity.com/articles/the-hidden-gems-of-r...

Does <html> or <body> scroll the page?

TL;DR: All modern browsers default to using the <html> element as the main document viewport. In CSS, prefer to set overflow properties to html (or :root).

Scrolling overflowing elements with JavaScript

HTML elements with overflow-y: auto or overflow-y: scroll will get a scrollbar when their content is higher than their own height.

When you scroll an element , the element's scrollTop property is updated with the scrollbar's new position. You can also set `elem...

Cucumber features as documentation

Cucumber allows for prose in features and scenarios. Example:

Feature: Cancel account

  There are several ways to cancel a user account. Admins need to 
  do it in complex cases, but normally, users can do it themselves.
  
  Scenario: User cancels his own account
    
    Users should be able to cancel an account themselves, so the 
    admins do not need to do it.
    
    Given a user account for "willy@astor.de"
    When I sign in as "willy@astor.de"
    And I follow "Cancel account"
    Then I should see "Account canceled"...

An auto-mapper for ARIA labels and BEM classes in Cucumber selectors

Spreewald comes with a selector_for helper that matches an English term like the user's profile into a CSS selector. This is useful for steps that refer to a particular section of the page, like the following:

Then I should see "Bruce" within the user's profile
                                 ^^^^^^^^^^^^^^^^^^

If you're too lazy to manually translate English to a CSS selector by adding a line to features/env/selectors.rb, we already have an [auto-mapper to translate English into ...

Updated: Capybara: Running tests with headless Chrome

Chrome is now kept from opening PDF downloads. It will stay on the current page.

Updated: Capybara: Running tests with headless Chrome

Updated for recent versions of Chrome, which do not have a "remote debugging address" and only listen on localhost.

Disable automatic code suggestions in RubyMine

To disable the mostly useless automatic suggestion popups in RubyMine, go to File / Settings, then to Editor / General / Code Completion and uncheck Auto-display code completion.

You can still open the popup by pressing CTRL + Space. And you probably want to use Context-dependent word expansion instead, anyway.

Why am I getting different results working with SVG files and ImageMagick?

When you are working with SVG files and ImageMagick you can get different results on different machines depending on which additional packages you have installed.

From: http://www.imagemagick.org/script/formats.php

ImageMagick utilizes inkscape if its in your execution path otherwise RSVG. If neither are available, ImageMagick reverts to its internal SVG renderer.

Git: How to stage hunks with a single key press

In interactive commands, Git allows the user to provide one-letter input with a single key without hitting enter (docs).

# Enabled this feature globally
git config --global interactive.singlekey true

# Or enable this feature locally for a single repository
git config interactive.singlekey true

This allows you to hit "y" instead of "y + ENTER" to move to the next hunk.

Stage this hunk [y,n,q,a,d,s,e,?]?

Building web applications: Beyond the happy path

When building a web application, one is tempted to claim it "done" too early. Make sure you check this list.

Different screen sizes and browsers

Desktops, tablets and mobile devices have all different screen resolutions. Does your design work on each of them?

  • Choose which browsers to support. Make sure the page looks OK, is usable and working in these browsers.
  • Use @media queries to build a responsive design
    • If you do not suppo...

How to use html_safe correctly

Back in the war, Rails developers had to manually HTML-escape user-supplied text before it was rendered in a view. If only a single piece of user-supplied text was rendered without prior escaping, it enabled XSS attacks like injecting a <script> tag into the view of another user.

Because this practice was so error-prone, the rails_xss plugin was developed and later integrated into Rails 3. rails_xss follows a different approach: Instead of relying...

Rails I18n fallback locales

When you need to create a locale for a language variant (like Austrian for German), you probably don't want to duplicate your entire de.yml file only to change a few minor exceptions for our Austrian friends.

Luckily, the I18n gem used by Rails has a fallback feature where you can make one locale file fall back to another if no translation is available.

In the example above you would have a config/locales/de_DE.yml:

de_DE:
  # hundreds of translations here

... and another...

Unpoly: Showing the better_errors page when Rails raises an error

When an AJAX request raises an exception on the server, Rails will show a minimal error page with only basic information. Because all Unpoly updates work using AJAX requests, you won't get the more detailled better_errors page with the interactive REPL.

Below is an event listener that automatically repeats the request as a full-page load if your development error shows an error page. This means you get...

Sidekiq: Problems and Troubleshooting

When using Sidekiq in your application, you must write thread-safe code.

This wiki page also lists gems that are known to be unsafe on threaded applications.
When adding a gem that will also be used by a Sidekiq worker, make sure to confirm it's thread-safe.

Caution when using the || operator to set defaults

I often see the use of || to set a default value for a variable that might be nil, null or undefined.

x = x || 'default-value'

This pattern should be avoided in all languages.

While using || works as intended when x is null or an actual object, it also sets the default value for other falsy values, such as false. false is a non-blank value that you never want to override with a default.

To make it worse, languages like JavaScript or Perl have [many more fal...

Caching in Rails < 6.1 may down parts of your application when using public cache control

TL;DR When using Cache-Control on a Rails application, make sure the Vary: Accept header is set.

Proxy caching is a good feature to serve your publicly visible application content faster and reduce load on your servers. It is e.g. available in nginx, but also affects proxies delivered by ISPs.

Unfortunately, there is a little problem in Rails < 6.1 when delivering responses for different MIME-types. Say you have an arbitrary route in your Rails application that is able to respond with regular HTML and JSON. By sending the specific ...

Reverse lookup a fixture name by its id and table name

To reverse lookup a fixture by its table name and id, use the following approach on ActiveRecord::FixtureSet:

table = 'users'       # Specify the fixture table name
id = 123122           # Specify the ID to look for

# Find the fixture that matches the given ID
ActiveRecord::FixtureSet.all_loaded_fixtures[table].fixtures.find { |key, value| value['id'] == id }

Result Example:

[
  "one", # Fixture name
  #<ActiveRecord::Fixture:0x00007e79990234c8>, # ActiveRecord::Fixture object
  @fixture= { ... }, # The raw fixtu...