ActiveRecord::Store: migrate data in store
When you need to store structured data (like Ruby hashes) in a single database column with ActiveRecord, a simple way is to use PostgreSQL's jsonb
columns. ActiveRecord will automatically serialize and deserialize your Hash to and from JSON, and you can index JSON paths for fast reads.
As an alternative, ActiveRecord::Store
offers a way to store hashes in a single database column. This card will show you how to migrate those hashes in an ActiveRecord::Migration
by example:
...
Checklist: Rails Authentication
Authentication is a special part of web applications. On the one hand, it usually is a crucial security mechanism restrict access to certain people and roles. On the other hand, most users authenticate only once, so it is very unlikely to spot issues by accident.
So, here comes a quick checklist to help you verifying your authentication solution is all set.
- This should be default: use HTTPS with HSTS. The HSTS part is important.
- Use a reliable authentication solution, e.g. Clearance or [Devise...
screenfull.js: Simple wrapper for cross-browser usage of the JavaScript Fullscreen API
Using the JS fullscreen API is painful because all browers use different methods and events and you need to use lots of boilerplate code to make your application work in all browsers.
The "screenfull" library wraps that for you, including events.
Examples
The linked GitHub repo contains some information. You basically use the library like this:
// Make an element go fullscreen
screenfull.request(element)
// Leave fullscreen
screenfull.exit()
...
Unpoly: Loading large libraries on-demand
When your JavaScript bundle is so massive that you cannot load it all up front, I would recommend to load large libraries from the compilers that need it.
Compilers are also a good place to track whether the library has been loaded before. Note that including same <script>
tag more than once will cause the browser to fetch and execute the script more than once. This can lead to memory leaks or cause duplicate event handlers being registered.
In our work we mostly load all JavaScript up front, since our bundles are small enough. We recent...
Rails: How to provide a public link in a mail
Lets say we have a user
with a contract
whereas contract
is a mounted carrierwave file.
Now we want to send the link to the contract in a mail. For this use case join the root_url
with the public contract path in the mailer view:
Plain text email
URI.join(root_url, @user.contract.url)
HTML email
link_to('Show contract', URI.join(root_url, @user.contract.url).to_s)
Note: You need to follow [http://guides.rubyonrails.org/action_mailer_basics.html#g...
Fixing: Gem::Package::PathError: installing into parent path is not allowed
This might be a known issue with Rubygems 2.5.1. This will help:
gem update --system
How to resize your boot partition when there is an encrypted partition after it
Boot partitions from installations prior to the 16.04 era are terribly small. When you install updates and encounter errors due to a full /boot
partition, consider risizing it.
If you can't do the steps described below, ask someone experienced to help you out.
This has worked 100% so far. 1 out of 1 tries. ;)
Scenario A: There is unassigned space on your physical drive
When there is some unpartitioned space on your drive, increasing the size of /boot
is actually very easy (even though the list below is rather long). It only takes a...
Rails: Overriding view templates under certain conditions only
Rails offers a way to prepend (or append) view paths for the current request. This way, you can make the application use different view templates for just that request.
Example
A use case of this is a different set of view templates that should be used under certain circumstances:
class UsersController < ApplicationController
before_action :prepare_views
def index
# ...
end
private
def prepare_views
if <condition>
prepend_view_path Rails.root.join('app', 'views', 'special')
end
end
...
Advantages of using appname.daho.im:3000 over localhost:3000
Running rails server
will start a local server that you can access via http://localhost:3000
.
When you are working on multiple web apps, they will likely set cookies with generic names on localhost
. This is annoying, since you will sign out your current user whenever you switch to another app.
A better way is to use our own daho.im service. All daho.im subdomains resolve to your local IP (127.0.0.1). That means you can use a different hostname for different apps, and you will stay logged in in each app:
http://foo-ap...
PostgreSQL: Upgrading your user to a superuser
Your default postgres user is named like your linux user. That default user has limited access privileges, which can cause issues such as:
- DatabaseCleaner needs to disable foreign key constraints before it can wipe the database.
- Importing a remote dump with geordi
- Asking Postgres to show the storage path of a database
Doing these things without a superuser will show a Postgres error or (in Ruby) raise PG::InsufficientPrivilege
.
To do so, the application's PostgreSQL user must be a superuser. ...
How to control Chromedriver using curl
Here is how to use Chromedriver without libraries like selenium-webdriver
. This can be useful for debugging.
The following example visits a web page and reads the a headline's text contents.
-
Create a session. You will get a JSON response containing lots of information about your Chrome session, including a
sessionId
. Use that to send any future commands to your chromedriver session.$ curl -XPOST http://localhost:9515/session -d '{"desiredCapabilities":{"browserName":"chrome"}}' {"sessionId":"your-session-id-here","sta...
XHR is not JSON
When a Rails controller action should handle both HTML and JSON responses, do not use request.xhr?
to decide that. Use respond_to
.
I've too often seen code like this:
def show
# ...
if request.xhr?
render json: @user.as_json
else
# renders default HTML view
end
end
This is just plain wrong. Web browsers often fetch JSON via XHR, but they (should) also send the correct Accept
HTTP header to tell the server the data they expect to receive.
If you say request.xhr?
as a means for "wants JSON" you are ...
Cucumber: How to avoid VCR errors for unused requests in pending tests
When you have a pending Cucumber step (or feature) that also uses an existing VCR cassette, your pending test may fail at the very end with an error like this:
There are unused HTTP interactions left in the cassette:
- [get ...] => [200 ...]
- [get ...] => [200 ...] (VCR::Errors::UnusedHTTPInteractionError)
The error happens because your VCR is configured to complain about cassettes that contain extra requests which your test did not use. This is often a good configuration.
If you do not want to change your whole test suite...
Rails and Postgres: How to test if your index is used as expected
This is a small example on how you can check if your Postgres index can be used by a specific query in you Rails application. For more complex execution plans it might still be a good idea to use the same path of proof.
1. Identify the query your application produces
query = User.order(:last_name, :created_at).to_sql
puts query
# => SELECT "users".* FROM "users" ORDER BY "users"."last_name" ASC, "users"."created_at" ASC
2. Add an index in your migration and migrate
add_index :users, [:last_name, :created_at]...
How to use cookies with curl
When making requests using curl, no cookies are sent or stored by default.
However, you can tell curl to re-use cookies received earlier (or forge your own cookies).
There are 2 command line switches you need to use:
-
-c
will write cookies to a given file -
-b
will read cookies from a given file
Example
The remote server sets a "foo" cookie to value "bar". We tell curl to store them to a file at /tmp/cookies
using the -c
switch.
$ curl -c /tmp/cookies http://httpbin.org/cookies/set?foo=bar
You may look at the file, ...
Jasmine: Mocking API requests in an Angular service spec
Situation: You want to write a spec for a function inside an Angular service. This function at some point makes an API request and acts upon response. Notably, your Angular app employs uiRouter, although it is not used nor actually required for this test.
Working test setup
# Capitalized expressions are intended to be replaced with YOUR values
describe 'SERVICE', ->
beforeEach ->
module 'MODULE'
module ($urlRouterProvider) ->
# Prevent uiRouter's initialization, i.e. do not sync the current URL
# with its r...
HTML: Making browsers wrap long words
By default, browsers will not wrap text at syllable boundaries. Text is wrapped at word boundaries only.
This card explains some options to make browsers wrap inside a long word like "Donaudampfschifffahrt"
.
Option 1: hyphens CSS property (preferred)
Modern browsers can hyphenate natively. Use the hyphens CSS property:
hyphens: auto
There is also hyphens: none
(disable hyphenations even at ­
entities) and hyphens: manual
(hy...
chromedriver-helper gem in Gemfile might break you selenium tests (of other projects)
Summary: Don't add chromedriver-helper to the Gemfile
- the executables might break your tests in projects where
chromedriver-helper
is not in the Gemfile - developers with different chrome versions will have problems using the same
chromedriver-helper
version
Background
If you install the chromedriver-helper
gem, but don't have it in you Gemfile, your selenium tests might fail with:
Selenium::WebDriver::Error::WebDriverError: unable to connect to chromedriver 127.0.0.1:9515
The reason is that chromedriver-helper
ov...
Inspecting Angular 1.x UI Router
If your Angular app has some decent complexity, it will not be easy to use UI Router straight away. Here are some hints on how to get around.
Accessing the UI Router $state service from the browser console
$state = angular.element(document.body).injector().get('$state')
: Retrieves the Angular injector and asks it for the $state
service.
Inspecting the current state
$state.current
Inspecting params of the current state
$state.params
Turning off VCR when stubbing with Webmock
Sometimes when working with VCR you still want to use webmock. Since VCR hooks into webmock and fails when an unknown request is happening, you have to turn it off in order to use webmock like you are used to. Here is how to do this in rspec.
RSpec.configure do |config|
config.around do | example |
if example.metadata[:turn_off_vcr]
VCR.turn_off!
example.run
VCR.turn_on!
else
example.run
end
end
end
Webservice to test and inspect requests
Requestb.in is a webservice that gives you a temporary URL you can use to test request. The page will automatically record and display the latest web request made to it.
Spreewald: Content-Disposition not set when testing a download's filename
Precondition
- You are not using javascript tests
- The file is served from a public folder (not via controller)
Problem description
If you deliver files from a public folder it might be that the Content-Disposition
header is not set. That's why the following spreewald step might raise an error:
Then I should get a download with filename "..."
expected: /filename="some.pdf"$/
got: nil (using =~) (RSpec::Expectations::ExpectationNotMetError)
Solution
One solution...
Fixing flaky E2E tests
An end-to-end test (E2E test) is a script that remote-controls a web browser with tools like Selenium WebDriver. This card shows basic techniques for fixing a flaky E2E test suite that sometimes passes and sometimes fails.
Although many examples in this card use Ruby, Cucumber and Selenium, the techniques are applicable to all languages and testing tools.
Why tests are flaky
Your tests probably look like this:
When I click on A
And I click on B
And I click on C
Then I should see effects of C
A test like this works fine...
Be careful to use correct HTTP status codes for maintenance pages
When your public-facing application has a longer downtime for server maintenance or long migrations, it's nice to setup a maintenance page to inform your users.
When delivering the maintenance page, be very careful to send the correct HTTP status code. Sending the wrong status code might get you kicked out of Google, or undo years of SEO work.
Popular footguns
Here are some ways to shoot yourself in the foot during maintenance:
- If all your routes send a "200 OK" with a HTML body "We're b...