Today I Learned

A Hashrocket project

89 posts by viniciusnegrisolo @vfnegrisolo

Does CoffeeScript has a ternary operator?

Javascript has a ternary operator condition ? expr1 : expr2 like:

var x = true;
x ? 'yes' : 'no'
//=> "yes"
x = false;
x ? 'yes' : 'no'
//=> "no"

What about CoffeeScript?
x ? 'yes' : 'no'

will be compiled to the following:

if (typeof x !== 'undefined' && x !== null) {
} else {
  ({ 'yes': 'no' });

Why? Because of The Existential Operator

So there is no ternary operator on CoffeeScript. The best you can do is to have an one-line if-else statement:

if x then 'yes' else 'no'

h/t @mwoods79

Vim tree view mode

In folder/file structure if you type i you’ll change the way you see the folders and files.

There are 4 different view modes and one of them is something like that:

| app/
| bin/
| config/
| | environments/
| | | development.rb
| | | production.rb
| | | test.rb
| | initializers/
| | locales/
| | application.rb
| | boot.rb
| | database.yml
| | environment.rb
| | routes.rb
| db/

So yes, We don’t need nerdtree

Rails 5 API and CORS

So if you have your frontend and backend on different domains you’ll need to allow CORS (cross-origin HTTP request).

Rails 5 with --api mode will prepare the setup for you. You just need to uncomment the following:

# Gemfile
gem 'rack-cors'
# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'localhost:4200'
    resource '*',
      headers: :any,
      methods: %i(get post put patch delete options head)

Time Travel by Rails

Rails have travel, travel_to, travel_back Testing Helper Methods to travel in time and then test your app with exact dates and times.

include ActiveSupport::Testing::TimeHelpers

=> Tue, 17 May 2016 12:31:52 UTC +00:00

travel_to, 11, 24, 01, 04, 44)
=> Wed, 24 Nov 2004 06:04:44 UTC +00:00

=> Tue, 17 May 2016 12:32:17 UTC +00:00

Another nice alternative is to use gems like:

Rails 5 API mode

You can build a rails API with the --api mode on Rails 5.

rails _5.0.0.rc1_ new rails5-api --api

Gems removed with api mode:

  • coffee-rails
  • jquery-rails
  • sass-rails
  • uglifier
  • turbolinks
  • jbuilder

Files removed with api mode:

  • app/assets
  • lib/assets
  • vendor/assets
  • app/helpers
  • app/views/layouts/application.hmtl.erb


app/controller/application_controller.rb has changed to inherit from ActionController::API

Rack middleware list changed with api mode:

5 middlewares were removed, including Cookies and Flash.

use Rack::MethodOverride
use WebConsole::Middleware
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash

Check their changelog

Rails 5 changed belongs_to default validation

New Rails 5 applications comes with this initializer:

# config/initializers/active_record_belongs_to_required_by_default.rb
Rails.application.config.active_record.belongs_to_required_by_default = true

So now, belongs_to associations require presence by default.

In order to make this relation optional you can change the initializer value for the whole app, or add optional: true to your relation:

belongs_to :user, optional: true

That’s the code change.

How to take next elements with Enumerator

So we had this logic to get the next 10 Tuesdays and Thursdays:

date = Time.current
(1..10).map { date = next_available_day(date) }

