View

Migrate data between Redis servers

There is a reasonable simple way to move data between Redis servers: Simply temporarily configure the new server as a replica of the old server.

To do this:

  • Make sure the new Redis server can access the old server. If they are on different networks, a simple SSH tunnel will do.
  • Connect to the new server using redis-cli.
  • Tail the log of the redis server (found in /var/logs/redis) in another terminal.
  • Make sure the server is currently master and not already a replica (check INFO replication)
  • Enable replication with `REPLICAOF...
Repeats

Ruby: Referencing global variables with the built-in English library

With Ruby's build-in library English you can reference global variables with an english name. This makes you code easier to read and is also suggested by Rubocop's Style/GlobalVars cop.

Example before:

if 'foo' =~ /foo/
  puts $~[1] # => foo
end

Example after:

if 'foo' =~ /foo/
  puts $LAST_MATCH_INFO[1] # => foo
end

Require pitfall in Rails

The English library is not loaded by default in Rails. S...

Deprecated

How Rails and MySQL are handling time zones

When working with times and dates in Rails applications, you need to deal with the following problem:

  • In Rails, Time objects have a time zone. You can get the zone name by doing time_object.zone.
  • This zone is considered when doing time calculations, e.g. 10 AM CEST minus 8 AM UTC is zero.
  • A datetime in MySQL does not have a zone. It just stores the literal string "2010-05-01 12:00:00".
  • That means that Rails must make assumptions about timestamps loaded from and written to MySQL.

Rails has two completely different modes ...

whenever: Installing cron jobs only for a given Rails environment or Capistrano stage

We use the whenever gem to automatically update the crontab of the servers we deploy to. By default, whenever will update all servers with a matching role (we use the :cron role ).

This card describes how to install some tasks only for a given Rails environment or for a given Capistrano stage.

Installing jobs only for a given Rails environment

In yo...

Repeats

How to update a single gem conservatively

The problem

Calling bundle update GEMNAME will update a lot more gems than you think. E.g. when you do this:

bundle update cucumber-rails

... you might think this will only update cucumber-rails. But it actually updates cucumber-rails and all of its dependencies. This will explode in your face when one of these dependencies release a new version with breaking API changes. Which is all the time.

In the example above updating cucumber-rails will give you Capybara 2.0 (because capybara is a dependency of `cucumber-rail...

Repeats

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 netstat instead of nmap.

Note that nmap's service discovery may trigger several requests.

Example

When using nmap, adding the -A switch ...

Auto-destruct in 3 days

Geordi 3 released

We released two new versions of Geordi. For projects with Ruby 1.8.7 or 1.9.3 you now have to run gem install geordi -v '~>2' to get a compatible version.

Geordi 2.11.0

