How to deal with 'parent id missing' error in nested forms

tl;dr

  • Use form models to handle this problem
  • Or soften the validation to validates_presence_of :parent

Usually you would validate presence of parent object id, like in this example:

class Parent < ActiveRecord::Base
  has_many :nested, :inverse_of => :parent
  accepts_nested_attributes_for :nested
end

class Nested < ActiveRecord::Base
  belongs_to :parent
  validates_presence_of :parent_id # <- 
end

With the parent already persisted creating nesteds still works fine.

But one will encounter a *'parent id missing' er...

How to silence thin boot messages

Each time thin boots, it prints a boot message :

Thin web server (v1.6.3 codename Protein Powder)
Maximum connections set to 1024
Listening on localhost:36309, CTRL+C to stop

If you are running parallel tests with thin, this will clutter you output. Disable thin logging with these lines:

# e.g. in features/support/thin.rb

require 'thin'
Thin::Logging.silent = true

Note that this disables all logging in tests. Instead, you also might set a different logger with `Thin::Loggi...

How to split config/routes.rb in Rails 4

A word of caution

There should rarely be a reason for you to split up config/routes.rb. If you need to, probably your whole application should be split up.

Split it anyway

Rails::Engine looks at config.paths['config/routes.rb'] and registers its value with app.routes_reloader. This means you could put routing files anywhere and then require them. However, I recommend to put any routing files into config/routes/:

# config/routes/example.rb

Rails.application.routes.draw do
 resources :example
end

After creating y...

marco-polo improves your Rails console prompt

MarcoPolo shows your app name and environment in your console prompt so you don't accidentally break production
Officially supporting IRB (standard rails console) and pry (via pry-rails gem).

Example:

$ rails console
Loading development environment (Rails 4.2.1)
agencyapp(dev)> 

List of Helpful RubyMine Shortcuts

Navigation

CTRL + SHIFT + ALT + N

Search for any symbol in your application, like CSS classes, Ruby classes, methods, helpers etc.

CTRL + SHIFT + N

Search for filename in your application (also dependencies)

CTRL + E

Open a list of recently opened files

ALT + POS1

Open a the navigation bar as a context menu. Allows you to quickly navigate between files.

CTRL + G

Go to line

Actions

CTRL + SHIFT + A

:...

PostgreSQL: Be careful when creating records with specific ids

In tests, it is sometimes useful to create records with specific ids. On PostgreSQL this can cause problems:

Usually, PostgreSQL uses an "autoincrement" sequences to provide sequential ids for new database rows. However, these sequences will not increment if you insert a record "by hand". This will cause an error:

record = Record.create!
record.id                             # => 100, next automatic id will be 101
Record.create!(id: record.id + 1)     # okay, but next automatic id will still be 101
Record.create!                       ...

Jasmine: Testing complex types for equality

Jasmine comes with two matchers that test for equality. The first is toBe:

expect(first).toBe(second)

toBe passes when first === second. Unfortunately this is useless for non-primitive values because JavaScript is a horrible language.

However, Jasmine comes with another matcher toEqual:

expect(first).toEqual(second)

This matcher behaves as a human would expect for types like the following:

  • Arrays
  • Objects
  • Nested array/object constructs
  • Regular expressions...

Mocking time in Jasmine specs

The easiest way to freeze or travel through time in a Jasmine spec is to use the built-in jasmine.clock().

  • After jasmine.clock().install() you can use it to control setTimeout and setInterval.
  • Using jasmine.clock().mockDate() you can mock new Date() (which returns the current time in Javascript)

While you can use SinonJS Fake timers, using the built-in Jasmine clock will save you an extra dependency.

Pierce through Javascript closures and access private symbols

If you are writing any amount of Javascript, you are probably using closures to hide local state, e.g. to have private methods.

In tests you may find it necessary to inspect a variable that is hidden behind a closure, or to mock a private method using Jasmine spies.

You can use the attached Knife helper to punch a hole into your closure, through which you can read, write or mock local symbols:

klass = (->

 privateVariable = 0

 privateMethod = ->
   ...

JavaScript events: target vs currentTarget

tl;dr: Use event.currentTarget unless you are absolutely certain that you need event.target.


Since it hasn't been written down in this deck before, here it goes:

When working with JavaScript Event objects, the DOM element that triggered the event is attached to them. [1]
However, there are 2 "opinions" on which element that would be:

  • The element that the user interacted with (event.target),
  • or the element that the event listener is bound to (event.currentTarget).

Note that both can be, but not...

How to fix: iPad does not trigger click event on some elements

iPads will not trigger click events for all elements. You can fix that, but you don't want to know why.

Example: Capturing clicks on table rows (use case would be clicking the 1st link inside it for better UI). Consider this setup:

<table>
  <tr>
    <td>hello</td>
  </tr>
</table>

^

$(document).on('click', 'tr', function () {
  alert('row clicked')
});

While this works on a desktop browser, clicking the row/cell on an iPad will just do nothing.

Turns out, the iPad will only trigger such events for ...

Parallel Rspec with RTeX

Running projects parallel makes some trouble with PDF generation. Use geordi rspec spec to force sequential tests for the whole application or failed specs only.


geordi rspec
RTeX::Document::GenerationError in '...'
Could not find result PDF document.pdf after generation.
Check .../document.log

The document will show you, that RTeX tries to generate a PDF document out of a HTML file, which won't work.

Protip: Clone large projects multiple times

Large projects usually have large test suites that can run for a long time.
This can be annoying as running tests blocks you from picking up the next story -- but it doesn't have to be that way!

Simply clone your project's repo twice (or even more often).

When your work on a feature branch is done, simply push that branch and check it out on your 2nd copy to run tests there.
You can pick up a new story and work on that on your "main" project directory.

If you do it right, you will even be able to run tests in both your 2nd copy and your m...

Material Design Lite

CSS (+ some Javascript) framework, implementing Google's material design for static web pages.

Can be used for plain websites without requiring a full blown Javascript framework, unlike the (also excellent) Polymer paper elements, or Angular material.

Prelimiary impression:

I would recommend against using it at this stage, for a couple of reasons:

  • It is much less complete than you might expect from a CSS framewor...

A non-weird replacement for grouped_collection_select

Rails comes with grouped_collection_select that appears to be useful, but isn't.

As an alternative, consider the flat_grouped_collection_select found below. It takes a third argument that extracts the group from each element in the collection:

= form.flat_grouped_collection_select :user_id, users, :department, :id, :full_name

Here is the monkey-patch:

class ActionView::Helpers::FormBuilder

  def flat_grouped_collection_selec...

Rails 3 ActiveRecord::Persistence#becomes does not copy changed attributes

Note: ActiveRecord::Base#becomes has a lot of quirks and inconsistent behavior. You probably want to use ActiveType.cast instead.


This issue will be encountered when relying on attribute_was methods of ActiveModel::Dirty after casting a model which has defaults to a form model, for example.

In my case a record with an assignable_values legacy value beca...

Querying model errors in Rails 4

ActiveModel supplies an errors object that behaves similar to a Hash. It can be used to add errors to a record, as well as to query the record for registered errors. This object is returned when calling <object>.errors:

errors = @user.errors # => #<ActiveModel::Errors ...>

Here are some helpful messages of its API:


[<attribute name>]

Returns an array of error messages on that attribute. Example: errors[:name] => ['is missing']


add_on_blank(<attribute list>) (similarly add_on_empty)

Registers an error ...

Reverse-proxying web applications with Apache 2.4+

Note: Making a reverse proxy with nginx is much more straightforward.


A reverse proxy is a "man in the middle" server that tunnels requests to another server. You can use for things like:

  • Expose a local service that you cannot directly reach over the internet
  • "Change" the domain or path of a web application by rewriting them on the fly
  • Instantly change servers that respond to a name or ...

sessionStorage: Per-window browser storage

All major browsers (IE8+, FF3.5+, Safari 4+, any Chrome) support sessionStorage, a JavaScript storage object that

  • survives page reloads and browser restores,
  • but is different per new tab/window (in contrast to localStorage which is shared across all tabs).

MDN says:

The sessionStorage object is most useful for hanging on to temporary data that should be saved and restored if the browser is accidentally refreshed

Demo

Example usage:

Upgrading from Capistrano 2 to 3

Capistrano 3 is a major rework of the framework and requires several adjustments to your deploy configuration files. The biggest change is that they moved away from their custom DSL and use Rake instead. For connecting with and operating on the servers, they bring a new gem SSHKit which does the heavy lifting. It's SSHKit's DSL that is used anywhere inside the Rake tasks. See #Resources at the bottom for examples.

Step 1: Upgrade guide

For migration from 2 to 3, follow this tutorial: [Capistrano 3 Upgrade Guide](https://semaphorec...

Savon testing: How to expect any message

When using Savon to connect a SOAP API, you may want to use Savon::SpecHelper to mock requests in your tests as described in their documentation.

When sending a message body, the savon mock object requires a message to be set, like this:

savon.expects(:action_name).with(message: { user_id: 123 }).returns('<some xml>')

If you want to stub only the returned XML and do not care about request arguments, you can not omit with as Savon's helper will complain:

savo...

Testing setTimeout and setInterval with Jasmine

Jasmine has a jasmine.clock() helper that you can use to travel through time and trigger setTimeout and setInterval callbacks:

beforeEach(function() {
  timerCallback = jasmine.createSpy("timerCallback");
  jasmine.clock().install();
});

afterEach(function() {
  jasmine.clock().uninstall();
});

it("causes a timeout to be called", function() {
  setTimeout(function() {
    timerCallback();
  }, 100);

  expect(timerCallba...

Why you see a GET "/__identify__" request in Capybara tests

You might wonder about this request in your test.log:

Started GET "/__identify__" for 127.0.0.1 at 2015-04-29 18:00:02 +0100

This is what happens: For drivers like Selenium, Capybara will boot up a Thin or Webrick server in a separate thread. It then makes a GET request to /__identify__ to see if the server is ready to accept requests.

Since you don't have a route that responds to /__identify, Capybara will wrap your Rails app in...

PostgreSQL vs MySQL: How to UPDATE using a JOIN

When you want to UPDATE a table with information from an associated table, you can JOIN the associated table into the statement.

Example

Let's say you have a database schema where an Employee belongs_to :department:

+-----------------+
| Employee        |                   +------------+
|-----------------| n               1 | Department |
| email           |-------------------|------------+
| department_id   |                   | name       |
+-----------------+                   +------------+

Because of perfo...