def next_available_day(date)
  loop { return date if tuesday_or_thursday?(date += }

def tuesday_or_thursday?(date)
  date.wday == 2 || date.wday == 4

With Enumerator it seems cleaner:


def next_available_dates(date) do |enumerator|
    loop { enumerator.yield date if tuesday_or_thursday?(date += }

def tuesday_or_thursday?(date)
  date.wday == 2 || date.wday == 4

h/t by @mwoods79

Rails 5 deprecation warning for Controller tests

Rails 5 has changed its ActionController::TestCase::Behavior to methods we use in controller tests and now you need to specify params key to the requests.

So if you had this in you tests:

get :show, id: 1

You’ll need to change to:

get :show, params: { id: 1 }

There is a warning message like this:

ActionController::TestCase HTTP request methods will accept only
keyword arguments in future Rails versions.
  get :show, params: { id: 1 }, session: { user_id: 1 }
  process :update, method: :post, params: { id: 1 }

Even if you use Rpsec you will need to change because rspec-rails uses this module to create the requests to the controllers.

Auto Complete with vim snippets

There is a vim plugin called vim-snipmate that lets to auto complete a bunch of code for you. So you type some snippet trigger and hit <tab> and that’s it.

Also there is another vim plugin vim-snippets with a lot of snippets for a lot of languages or file types.

For example this snippet for if in shell files:

snippet if
    if [[ ${1:condition} ]]; then


Global git hooks

There are no global git hooks.

But you can create global hook templates and for every project you can use them.

Create a folder for your global templates:

mkdir -p ~/.git-templates/hooks

Configure git to use this templates folder:

git config --global init.templatedir '~/.git-templates'

Create an executable hook, for example `~/.git-templates/hooks/pre-commit bash #!/bin/sh echo "This happens before the commit" For every project you want to use these templates restart git project running: bash git init These will create symbol links like: bash lrwxr-xr-x pre-commit -> /Users/vnegrisolo/.git-templates/hooks/pre-commit

Vim arglist => replace text to multiple files

  • :arg => list files in arglist
  • :argdelete * => clean arglist
  • :argadd **/*.rb => add files to arglist
  • :argdo %s/foo/bar/gc => replace foo by bar in arglist
  • :argdo update => save changes to arglist
  • :argdo undo => undo changes to arglist

Navigation in arglist

  • [a => go to the previous file in arglist
  • ]a => go to the next file in arglist
  • [A => go to the first file in arglist
  • ]A => go to the last file in arglist

Github Reactions and Merge Strategy

Recently Github has launched 2 new features:

Reactions to comments

Now users can add few reactions to Issues, Pull Requests or Comments. This will reduce a lot of noise on issues like the 👍 (:+1:) for new feature. Really cool.

Squash and rebase as a new merge strategy

Github always create a new commit merging a branch into another one (usually master).

So now we can choose to squash commits and merge. So all commits in a branch will become just one and this one will be rebased into the branch. Sounds cool for a few situations.

Check it out!

Rails nested forms

You can use rails Nested Forms even with plain form objects.

You just need to use form.fields_for and then declare the params name and the object for validation errors.


= form_for @foo_form, as: :foo, url: foo_path do |form|
  = form.text_field :name
  = form.fields_for :bar_params, do |nested_form|
    = nested_form.text_field :description


class FooForm
  include ActiveModel::Model

  attr_accessor :name, :bar_params, :bar
  validates :name, presence: true

  def initialize(attributes = {})
    super attributes  =

  def save
    valid? && Foo.create(name: name)&&
class BarForm
  include ActiveModel::Model

  attr_accessor :description
  validates :description, presence: true

  def save
    valid? && Bar.create(description: description)


class FooController < ApplicationController
  def edit
    @foo_form =

  def create
    @foo_form =[:foo])
      redirect_to root_path
      render :edit

So the bar params will be scoped into bar_params node, and the validations will work.

Capybara tests on a Rails Engine

If you have a Rails Engine you probably have a dummy app attached in test/dummy or spec/dummy to run and manual test the engine, right?

So you can use this dummy app to have some feature tests with capybara.

The trick is to change the RAILS_ROOT to point to the correct file.

For cucumber tests add the following into features/support/env.rb:

ENV["RAILS_ROOT"] ||= File.expand_path(File.dirname(__FILE__) + '/../../spec/dummy')

For rspec tests add the following into spec/rails_helper.rb:

ENV["RAILS_ROOT"] ||= File.expand_path(File.dirname(__FILE__) + '/dummy')

Ruby Keyword Arguments - mandatory params

If you do not set a default value for a keyword argument it will become mandatory and will raise an ArgumentError.

an example:

def mandatory_keyword(bar:)

def default_keyword(bar: nil)

and its test:

describe 'keyword_arguments' do
  it { expect{mandatory_keyword()}.to raise_error(ArgumentError) }
  it { expect(mandatory_keyword(bar: 'bar')).to eq('foo=bar') }

  it { expect(default_keyword()).to eq('foo=') }
  it { expect(default_keyword(bar: 'bar')).to eq('foo=bar') }

In case you don’t want this behavior you can always set a default to nil.

Cucumber step inception

I learned that you can call a cucumber step inside another one. Super cool!

Image a simple step like this:

Then /^I should see "(.*)"$/ do |text|
  expect(page).to have_content(text)

Now you have modals on your web app and you need to restrict this assertion to inside the modal.

So you can start to duplicate the step above to match the within modal and all the ones that could be reusable with modals.

Or you can create a new generic step that scope into the modal and calls your original step, such as:

And /^(.*?) within the modal$/ do |step_definition|
  within ".modal", visible: true do
    step step_definition

Now you can call both steps in your gherkin files:

Then I should see "Hello World!"


Then I should see "Hello World!" within the modal

Just be careful with generic and reusable steps. The idea is to help developers and not confuse them.

reference: Cucumber wiki - call step from step definition

h/t Taylor Mock

Capybara's RackTest driver limitation

By default, if you click a link through Capybara and it takes you into an external site, the current_url will work fine, but the content on the page does not change.

RackTest is the Capybara’s default driver and it has its limitations.

you cannot use the RackTest driver to test a remote application, or to access remote URLs

If you really need to do that know other drivers features and try them.

h/t by Nick Palaniuk

Ruby array shortcuts - "&:" and "&method"

Call a method on every items with &:

So this:

[:foo, :bar].each do |item|

Can be reduced to:

[:foo, :bar].each(&:to_s)

But, what if you want to call a method for each item in an array, and this item should be a parameter for this method?

Call a method with every items as a parameter with &method

So this:

[:foo, :bar].each do |item|

Can be reduced to:

[:foo, :bar].each(&method(:puts))

Fixing a past commit

To add some code changes to a past commit you can commit with the fixup option and then rebase it.

# add the code changes you want to add to the past commit
git add .

# get the git commit you want to add the changes and copy its reference
git log

# commit the changes with the options `fixup`
git commit --fixup <COMMIT_REF>

# rebase the commits to apply the fixup from one commit before the starter commit
git rebase -i --autosquash <COMMIT_REF>~1

This will open your editor (vim) with the rebase plan, so you can apply it.

Advanced Search with Textacular

Textacular exposes full text search capabilities from PostgreSQL, extending ActiveRecord with scopes making search easy and fun!

We wanted an advanced search, but that should also work as autocomplete.

So we end up using the gem textacular and the PostgreSql tsquery with the :* for prefixed searches

Game.advanced_search(title: 'street fi:*')

Thanks @mrmicahcooper!


Tabularize in VIM - changing whitespaces count

In order to tabularize texts based on comma character use the tabular vim plugin:

:Tabularize /,

This will by default add at least 1 whitespace to the left and exactly 1 whitespace to the right.

You can change this adding /l<NUM>r<NUM> to the end of command.

For 0 to the left and 1 to the right:

:Tabularize /,/l0r1


# original
resources :posts, path: 'blog_posts', only: [:index, :show, :create]
resources :comments, path: 'user_comments', only: [:index, :show]

# :Tabularize /,
resources :posts    , path: 'blog_posts'    , only: [:index , :show  , :create]
resources :comments , path: 'user_comments' , only: [:index , :show]

# :Tabularize /,/l0r1
resources :posts   , path: 'blog_posts'   , only: [:index, :show , :create]
resources :comments, path: 'user_comments', only: [:index, :show]


Difference betweent `to_a` and `to_ary`

  • to_a => called for explicit conversions
  • to_ary => called for implicit conversions


class Coordinates
  attr_reader :x, :y
  def initialize(x, y)
    @x, @y = x, y

  def to_a
    puts "to_a called"
    [x, y]

  def to_ary
    puts "to_ary called"
    [x, y]

coordinates =, 7)

puts "splat"
a = *coordinates
# => to_a called

puts "multiple assignment"
x, y = coordinates
# => to_ary called

puts "Implicit conversion into block params"
[coordinates].each { |(x, y)| puts x }
# => to_ary called

Go to file under the cursor in Vim

Let’s say in a file you reference another one, requiring that code. Vim has an very easy way to open the required (imported, loaded, etc) file. Great tip for adding external dependencies code.

Put the cursor in the file name you want to open and:


If you want to go back: <Ctrl> o.

To find the file Vim uses an option called path, and you can check your current path with:

:set path

So if you expect a file is not being found you can check the path and add values to it.

:set path+=some_special_folder/

Finally, as Vim looks for a lot of paths, it may find more than one, and gf will bring the first one. To get the second match, type g2f, for the third g3f and so on.

Also, check this article to restrict Vim options by file extensions and to add file suffixes.

Vim macro is amazing!

If you want to repeat a bunch of vim commands for running multiple times, record them in a macro and run wherever you want.

To record a macro you need:

  1. type q followed by any char: [a-z]
  2. type your vim commands
  3. type q again to finish recording

Finally, to run the macro that you just created type:

@ followed by the same char you chose to store the macro.

Ruby String Mutability

Until Ruby 3 we need to explicitly call the method freeze on literal strings, so they become immutable. And, if you have a lot of literal strings in a file, this will be very repetitive and verbose. In order to let our code cleaner there is a magic comment that can be added in the top of each file.

the magic:

# frozen_string_literal: true

And it is done, all literal string are frozen now :)


class Unfrozen
  def foo
class StringFrozen
  def foo
# frozen_string_literal: true
class ClassFrozen
  def foo

To test that:

require 'spec_helper'

describe 'Ruby String Mutability' do
  it 'validates string mutability' do
    expect( to be false
    expect( to be true
    expect( to be true
Randomized with seed 51265

Finished in 0.00179 seconds (files took 0.45396 seconds to load)
1 example, 0 failures