Compatible changes

  • Added the possibility to change the Rails root for the capistrano config via the environment variable RAILS_ROOT. This allows you as a gem developer to run a command like RAILS_ROOT=~/Projects/my-blog geordi console staging whereas geordi uses the capistrano config from my-blog. Otherwise you would need to follow the instructions of [th...
Repeats

Jasmine: Testing AJAX calls that manipulate the DOM

Here is a Javascript function reloadUsers() that fetches a HTML snippet from the server using AJAX and replaces the current .users container in the DOM:

window.reloadUsers = ->
  $.get('/users').then (html) ->
    $('.users').html(html)

Testing this simple function poses a number of challenges:

  • It only works if there is a <div class="users">...</div> container in the current DOM. Obviously the Jasmine spec runner has no such container.
  • The code requests /users and we want to prevent network interaction in our unit test...
Linked content

Five years of "Today I Learned" from Josh Branchaud

The linked GitHub repository is a bit like our "dev" cards deck, but groomed from a single person (Josh Branchaud). It includes an extensive list of over 900 TILs on many topics that might be interesting for most of us. (e.g. Ruby, Rails, Git, Unix..)

Ruby

Here is an excerpt of all the Ruby TILs that were new to me. I encourage you to take your time to skim over the original list as well!

Rails: Concurrent requests in development and tests

With puma you can have concurrent requests. There are two concepts on how Puma can handle two incoming requests: Workers and Threads.

Workers

Puma can have multiple workers. Each worker is a process fork from puma and therefore a very heavy instance and can have multiple threads, that handle the incoming requests.

Example: A Puma server with 2 workers and 1 thread each can handle 2 request in parallel. A third request has to wait until the thread of one of the workers is free.

Threads

Rails is thread-safe since version 4 (n...

Video transcoding: Web and native playback overview (April 2020)

Intro

Embedding videos on a website is very easy, add a <video> tag to your source code and it just works. Most of the time.

The thing is: Both the operating system and Browser of your client must support the container and codecs of your video. To ensure playback on every device, you have to transcode your videos to one or more versions of which they are supported by every device out there.

In this card, I'll explore the available audio and video standards we have right now. The goal is to built a pipeline that transcodes unknown ...

Linked contentRepeats

Writing a README for a project

Rails applications and ruby gems should have a README that gives the reader a quick overview of the project. Its size will vary as projects differ in complexity, but there should always be some introductory prose for a developer to read when starting on it.

Purpose

That's already the main purpose of a project README: Give a new developer a quick overview of the project. In sketching this outline, the README should notify the reader of any peculiarity he needs to know of.

Remember that in a few months, you'll be a kind of "new ...

Repeats

Redirecting responses for PATCH or DELETE will not redirect with GET

Redirect responses to PATCH and DELETE requests will be followed with PATCH or DELETE. Redirect responses to GET and POST will be followed with a GET.
The Rails form_for helper will use a workaround to send POST requests with a _method param to avoid this issue for PATCH/DELETE.

If you make requests yourself, watch out for the following behavior.

When you make an AJAX request PATCH /foo and the /foo action redirects to /bar, browsers will request PATCH /bar. You probably expected the second request to be...

How to avoid ActiveRecord::EnvironmentMismatchError on "rails db:drop"

After loading a staging dump into development, you might get an ActiveRecord::EnvironmentMismatchError when trying to replace the database (like rails db:drop, rails db:schema:load).

$ rails db:drop
rails aborted!
ActiveRecord::EnvironmentMismatchError: You are attempting to modify a database that was last run in `staging` environment.
You are running in `development` environment. If you are sure you want to continue, first set the environment using:

        bin/rails db:environment:set RAILS_ENV=development

Starting with R...

Sass partial names must always start with an underscore

Be careful to name any file @imported by SASS with a leading underscore.

SASS files not beginning with an underscore will be rendered on their own, which will fail if they are using variables or mixins defined elsewhere. (For me it broke only in production, which may be due to some settings in SASS-GEM/lib/sass/plugin/rails.rb.)

From the SASS docs:

The underscore lets Sass know that the file is only a partial file and that it should not be generated into a CSS file.

Linked content

Inspecting a live Ruby process

How to get a backtrace from a running Ruby process:

Ruby 2.4+

TL;DR to get the backtrace of a live process (sudo required):

# First, find out the PID of your Ruby process (e.g. passenger-status)
$ sudo gdb -p PID
(gdb) generate-core-file                  # generate a core.PID file for later inspection
(gdb) t a a bt                            # thread apply all backtrace
(gdb) call (void) close(1)                # close...
Linked content

How to use the Capistrano 2 shell to execute commands on servers

Capistrano 2 brings the shell command which allows you to run commands on your deployment targets.
There is also invoke to run a command directly from your terminal.

Both commands allow running Capistrano tasks or shell commands, and scope to individual machines or machine roles.

Unfortunately Capistrano 3 does not include these commands any more.

cap shell

Basics

First of all, spawn a Capistrano shell (we're using the multistage extension here):

$ cap staging shell

In your "cap" shell you can now run Capistrano ta...

Rails: Rest API post-mortem analysis

This is a personal post-mortem analysis of a project that was mainly build to provide a REST API to mobile clients.

For the API backend we used the following components:

  • Active Model Serializer (AMS) to serializer our Active Record models to JSON.
  • JSON Schema to test the responses of our server.
  • SwaggerUI to document the API.

It worked

The concept worked really good. Here are two points that were extraordinary compared to normal Rails project with many UI components:

  • Having a Rails application, that has no UI components (only...
This website uses cookies to improve usability and analyze traffic.
Accept or learn more