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...