Calling a helper method with the same name as your current partial
Partials always define a local variable with the same name as themselves. E.g. when you are in _recent_users.html.erb
, a local variable recent_users
will be defined and overshadow any helper method that is also called recent_users()
.
If you would like to use a helper method recent_users()
in a partial _recent_users.html.erb
you can say this in the partial template:
<% recent_users = self.recent_users() %>
<% recent_users.each do |user| %>
...
<% end %>
Your database tables should always have timestamps
Whenever you create a table from a database migration, remember to add updated_at
and created_at
timestamps to that table. Without those timestamps, investigating future bug reports will be hell. Always have timestamps.
Adding timestamps to new tables
When you create a table using create_table
, you can add timestamps by using the timestamps
shortcut:
class CreateEpisode < ActiveRecord::Migration
def change
create_table :episodes do |t|
t.string :name
t.timestam...
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...
CSS: The inset CSS shorthand
The inset CSS property is a shorthand that corresponds to the top, right, bottom, and/or left properties. It has the same multi-value syntax of the margin shorthand.
Example
<div class="outer">
<div class="inner">
Some text
</div>
</div>
.outer {
background-color: cyan;
position: relative;
width: 500px;
height: 500px;
}
Top, right, bottom and left
https://jsfiddle.net/jqx68wem/
.inner {
background-color: darkCyan;
position: absolute;
top: 10px;
right: 10px;
bottom: 10p...
Fix: esbuild assets are missing after capistrano deploy
Issue: You have an app using jsbundling-rails and esbuild. After deploy, the assets built by esbuild are missing in public/assets.
Solution: Add app/builds
to your git repo (by adding a app/builds/.keep
file).
Something in sprockets is caching paths and refuses to accept files in "unknown" locations.
Fix PNG colors in IE, old Safaris and new Firefoxes
Some browsers render PNG images with color profiles and other shenanigans, some don't.
The cleanest way to have consistent colors across browsers is to convert all your images to a standard color profile, strip the image's original profile and attach the standard profile.
If you can't be bothered to convert color profiles, a quicker (but less effective) method is to remove some PNG chunks from your files.
With Geordi
[Geordi](https://git...
Writing strings as Carrierwave uploads
When you have string contents (e.g. a generated binary stream, or data from a remote source) that you want to store as a file using Carrierwave, here is a simple solution.
While you could write your string to a file and pass that file to Carrierwave, why even bother? You already have your string (or stream).
However, a plain StringIO object will not work for Carrierwave's ActiveRecord integration:
>> Attachment.create!(file: StringIO.new(contents))
TypeError: no implicit conversion of nil into String
This is because Carrierwav...
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 lo...
PostgreSQL: How to show database size
SELECT pg_size_pretty(pg_database_size('some-database'));
Example
SELECT pg_size_pretty(pg_database_size('cards_p'));
----------------
13 GB
(1 row)
SELECT pg_database_size('cards_p');
pg_database_size
------------------
13524832927
(1 row)
Related
The Easiest Way to Parse URLs with JavaScript
A very clever hack to parse a structured URL object is to create a <a>
element and set its href
to the URL you want to parse.
You can then query the <a>
element for its components like schema, hostname, port, pathname, query, hash:
var parser = document.createElement('a');
parser.href = 'http://heise.de/bar';
parser.hostname; // => 'heise.de'
pathname = parser.pathname; // => '/bar'
if (pathname[0] != '/')
pathname = '/' + pathname // Fix IE11
One advantag...
Icon font vertical alignment in Windows
I had an issue with icons from an icon font aligning differently on Linux, iOS and Windows (seemingly browser-independent). With vertical-align:middle
, they aligned properly on Linux, iOS and macOS, whereas with a vertical-align
of -18%
, it looked good on Windows and iOS, but not Linux.
Further investigation showed that not only icons, but also normal capital letters aligned differently. No setting of vertical-align
could fix this, neither top
, bottom
, middle
, nor additional paddings or margins. It seems like browsers take the...
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.
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...
Hiding the clear input button of Edge (with EdgeHTML engine)
Edge (and some versions of Internet Explorer, like IE11) use to render a × clear input button on text fields. While this is intended as a nicety for users, it comes in annoying when you've built and styled your own clear input button.
Hide the Edge × with this pseudo selector:
input::-ms-clear
display: none
Differences between transactions and locking
Web applications can be used by multiple users at the same time. A typical application server like Passenger has multiple worker processes for a single app. In a distributed deployment setup like we use at makandra you will even have multiple application servers, each with their own worker pool.
This means that your code needs to deal with concurrent data access. The two main tools we use to cope with concurrency are database transactions and distributed locks. These two are not interchangeable. You ca...
Preload associations in loaded records
Sometimes you want to fetch associations for an ActiveRecord that you already loaded, e.g. when it has deeply nested associations.
Edge Rider gives your models a static method preload_associations
. The method can be used to preload associations for loaded objects like this:
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
@user.preload_associations(threads: { posts: :author }, messages: :sender)
end
end
The attached initializers re...
Double loading issue with Ruby default gems
Ruby includes many standard gems that are bundled into the Ruby installation. Here is an example for the gem strscan
that will be displayed as default
:
gem list strscan
*** LOCAL GEMS ***
strscan (default: 3.0.1)
It is still possible to have newer version of a gem installed beside the default version:
gem install strscan
Fetching strscan-3.0.3.gem
Building native extensions. This could take a while...
Successfully installed strscan-3.0.3
1 gem installed
gem list strscan
*** LOC...
How to debug issues with zeitwerk and Rails
In case you have trouble with the zeitwerk autoloader, you can check out the documentation Autoloading and Reloading Constants and Classic to Zeitwerk HOWTO for some debugging hints.
For myself it was useful to print the registered constants and the file references during the boot. Therefore you need to add Rails.autoloaders.log!
at the end of your config/application.rb
file. You could also run `bin...
Waiting for page loads and AJAX requests to finish with Capybara
If you're using the Capybara webdriver, steps sometimes fail because the browser hasn't finished loading the next page yet, or it still has a pending AJAX request. You'll often see workarounds like
When I wait for the page to load
Then ...
Workarounds like this do not work reliably, will result in flickering tests and should be avoided. There is no known reliable way to detect if the browser has finished loading the page.
Solution
Instead you should wait until you can observe the result of a page load. E.g. if y...
Google Analytics: Change the tracked URL path
By default, Google Analytics tracks the current URL for every request. Sometimes you will want to track another URL instead, for example:
- When an application URL contains a secret (e.g. an access token)
- When you want to track multiple URLs under the same bucket
- When you want to track interactions that don't have a corresponding URL + request (e.g. a Javascript button or a PDF download)
Luckily the Analytics code snippet allows you to freely choose what path is being tracked. Simple change this:
ga('send', 'pageview');
......
ActiveType 1.2 supports "change_association"
With ActiveType 1.2 you can modify associations (has_many
etc.) after they have been defined.
One common use case for this is to change an association inside a form model, like this:
class Credential < ActiveRecord::Base
end
class User < ActiveRecord::Base
has_many :credentials
end
class SignUpCredential < ActiveType::Record[Credential]
end
class SignUp < ActiveType::Record[User]
change_association :credentials, class_name: 'SignUpCredential'
end
Now, if you load `credentials...
CSS: Don't target multiple vendor-prefixed pseudo-elements in a single rule
Some pseudo-elements need to be addressed with vendor prefixes. E.g. ::selection
is not supported by Firefox, you need to use ::-moz-selection
instead.
What you cannot do is to define a single CSS rule to address both the standard and vendor-prefixed form:
::selection, ::-moz-selection {
background-color: red;
}
This rule will be ignored by all browsers. The reason is that if a browser doe...
Rails: namespacing models with table_name_prefix instead of table_name
When you want to group rails models of a logical context, namespaces are your friend. However, if you have a lot of classes in the same namespace it might be tedious to specify the table name for each class seperately:
class Accounting::Invoice < ApplicationRecord
self.table_name = 'accounting_invoices'
...
end
class Accounting::Payment < ApplicationRecord
self.table_name = 'accounting_payments'
...
end
A replacement for the self.table_name
-assignment is the table_name_prefix
in the module definition:
modu...
Project maintenance: four levels of code quality
Code quality can be measured in four levels:
- (Working code)
- Reliable code (minimum)
- Readable code (ok for short-lived code)
- Changeable code (standard level)
The code quality of a project directly impacts its maintainability.
Generally you should aim for level 3. If the code will stay for less than a few months, it may stay at level 2. Never go below level 1.
0. Working code
You have implemented that feature and it works. Congrats! You have reached level zero, which means three levels of code quality lie ahead.
First, m...