When defining a trait using the Modularity gem, you must take extra steps to define constants to avoid caveats (like when defining subclasses through traits).
tl;dr
In traits, always define constants with explicit
self
.
If your trait defines a constant inside the as_trait
block, it will be bound to the trait module, not the class including the trait.
While this may seem unproblematic at first glance, it becomes a problem when including trai...
Event delegation is a pattern where a container element has a single event listener that handles events for all descendants that match a CSS selector.
This pattern was popularized by jQuery that lets you do this:
$('.container').on('click', '.message', function(event) {
console.log("A message element was clicked!")
})
This technique has some advantages:
Our gem spreewald supports a few helpers for development. In case you notice errors in your Cucumber tests, you might want to use one of them to better understand the underlying background of the failure. The following content is also part of the spreewald's README, but is duplicated to this card to allow repeating.
Pauses test execution and opens an IRB shell with current cont...
In my career, I have consumed hundreds of REST APIs and produced dozens. Since I often see the same mistakes repeated in API design, I thought it might be nice to write down a set of best practices. And poke fun at a couple widely-used APIs.
Much of this may be "duh", but there might be a few rules you haven't considered yet.
When you find similar groups of expect
calls in your tests, you can improve readability by extracting the group into its own matcher. RSpec makes this easy by allowing matchers to call other matchers.
The following test checks that two variables foo
and bar
(1) have no lowercase characters and (2) end with an exclamation mark:
expect(foo).to_not match(/[a-z]/)
expect(foo).to end_with('!')
expect(bar).to_not match(/[a-z]/)
expect(bar).to end_with('!')
We can extract the repeated matcher chains into a custom m...
The sprintf
method has a reference by name format option:
sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 }) # => 1 : 2.000000
sprintf("%{foo}f", { :foo => 1 }) # => "1f"
The format identifier %<id>
stands for different data types to be formatted, such as %f
for floats:
sprintf('%f', 1) # => 1.000000
This is quite useful to replace ...
simple_format
ignores Rails' XSS protection. Even when called with an unsafe string, HTML characters will not be escaped or stripped!
Instead simple_format
calls sanitize
on each of the generated paragraphs.
ActionView::Base.sanitized_allowed_tags
# => #<Set: {"small", "dfn", "sup", "sub", "pre", "blockquote", "ins", "ul", "var", "samp", "del", "h6", "h5", "h4", "h3", "h2", "h1", "span", "br", "hr", "em", "address", "img", "kbd", "tt", "a", "acrony...
If you have any class which requires access to some path methods generated by your routes. Even though you could technically include Rails.application.routes.url_helpers
, this may include way too many methods and even overwrite some class methods in the worst case.
Instead, most of the time the following is advised to only make the desired methods available:
class Project
delegate :url_helpers, to: 'Rails.application.routes'
def project_path
url_helpers.project_path(self)
end
end
Ruby has the class Rational which allows you to store exact fractions. Any calculation on these variables will now use fractional calculations internally, until you convert the result to another data type or do a calculation which requires an implicit conversion.
Lets say you want to store the conversion factor from MJ
to kWh
in a variable, which is 1/3.6
. Using BigDecimals for this seems like a good idea, it usually helps with rounding errors over a float, but the...
Even when you app has no CSS at all, you still inherit a default user agent stylesheet from your browser.
These default styles vary from browser to browser:
Links found in A look at CSS Resets in 2018.
Every modern Rails app should have a Content Security Policy enabled.
The following "default" is a minimal policy that should
In your config/initializers/content_security_policy.rb
, set
Rails.application.config.content_security_policy do |policy|
policy.object_src :none
policy.script_src :unsafe_eval, :strict_dynamic, :https # Browsers with support for "'strict-dynamic'" will ignore "https:"
po...
There are two distinct ways of commenting Haml markup: HTML and Ruby.
This will create an HTML comment that will be sent to the client (aka browser):
/= link_to 'Example', 'www.example.com'
This produces the following HTML:
<!-- = link_to 'Example', 'www.example.com' -->
Only use this variant if you need the comment to appear in the HTML.
This will comment code so it will not be sent to the client:
-# = link_to 'foo'
99% of the time you'll be adding notes f...
(Rails has a method ActiveRecord::Relation#merge
that can merge ActiveRecord scopes. However, its behavior has never been clear, and in Rails 7 it still discards conditions on the same column by the last condition. We discourage using #merge
!)
The best way to merge ActiveRecord scopes is using a subquery:
scope_a.where(id: scope_b)
It is a little less concise than #merge
, but unambiguous.
Assume a model where a deal has many documents:
class Deal < ApplicationRecord
has_many :...
A check if two date or time ranges A and B overlap needs to cover a lot of cases:
This means you actually have to check that:
A.start > B.end
)B.start > A.end
)Flipping this, A and B overlap iff A.start <= B.end && B.start <= A.end
The code below shows how to implement this in Ruby on Rails. The example is a class `Interv...
All direct child directories of app
are automatically added to the eager- and autoload paths. They do NOT create a module for namespacing. This is intuitive, since there normally is no module Model
, or module Controller
. If you want to add a new base directory, there's no additional config needed.
app
├── controllers
├── helpers
├── inputs # No config needed
├── mailers
├── models
├── uploaders # No config needed
├── util # No config needed
└── workers # No config needed
Sometimes it's handy to group files wit...
While upgrading CarrierWave from version 0.11.x to 3.x, we encountered some very nasty fails. Below are the basic changes you need to perform and some behavior you may eventually run into when upgrading your application. This aims to save you some time understanding what happens under the hood to possibly discover problems faster as digging deeply into CarrierWave code is very fun...
The following focuses on extension allowlisting, but it is the exact same thing for content type allowlisting with the `content_ty...
The old Chrome downloads bar had several advantages over the new subtle downloads dropdown:
They say the flag might be removed in the future, but for now it gets the downloads bar back.
To attach files to your records, you will need a new database column representing the filename of the file. To do this, add a new migration (rails g migration <name>
) with the following content:
class AddAttachmentToNotes < ActiveRecord::Migration[6.0]
def change
add_column :notes, :attachment, :string
end
end
Don't forget to rename the class and change the column details to fit your purpose. Run it.
The first way is to store your Carrierwave attachments not ...
Reminder of what you can do with Geordi.
Note: If you alias Geordi to something short like g
, running commands gets much faster!
Note: You only need to type the first letters of a command to run it, e.g. geordi dep
will run the deploy
command.
Guided deployment, including push, merge, switch branches. Does nothing without confirmation.
Run something for all Capistrano environments, e.g. geordi cap deploy
When you just clon...
For matching whitespaces in a regular expression, the most common and best-known shorthand expression is probably \s
.
It matches the following whitespace characters:
However, in some cases these may not be good enough for your purpose.
Sometimes a text may contain two words separated by a space, but the author wanted to ensure that those words are written in the same lin...
On the Rails console, assigning an object to a variable can lead to this strange error (without stacktrace):
irb > recipient = Recipient.find(123)
Traceback (most recent call last):
TypeError (nil can't be coerced into Integer)
irb > recipient
#<Recipient ...
The error is only in the output – the assignment is working. It only occurs when using the --nomultiline
option, and thus [only with IRB 1.2.0+ and before Ruby 3](https://github.com/makandra/geordi/blob...
TLDR
Using
.includes
or.eager_load
with 1-n associations is dangerous. Always use.preload
instead.
Consider the following ActiveRecord query:
BlogPost.eager_load(
:comments
:attachments,
).to_a
(Let's assume we only have a couple of blog posts; if you use pagination the queries will be more complicated, but the point still stands.
Looks harmless enough? It is not.
ActiveRecord will rewrite this into a query using LEFT JOIN
s which looks something like this:
SELECT "blog_posts...
In the discussion of the difference between include
and extend
in Ruby, there is a misconception that extend
would add methods to the singleton class of a ruby object as stated in many posts on this topic. But in fact, it is added to the ancestors chain of the singleton class! Even though it is technically not the same, practically this can be considered the same in most use cases.
This means, that we are able to overwrite these methods or call the parent version with super
depending in which order and in whi...
Most of our applications use CarrierWave for file uploads. CarrierWave has an integrated processing mechanism for different file versions with support for ImageMagick through CarrierWave::MiniMagick
(which requires the mini_magick
gem). In case your processing runs into an error, CarrierWave will just swallow it and rethrow an error with a very generic message like Processing failed. Maybe it is not an image?
which does not help you finding out what the actual problem is. CarrierWave probably does this for security purposes, but does n...