Bundler error: Downloading gem revealed dependencies not in the API

Recent Bundler (1.16.1) started complaining about missing dependencies in the Gemfile. This is due to a stricter handling of specifications (see attached link).

The error message looks like this:

Downloading example-gem-1.2.3 revealed dependencies not in the API or the lockfile (other-gem (< 3)).
Either installing with `--full-index` or running `bundle update example-gem` should fix the problem.

However, bundle install --full-index did not any better for me, and bundle update is not always a viable solution.

Easiest solut...

Generating test images on the fly via JavaScript or Ruby

When you need test images, instead of using services like lorempixel or placehold.it you may generate test images yourself.

Here we build a simple SVG image and wrap it into a data: URI. All browsers support SVG, and you can easily adjust it yourself.
Simply set it as an image's src attribute.

JavaScript

Simple solution in modern JavaScript, e.g. for use in the client's browser:

function svgUri(text) {
  let svg = `
    <svg wid...

RSpec: Expecting multiple calls of the same method

If the argument list is the same every time:

expect(object).to receive(:foo).with('argument').and_return('response 1', 'response 2')

If the argument list differs between invocations:

expect(object).to receive(:foo).with('argument 1').ordered.and_return('response 1')
expect(object).to receive(:foo).with('argument 2').ordered.and_return('response 2')

Running Rails 2 apps with modern MariaDB SQL server

You might have some trouble running a Rails LTS 2 app with MySQL 5.7.

If you don't want to hack Mysql 5.6 into your modern Ubuntu or use the MySQL sandbox, you might want to try MariaDB 10.x.

MariaDB 10.x should work with both old and new Rails applications.

[Switch to MariaDB](https://makandracards.com/makandra/468343-how-...

Understanding SQL compatibility modes in MySQL and MariaDB

MySQL and MariaDB have an SQL mode setting which changes how MySQL behaves.

The SQL mode value is comprised of multiple flags like "STRICT_TRANS_TABLES, NO_ZERO_IN_DATE". Each flag activates or disables a particular behavior.

The default SQL mode varies widly between versions of MySQL and MariaDB. In general, more recent versions of MySQL and MariaDB have stricter settings than older versions, and MySQL has stricter settings than the more liberal MariaDB.

If your app explodes ...

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
 ...

VNC browser disappears while typing

We often use the Then console step from spreewald in combination with geordi vnc from geordi to debug tests within a real browser. Sometimes when you type in the browser it suddenly disappears. You will only see a grey screen then.

This will always happen if you press the d key. Press the d key again and the browser will appear again.

Nested Spreewald patiently blocks are now patient

In Spreewald 1.10.4+, nested patiently blocks are now patient.

Here is an example:

patiently do
  outer_code
  patiently do
    inner_code
  end
end

On spreewald 1.11.2+ the inner block will wait for the full configured wait time (by default 5 seconds). The outer patiently block would now be out of time, but it will always be retried at least a second time. This behavior allows with_scope to be patient, and it must be patient, as explained below.

In versions 1.10.4 - 1.11.1, inner blocks would keep giving the ou...

How to: Solve gem loaded specs mutex

Use bundler > 1.15 to fix Gem::LOADED_SPECS_MUTEX (NameError).


Given the following project:

ruby -v
ruby 1.8.7

bundler -v
Bundler version 1.13.7

gem -v
1.8.30

rails -v
Rails 3.2.22.1

Running specs or features resulted in:

uninitialized constant Gem::LOADED_SPECS_MUTEX (NameError)

The previous settings described in Maximum version of Rubygems and Bundler for Ruby 1.8.7 and Rails 2.3 (even the rails version was rails 3.2 and not 2.3) seems not to work here, so I used (also described in the ca...

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.

  1. 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...
    

RSpec expects pending tests to fail

When flagging a spec that will be implemented later as pending, include a failing spec body or RSpec 3 will consider the pending test as failing.

The reasoning is: If the spec is flagged as pending but passes, it should not be pending. So these will fail:

it 'does something' do
  pending
end

it 'does something else' do
  pending
  expect(1).to eq(1)
end

The first case may be unexpected, if you just wanted to write down that something should eventually happen that will be implemented later.

Instead, ...

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 ...

Think twice before using application names in your variables and methods

I recently had fun with replacing a custom video plattform ("mycustomtv") in one of our applications. I learned a lot about naming stuff.

youtube_mycustomtv_chooser is a bad name for a directive.

Why?

  • if you add, for example, other video systems like vimeo, the name of the method either lies or will get longer.
  • if you replace one system, you will have to change the method and all of its occurrences (and you're very lucky if it is only one poorly named thing in your application)

What would be a better solution?

Abstract fro...

Katapult 0.4.0 released

Features

  • Generating a project README
  • Finally: Support for modelling associations between models in your application model! Example:
# lib/katapult/application_model.rb

model 'Cart' do |cart|
  cart.belongs_to 'User'
end

crud 'User' do |user|
  user.attr :fullname
end

Decide whether cronjobs should run on one or all servers

Understanding your type of cronjob

Some cronjobs must only run on a single server. E.g. when you run nightly batch operations on the database, it should probably run on a single server. Running it on multiple servers would likely result in deadlocks or corrupt data.

Some cronjobs must always run on all servers. E.g. starting a sidekiq process on reboot.

Configuring whenever

If not configured otherwise, cronjobs defined in whenever's `s...

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...

Katapult 0.3.0 released

Katapult 0.3.0 brings Rails 5 and Ruby 2.5 support with a new design, plus a ton of smaller features, fixes and improvements.

Features

  • Generating a Rails 5.1.4 app on Ruby 2.5.0
  • Dropped asset pipeline in favor of Webpacker
  • The generated application now has a sleek, simple design based on Bootstrap
  • Employing Unpoly
  • New application model DSL shortcut crud for "create a model and a web UI with crud actions"
  • The generated application model is now a transformable e...

Ruby: Using all? with empty collection

Enumerable#all? returns true for an empty collection. This totally makes sense but you have to think about it when making assumptions on relations which might be empty.

[].all?(&:will_never_be_called_here) => true

Example with empty collection

class Researcher < ActiveRecord::Base
  has_many :papers
end

class Paper
  validates :topic, inclusion: { in: ['computer_science', 'mathematics', 'economy'] }
end

Easy goal: Delete all researches who write onl...

Capybara: A step for finding images with filename and extension

This cucumber step is useful for testing an image (looking at the src of the image).

Then(/^I should see the image "([^"]*)"$/) do |filename_with_extension|
  expect(page).to have_css("img[src*='#{filename_with_extension}']")
