ActiveRecord: Named bindings in conditions
In Active Record you can use named bindings in where-conditions. This helps you to make your code more readable and reduces repetitions in the binding list.
Example without named bindings
User.where(
  'name = ? OR email = ?',
  params[:query],
  params[:query]
)
Example with named bindings
User.where(
  'name = :query OR email = :query',
  query: params[:query]
)
Capybara will not find links without an href attribute
Capybara and most assistive technology  will fail to find <a> tags that are missing an href attribute. This will probably happen to you every now and then on JavaScript-heavy applications.
An example would be an AngularJS application where the following HTML actually works. [1]
<a ng-click="hello()">Hello</a>
Capybara will fail to find that link, even though looking it up via the DOM shows it:
>> find_link("Hello")
Capybara::...
Don't define a controller action called #process
Remember that your controller actions share the same method space with private methods defined in ActionController::Base. If your controller behaves in super-weird ways, check that you don't overwrite some internal method with a controller action.
Examples for internal methods:
- #process
- #process_action
- #cookies
- #params
- #request
- #response
Debugging
If you accidentally did overwrite some internal method, you may come across an  ArgumentError with the message `wrong number of arguments (given 1, expe...
Improve accessibility with [aria-required] in SimpleForm
SimpleForm comes with an option browser_validations which could be used to give fields that have a presence validation the HTML required attribute. We usually turn it off due to difficulties controlling its behavior and appearance. Instead we only mark required fields with an asterisk (*) next to its label. Blind users probably only discover the validation issue after submitting the form due to the now displayed error messages.
A compromise with better acce...
RSpec: Marking sections in long examples
RSpec examples can get quite long, especially in feature specs. This makes them hard to read & understand. Also, when executing them, it may take seconds to see any progress.
To improve this, I have successfully been using a little "step" helper in my tests. It marks semantic sections, structuring an example while improving documentation. When the test runs, each step prints its message (or a dot, depending on your formatter).
# spec/support/step_helper.rb
module StepHelper
  # Use this helper to label groups of related actions in l...
How to silence Puma for your feature tests
When RSpecs runs the first feature spec, you may see log output like this:
Capybara starting Puma...
* Version 6.5.0, codename: Sky's Version
* Min threads: 0, max threads: 4
* Listening on http://127.0.0.1:39949
You can disable this behavior by tweaking Capybara's Puma server in your spec/support/capybara.rb:
Capybara.server = :puma, { Silent: true }
Note
You don't need to configure this if you're using system tests with modern versions of Rails. They do [exactly the same](https://github.com/rails/rails/blob/ma...
How to use Ubuntu in English, but still show German formats
If you want to have an English Ubuntu UI, but still see dates, money amounts, paper formats, etc. in German formats, you can fine-tune your /etc/default/locale like this:
LANG="en_US.UTF-8"
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
LC_COLLATE="de_DE.UTF-8"
LC_MONETARY="de_DE.UTF-8"
LC_PAPER="de_DE.UTF-8"
LC_NAME="de_DE.UTF-8"
LC_ADDRESS="de_DE.UTF-8"
LC_TELEPHONE="de_DE.UTF-8"
LC_MEASUREMENT="de_DE.UTF-8"
LC_IDENTIFICATION="de_DE.UTF-8"
Make sure you have both en...
Git: rebase dependent feature branch after squash
This card will show you how to use git rebase --onto without confusion.
Use case:
You've got two feature branches (one and two), where two depends on one. Now commits of branch one have changed after you branched two from it (i.e. after code review the commits of branch one are squashed). Thus the commit history of branch one has changed. Branch two's history however didn't change.
Solution:
To make the branches share the same commit history again you will have to rebase and replay (attach) the a...
RSpec: Defining helper methods for an example group
You can define methods in any example group using Ruby's def keyword or define_method method:
describe "example" do
  def sum(a, b)
    a + b
  end
  it "has access to methods defined in its group" do
    expect(sum(3, 4)).to be(7)
  end
end
The helper method is also available to groups nested within that group. The helper method is not available to parent or sibling groups.
Global helpers
To define helpers for all specs (or all specs of a type), [define it in a module](https://rspec.info/features/3-12/rspec-core/help...
How to define a table name prefix for all Rails models in a given namespace
ActiveRecord computes table names of model classes, and results are usually just like you'd expect.
Adding a prefix for all classes in a namespace can feel a odd or broken, but does not have to be. It's actually very easy when done right.
Summary (tl;dr)
Here's the short version: Define a table_name_prefix method in the namespace module, and do not define any table_name_prefix in ActiveRecord classes inside of it. If this sounds familiar, we have [a card about using it already](https://makandracards.com/makandra/47198-rails-namespac...
How to find out what is running on a port on a remote machine
By convention, common protocols use a defined port, like 80 for HTTP or 443 for HTTPS.
You can use nmap to find out what service is running behind a given port, and most often see some details about it. This can be helpful if servers don't offer the services you expect for some ports. If you'd like to see what ports are listing on your local machine, you might want to use ss instead of nmap.
Note that nmap's service discovery may trigger several requests.
Example
When using nmap, adding the -A switch will ...
RSpec Argument Matchers: Expecting non-primitive objects as method invocation arguments
Expecting a primitive value as an argument to a method invocation is easy:
expect(object).to receive(:foo).with('arg1', 'arg2')
This expectation would be met with this call:
object.foo('arg1', 'arg2')
But what if the argument is expected to be an object with a given set of methods? E.g. this class with #first_name and #last_name methods:
class Person
  def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
  end
  
  attr_reader :first_name, :last_name
  
end
``...
Managing chrome versions for selenium
Currently we often use geordi to run cucumber and rspec tests. Geordi takes care of installing a matching chromedriver for the installed google-chrome binary. The google-chrome binary is managed by apt.
Another approach is to use the Selenium Manager for installing and using the correct browser versions for you. Here is the setup you need for your integration tests:
Capybara.register_driver :chrome do |app|
  options = Sele...
Webpack(er): Analyze the size of your JavaScript components
We're always striving towards keeping our website's JavaScript as small as possible.
If you're using webpack(er), you can use the webpack-bundle-analyzer plugin to get a good overview, which of your JavaScript modules take up how much space, and where you can optimize.
To use it, add it via npm or yarn
yarn add webpack-bundle-analyzer
Then add this to your environment.js:
// Uncomment this code to show statistics of bundle sizes. Generated file will automatically...
Custom error pages in Rails
Static error pages
To add a few basic styles to the default error pages in Rails, just edit the default templates in public, e.g. public/404.html.
A limitation to these default templates is that they're just static files. You cannot use Haml, Rails helpers or your application layout here. If you need Rails to render your error pages, you need the approach below.
Dynamic error pages
- Register your own app as the applicatio...
Don't forget: Automatically remove join records on has_many :through associations
Bad
# Given the following models
class Image < ActiveRecord::Base
  has_many :album_images
  has_many :albums, through: :album_images
end
class Album < ActiveRecord::Base
  has_many :album_images
  has_many :images, through: :album_images
end
# Join model
class AlbumImage < ActiveRecord::Base
  belongs_to :album
  belongs_to :image
end
Destroying a record in this setup will only remove the record itself, and leave orphaned join records behind.
image = Image.last
image.destroy # removes only the `image` record,
   ...
Rails: Handling actions that need to happen after all transactions
In Rails 7.2. the feature ActiveRecord.after_all_transactions_commit was added, for code that may run either inside or outside a transaction (we have a special card for nested transactions in general) and needs to perform work after the state changes have been properly persisted. e.g. sending an email.
Example
def publish_article(article)
  article.update(published: true)
  ActiveRecord.after_all_transactions_commit do
    PublishNotification...
Rails: Testing exceptions with the rescue_responses setting
In Rails 7.2 the new default for config.action_dispatch.show_exceptions is rescuable.
- 
:rescuable: It will show a Rails error page in the response only for rescuable exceptions as
 defined byActionDispatch::ExceptionWrapper.rescue_responses. In the
 event of an unexpected internal server error, the exception that caused
 the error will still be raised within the test so as to provide a useful
 stack trace and a good debugging experience.
- 
:all: It wi...
RSpec: Defining negated matchers
You can use RSpec::Matchers.define_negated_matcher to define a negated version of an existing matcher. This is particularly useful in composed matcher expressions or to create more expressive and meaningful matchers.
You should only negate "atomic" matchers with an unambiguous inversion. For example, have_radio_button(label) can be negated, whereas have_active_radio_button(label) should not be. Its inversion could either mean "there is a radio button with that label, but it is not active", or "there is no radio button with that la...
A modern approach to SVG icons
You have some SVG files you want to use as icons on your website. How would you embed them?
Common options are:
- Use them with an image: <img src='path-to-icon.svg'>
- Embed them inline with <svg>$ICON</svg>
- Embed them using CSS and background-image: url(path-to-icon.svg)or evenbackground-image: url(data:$ICON).
- Build your own icon font.
All of these have drawbacks:
- Image and background-imagedo not allow to recolor the image using CSS.
- Inline-<svg>are unnecessary work for the server and are...
Regex: Be careful when trying to match the start and/or end of a text
Ruby has two different ways to match the start and the end of a text:
- 
^(Start of line) and$(End of line)
- 
\A(Start of string) and\z(End of string)
Most often you want to use \A and \z.
Here is a short example in which we want to validate the content type of a file attachment. Normally we would not expect content_type_1 to be a valid content type with the used regular expression image\/(jpeg|png). But as ^ and $ will match lines, it matches both content_type_1 and content_type_2. Using \A and \z will wo...
Statistics and Reports on Web Performance Optimization
Case studies and experiments demonstrating the impact of web performance optimization (WPO) on user experience and business metrics.
How to use Parallel to speed up building the same html partial multiple times (for different data)
The parallel-gem is quite easy to use and can speed up rendering time if you want to render the same partial multiple times (e.g. for rendering long lists of things).
Parallel supports execution using forked processes (the default), threads (mind the GVL) and Ractors (some limitations for data sharing).
If your parallelized code talks to the database, you should [ensure not to leak database connections](https://makandracards.com/makandra/45360-using-activerecord-with-threads-will-leak-database-connect...
Choosing the right gems for your project
Adding a gem means you take over the liability towards the external code.
Checklist
Based on "To gem, or not to gem":
- Gem is really needed (prefer writing your own code for simple requirements without many edge cases)
- Gem is tested well (coverage and quality)
- Gem has a good code quality
- Gem's licence fits to the project requirement
- Try to avoid gems that do much more than your requireme...