Bundler + Rails: realpath expand_path and symlinked vendor/bundle cause ‘already loaded’ errors

Symlinked vendor/bundle results in double load errors since:

  • rails adds the realpath of each engines lib (and various other folders) to the $LOAD_PATH
  • bundler adds the symlinked version to the $LOAD_PATH
  • require_relative uses the realpath

which looks like: `already initialized constant Arturo::Middleware::MISSING_FEATURE_ERROR`

Reproduce:

  • bundle install –path vendor/bundle
  • mv vendor/bundle tmp
  • cd vendor && ln -s ../tmp/bundle bundle
  • enable eager_load + preload_frameworks in config/environment/development.rb
  • rails runner 1

Ruby issue

Patch:

require 'bundler/setup'

# https://grosser.it/2017/08/19/bundler-rails-realpath-expand_path-and-symlinked-vendorbundle-cause-already-loaded-errors
linked_bundle = File.expand_path("vendor/bundle")
real_bundle = File.realpath("vendor/bundle")
$LOAD_PATH.each_with_index do |path, i|
  $LOAD_PATH[i] = path.sub(linked_bundle, real_bundle)
end

Rails 5.1 do not compile asset in test vs asset is not present in the asset pipeline

We don’t want to compile assets during test runs, since that is slow, but we also don’t want the asset pipeline to fail because assets are missing.

This will not work if you plan on doing javascript integration tests, but everything else should work fine.

Rails 5.1 added a flag for this which prints deprecations and will be removed in rails 5.2 so that is not a elegant solution either.

config.assets.unknown_asset_fallback = true

So we are now using this fix to fake assets being available!:

# config/environments/test.rb
# make our tests fast by avoiding asset compilation
# but do not raise when assets are not compiled either
Rails.application.config.assets.compile = false
Sprockets::Rails::Helper.prepend(Module.new do
  def resolve_asset_path(path, *)
    super || path
  end
end)

Ruby on Kubernetes: Newrelic

– Report each environment as separate app
– Report namespace so we can track down where misbehaving pods live

    # config/application.rb (not in initializers)
    if ENV['POD_NAMESPACE'] # on kubernetes
      # report each env into a separate project
      NewRelic::Agent::Configuration::Manager.class_eval do
        undef app_names
        def app_names
          name = ENV.fetch('NEW_RELIC_APP_NAME')
          name += " #{Rails.env}" unless Rails.env.production?
          [name]
        end
      end

      # report namespace so we can track down where a troublesome pod lives
      # newrelic_rpm 3.18.0+ has a NEW_RELIC_PROCESS_HOST_DISPLAY_NAME setting which is supposed to do that, but did not work.
      class << NewRelic::Agent::Hostname
        def get
          "#{ENV.fetch('POD_NAME')}.#{ENV.fetch('POD_NAMESPACE')}"
        end
      end
    end