end
Then I should see the image "placeholder.png"

Outline: Read more about how to test a uploaded file here, e.g. file downloads.

How to debug Rails autoloading

ActiveSupport::Dependencies takes care of auto-loading any classes in development. This is usually useful, but when you run into issues with the Rails autoloader, you should take a look at what it's doing.

For me this was useful in an "exciting" case of auto-loading classes inside a thread which caused the application to stop responding.

Rails 4.x

ActiveSupport::Dependencies includes logging support. It is easy to use:

ActiveSupport::Dependencies.logger = Rails.logger

Rails 5+

[Logging support was removed](https://github...

Carrierwave: Deleting files outside of forms

TL;DR Use user.update!(remove_avatar: true) to delete attachments outside of forms. This will have the same behavior as if you were in a form.


As you know, Carrierwave file attachments work by mounting an Uploader class to an attribute of the model. Though the database field holds the file name as string, calling the attribute will always return the uploader, no matter if a file is attached or not. (Side note: use #present? on the uploader to check if the file exists.)

class User < ApplicationRecord
  mount :avatar, ...

RSpec: How to check that an ActiveRecord relation contains exactly these elements

To check which elements an ActiveRecord relation contains use the contain_exactly matcher.

describe User do
  let!(:admin) { create(:user, role: 'admin') }
  let!(:customer) { create(:user, role: 'customer') }
  
  subject(:users) { User.where(role: 'admin') }
  
  # Recommended (The error output is most helpful)
  it { expect(users).to contain_exactly(admin) }
  
  # Other options
  it { expect(users).to eq([admin]) }
  it { expect(users.pluck(:id).to eq([admin.id]) }
end

In case you have an `ActiveRecord::AssociationRelati...

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]...

Heads up: RSpec-Mocks' #stub_const will define intermediate modules that have not been loaded yet

The issue: You are using stub_const to change a constant value for your test.

stub_const "SomeClass::CONST", 'test'

All of a sudden, tests fail with undefined method 'some_method' for #<SomeClass:0x00000000101433a8>.

The reason

When using stub_const before the Class containing the constant has been loaded, a module is automatically created with the name.

Since RSpec does no autoloading, it will create a SomeClass module by itself. This is arguably a good idea.

As a workaround, use stub_const in your Rails specs li...