Databases don't order rows unless you tell them so
There is no such thing as a "default order" of rows in database tables.
For instance, when you paginate a result set: When using LIMIT
, it is important to use an ORDER BY
clause that constrains the result rows into a unique order. Otherwise you will get an unpredictable subset of the query's rows. You might be asking for the tenth through twentieth rows, but tenth through twentieth in what ordering? The ordering is unknown, unless you specified ORDER BY
.
In Rails, if you use Record.first
or Record.last
, it will default to orderin...
Gitlab: How to cancel redundant pipelines
In the Gitlab settings the flag Auto-cancel redundant pipelines is enabled by default. This auto-cancels jobs that have the interruptible
setting set to true
(defaults to false
e.g. to not cancel deploys by accident).
Consider to set the interruptible
flag for test jobs to reduce the load on your runners like in the following example .gitlab-ci.yml
:
rubocop:
interruptible: true
script:
- 'bundle exec rubocop'
rspec:
int...
CSS has a built-in clearfix
The need for clearfix hacks has been greatly reduced since we could layout with Flexbox or CSS Grid.
However, when you do need a clearfix, there's no reason to use a hack anymore. You can just give the clearing container display: flow-root
.
Difference between respond_to/format and params[:format]
To return non-HTML responses (like XLS spreadsheets), we usually use the
respond_to do |format|
format.xls do
# send spreadsheet
end
end
This is often, but not always the same as checking for params[:format] == :xls
, so don't rely on this when e.g. one format checks for authorization and the other doesn't.
params[:format]
is only set when a user explicitly puts a .xls
at the end of the URL.
The format.xls
block also responds when the user's browser requests the application/excel
MIME type.
If Internet Explo...
7 Rules for Creating Gorgeous UI
A great two-part article about various hacks you can use to create great-looking screen designers when you're not a designer.
Part 1 contains:
- Light comes from the sky
- Black and white first
- Double your whitespace
Part 2 contains:
- Learn the methods of overlaying text on images
- Make text pop— and un-pop
- Only use good fonts
- Steal like an artist
OpenAI TTS: How to generate audio samples with more than 4096 characters
OpenAI is currently limiting the Audio generating API endpoint to text bodies with a maximum of 4096 characters.
You can work around that limit by splitting the text into smaller fragments and stitch together the resulting mp3 files with a CLI tool like mp3wrap or ffmpeg.
Example Ruby Implementation
Usage
input_text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Mi eget mauris pharetra et ultrices neque."
output_mp3_path = Rails.root.join("tts/ipsum...
Capistrano: creating a database dump if migrating
In Capistrano 3, your Capfile requires 'capistrano/rails/migrations'
, which brings two Capistrano tasks: deploy:migrate
and deploy:migrating
. The former checks whether migrations should be performed. If so, the latter is invoked, which performs the actual migrations.
Knowing this, it is easy to dump the db only if migrations will run. First, enable conditional migrations:
# config/deploy.rb
set :conditionally_migrate, true # Only attempt migration if db/migrate changed
Then hook up the dump task to deploy:migrating
:
Rails: Pluck across associated tables
#pluck
is commonly used as a performant way to retain single database values from an ActiveRecord::Relation
Book.pluck(:title, :price) #=> [["The Hobbit", "8.99"], ["The Alchemist", "7.89"]]
But #pluck
can do more: you can query multiple tables as well!
Book.joins(:author).pluck("books.title, books.price, authors.name") #=> [["The Hobbit", "8.99", "J. R. R. Tolkien"], ["The Alchemist", "7.89", "Paulo Coelho"]]
Note the use of :author
for the joins, and then authors
for the pluck clause. The first corresp...
RailsStateMachine 2.2.0 released
-
Added: State machine can now use the
:prefix
-option to avoid name collision if you define multiple state machines on the same model, and use state names more than once- Previously
state_machine
-definitions like this:
would produce the following warning:class Form state_machine :first_wizard_stage do state :completed end state_machine :second_wizard_stage do state :completed end end
rails_state_machine-2.1....
- Previously
Livereload + esbuild
Getting CSS (and JS) live reloading to work in a esbuild / Rails project is a bit of a hassle, but the following seems to work decently well.
We assume that you already use a standard "esbuild in Rails" setup, and have an esbuild watcher running that picks up your source code in app/assets
and compiles to public/assets
; if not change the paths below accordingly.
Basic idea
We will
- use the
guard-livereload
gem as the livereload server (which send updates to the browser), - use the
livereload-js
npm package in the browser to con...
Webpack: How to split your bundles
To keep JavaScript sources small, it can sometimes make sense to split your webpack bundles. For example, if your website uses some large JavaScript library – say TinyMCE – which is only required on some selected pages, it makes sense to only load that library when necessary.
In modern webpack this is easily doable by using the asynchronous import
function.
Say we have an unpoly compiler that sets up TinyMCE like this (code is somewhat simplified):
// TinyMCE as part of the main bundle!
import tinymce from 'tinymce/tinymce'
// U...
MySQL: CONCAT with NULL fields
In MySQL,
CONCAT('foo', 'bar', NULL) = NULL
the NULL always wins in MySQL.
If you would rather treat NULL as an empty string, use CONCAT_WS
(concatenation with separator) instead:
CONCAT_WS('', 'foo', 'bar', NULL) = 'foobar'
PostgreSQL
In PostgreSQL the NULL
is not viral in CONCAT
:
CONCAT('foo', 'bar', NULL) = 'foobar'
Simple database lock for MySQL
Note: For PostgreSQL you should use advisory locks. For MySQL we still recommend the solution in this card.
If you need to synchronize multiple rails processes, you need some shared resource that can be used as a mutex. One option is to simply use your existing (MySQL) database.
The attached code provides a database-based model level mutex for MySQL. You use it by simply calling
Lock.acquire('string to synchronize on') do
# non-th...
Javascript: Avoid using innerHTML for unsafe arguments
Make sure that you use the correct property when editing an HTML attribute. Using innerHTML
with unsafe arguments makes your application vulnerable to XSS.
-
textContent
: Sets the content of aNode
(arguments are HTML-safe escaped) -
innerHTML
: Sets the HTML of anElement
(arguments are not escaped and may not contain user content)
Hierarchy
This hierarchy gives you a better understanding, where the textContent
and the innerHTML
properties are defined. It also includes (just for completeness) the innerText
property, whi...
Transfer records to restore database entries (with Marshal)
If you ever need to restore exact records from one database to another, Marshal
might come in handy.
Marshal.dump
is part of the ruby core and available in all ruby versions without the need to install anything. This serializes complete ruby objects including id
, object_id
and all internal state.
Marshal.load
deserializes a string to an object. A deserialized object cannot be saved to database directly as the the dumped object was not marked dirty, thus rails does not see the need to save it, even if the object is not present in...
RSpec: Messages in Specific Order
tl;dr
You can use
ordered
to ensure that messages are received in a specific order.
Example
expect(ClassA).to receive(:call_first).ordered
expect(ClassB).to receive(:call_second).ordered
expect(ClassB).to receive(:call_third).ordered
#ordered supports further chaining
How to define constants with traits
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 (without jQuery)
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:
- When you have many descendants, you save time by only registering a single listener.
- When the descendants are changed dynamic...
Spreewald development steps
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.
Then console
Pauses test execution and opens an IRB shell with current cont...
How to (and how not to) design REST APIs · stickfigure/blog Wiki
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.
RSpec: Composing a custom matcher from existing matchers
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.
Example
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...
Ruby: Using `sprintf` to replace a string at fixed named references
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
Example:
This is quite useful to replace ...
`simple_format` does not escape HTML tags
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...
How to use Rails URL helpers in any Ruby class
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