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...
Structuring Rails applications: the Modular Monorepo Monolith
Root Insurance runs their application as a monolithic Rails application – but they've modularized it inside its repository. Here is their approach in summary:
Strategy
- Keep all code in a single repository (monorepo)
- Have a Rails Engine for each logical component instead of writing a single big Rails Application
- Build database-independent components as gems
- Thus: gems/ and engines/ directories instead of app/
- Define a dependency graph of components. It should have few edges.
- Gems and Engines can be extracted easier once nece...
Checklist: Using Carrierwave in a Rails project
This checklist should help you to check edge cases that are not part of the default Carrierwave configuration.
- Check Default Configuration and Suggested Changes
- Use secret URLs.
- Check if you need expiring public URLs.
- Check if you need an optimized cache
- Use a [nested directory structure](https://makandracards.com/m...
Always convert and strip user-provided images to sRGB
Debugging image color profiles is hard. You can't trust your eyes in this matter, as the image rendering depends on multiple factors. At least the operation system, browser or image viewer software and monitor influence the resulting image colors on your screen.
When we offer our users the possibility to upload images, they will most likely contain tons of EXIF metadata and sometimes exotic color profiles like eciRGB. We want to get rid of the metadata, as it might contain sensitiv...
A Migration Path to Bundler 2+
Bundler 2 introduced various incompatibilites und confusing behavior. To add to the confusion, Bundler's behavior changed after the release of their version 2.
The linked article explains what happened.
Understanding grid sizes of (SVG) icons
A primer on vector graphics
For rastered image formats like JPG or PNG, each pixel is basically drawn on a fixed size canvas. To display such an image in a different size (say: 1.5 times larger than original), the renderer (your Browser / GPU / Monitor) needs to interpolate the color values of missing pixels. The image will appear slightly blurred.
This is different for vector graphics like the SVG (Scalable Vector Graphics) format. You can imagine SVG files as XML file contai...
Automated wordbreaks for long words
The problem:
So I had the issue that User input (coming from many different sources and users) often contains the same long word. Maybe that's a super german thing to have lots of long words I have to deal with. This long word needs to be fully visible on small screens but none of the automated word-break solutions offered by css (https://justmarkup.com/articles/2015-07-31-dealing-with-long-words-in-css/) is clever or supported enough to be a good solution. So I...
Resources for working with the Youtube API
You can use the Youtube API to get data from youtube. Here are some resources and some things that are good to know.
You need to create an API key and each request will cost a certain amount of Request-Points (depending on the kind of query).
It may help to understand youtube's domain model before starting.
It's best to just try out your requests in the browser to see what you will get.
A request can look like this (note that you have to replace the playlis...
Bookmarklet to generate a Pivotal Tracker story from Zammad Ticket
This is a bookmarklet you can add to Chrome or Firefox which will allow you to create a story in Pivotal Tracker from a Zammad ticket. This might come in handy when creating stories for SWAT Teams.
But first you will have to set two variables in the script below:
-
pt_project_id
: the ID of the Pivotal Tracker Project you want to add stories to. This can be found as part of the URL of the project (https://www.pivotaltracker.com/n/projects/<pt_project_id>
) -
pt_token
: the Pivotal Tracker token used for authentication. Can be found in y...
Rails: Verify the CSRF token
Rails uses a CSRF token in forms and AJAX requests to verify a user request. Internally it compares the injected CSRF token of the form data with the CSRF token in the encrypted user session. To prevent SSL BREACH attacks, the CSRF token from the form data is masked.
To better debug issues, when these tokens do not match, it is useful to unmask the CSRF token from the form da...
Unicorn: How to force a single threaded boot in development
Unicorn allows you to specify the maximum number of workers. In development this could be useful if you use a debugger, but do not want to overflow the console with other request like from ActionCable. Then just set the maximum number of workers to 1
and the other requests have to wait.
UNICORN_WORKERS=1 rails server
Guidelines for Pull Requests and Code Reviews
Projects with more than one developer should always consider to enforce code review even for small changes to improves the overall code health of the system. Here are some guidelines that can help you to accomplish this task.
Github
How to write the perfect pull request
Google's Engineering Practices documentation
Modern Code Review: A Case Study at Google
Though...
A collection of useful design resources for developers
This collection contains some useful design resources for developers. Many of them were mentioned in the Refactoring UI tutorials.
Tutorials
Rails: Invoking a view helper from the console
There are a few ways to access view helpers from the Rails console. The easiest way is the helper
shortcut:
helper.translate 'i18n.string'
helper.your_helper_method
If the desired helper renders a view template, you need this setup:
view_paths = Rails::Application::Configuration.new(Rails.root).paths["app/views"]
av_helper = ActionView::Base.new(view_paths).extend YourHelperModule
av_helper.your_helper_method
Rails routing: Using constraints to avoid "Missing template" errors
You can use constraints in your routes.rb
to avoid getting ActionView::MissingTemplate
errors when wrong routes are called. Instead, the user will see a 404.
If you want multiple routes to use the same constraint you can use the block syntax:
constraints(format: 'html') do
resources :pages
resources :images
end
If you want constraints only on certain routes, you can do:
get '/users/account' => 'users#account', constraints: { format: 'html' }
Tip
You can also avoid this error type through [format con...
How to enable Chromedriver logging
When using Chrome for Selenium tests, the chromedriver
binary will be used to control Chrome. To debug problems that stem from Selenium's Chrome and/or Chromedriver, you might want to enable logging for the chromedriver itself. Here is how.
Option 1: Use Selenium::WebDriver::Service
In your test setup, you may already have something like Capybara::Selenium::Driver.new(@app, browser: :chrome, options: ...)
, especially when passing options like device emulation.
Similar to options
, simply add an extra key service
and pass an inst...
Bash script to list commits by Pivotal Tracker ID
The main benefit of our convention to prefix commits by their corresponding Pivotal Tracker ID is that we can easily detect commits that belong to the same story. You can either do that manually or use the bash script below by copying it somewhere to your .bashrc
.
# Usage: ptcommits 123456
function ptcommits {
if test "$1"
then
local PTID=$(echo "$1" | grep "[0-9]*" -o) # Allow URLs
git log --onel...
Using CSS transitions
CSS transitions are a simple animation framework that is built right into browsers. No need for Javascript here. They're supported by all browsers.
Basic usage
Transitions are used to animate the path between to property values. For example, to let the text color fade from red to green on hover, the following SASS is used (shorthand syntax):
.element
color: red
transition: color .1s
&:hover
color: green
This tells the browser "whenever the color
of an .element
changes...
Rails: Do not load frameworks you don't need
Rails is split into a large number of (sub-) frameworks.
The most important and central of those are
- activesupport (extends the Ruby standard library)
- activerecord / activemodel (ORM for Rails)
- actionview / actionpack (controller / views)
- actionmailer (sends mails)
However, there are also some more situational frameworks included, such as
- actioncable (real time communications using websockets)
- actionmailbox (receives mails)
- actiontext (support for WYSIWYG text editor)
- activejob (background jobs)
- activestorage (file uplo...
Controlling how your website appears on social media feeds
When a user shares your content, a snippet with title, image, link and description appears in her timeline. By default social networks will use the window title, the first image, the current URL and some random text snippet for this purpose. This is often not what you want.
Luckily Facebook, Twitter, etc. lets you control how your content appears in the activity streams. They even have agreed on a common format to do this: OpenGraph <meta>
tags that go into your HTML's <head>
:
<meta property="og:url" content="http://start.m...
Unpoly: Showing the better_errors page when Rails raises an error
When an AJAX request raises an exception on the server, Rails will show a minimal error page with only basic information. Because all Unpoly updates work using AJAX requests, you won't get the more detailled better_errors page with the interactive REPL.
Below is an event listener that automatically repeats the request as a full-page load if your development error shows an error page. This means you get...
Webpack(er): A primer
webpack is a very powerful asset bundler written in node.js to bundle (ES6) JavaScript modules, stylesheets, images, and other assets for consumption in browsers.
Webpacker is a wrapper around webpack that handles integration with Rails.
This is a short introduction.
Installation
If you haven't already, you need to install node.js and Yarn.
Then, put
gem 'webpacker', '~> 4.x' # check if 4.x is still cu...
Jasmine: using async/await to write nice asynchronous specs
Jasmine has long standing support for writing asynchronous specs. In days gone by we used the done
callback to achieve this, but these days it is possible to write much more readable specs.
Async specs
As a first example, say we want to check that some form disables the submit button while working.
// bad (how we used to do it)
beforeEach(() => {
this.form = setupMyForm()
this.submitButton = findTheSubmitButton()
})
it('disables the submit button while working', (done) => {
expect(this.submitButton.disabled).toBe(false)
...
Adding Jasmine JavaScript specs to a Webpack(er) project
The goal is to get Jasmine specs running in a Rails project using Webpacker, with the browser based test runner. Should be easily adaptable to a pure Webpack setup.
Step 1: Install Jasmine
yarn add jasmine-core
Step 2: Add two separate packs
Since we do not want to mix Jasmine into our regular Javascript, we will create two additional packs. The first only contains Jasmine and the test runner. The second will contain our normal application code and the specs themselves.
We cannot...