From 6616e130239a818583f58dd038b7a80f2b4ff4d8 Mon Sep 17 00:00:00 2001 From: Jared Beck Date: Thu, 18 Mar 2021 01:18:32 -0400 Subject: [PATCH] Document and make explicit certain "boot" order - Ensure that the "paper_trail" initializer happens before the end-user's initializers (in their app's config/initializers) - Document the boot process of dummy_app and how it differs from a conventional app. This is a direct continuation of fc6c5f6, which was a collaboration between Eric and myself, but I choose to make this a separate commit, partly for vanity, and partly on the faint hope that it might make review easier. --- lib/paper_trail/frameworks/rails/railtie.rb | 12 +++--- spec/dummy_app/config/application.rb | 12 +++--- spec/dummy_app/config/boot.rb | 17 +-------- spec/spec_helper.rb | 41 ++++++++++++++++++--- 4 files changed, 50 insertions(+), 32 deletions(-) diff --git a/lib/paper_trail/frameworks/rails/railtie.rb b/lib/paper_trail/frameworks/rails/railtie.rb index 3b7fc6d4..2d93672b 100644 --- a/lib/paper_trail/frameworks/rails/railtie.rb +++ b/lib/paper_trail/frameworks/rails/railtie.rb @@ -2,13 +2,15 @@ module PaperTrail # Represents code to load within Rails framework. See documentation in - # `rails/railtie.rb`. + # `railties/lib/rails/railtie.rb`. # @api private class Railtie < ::Rails::Railtie - # PaperTrail only has one initializer. The `initializer` method can take a - # `before:` or `after:` argument, but that's only relevant for railties with - # more than one initializer. - initializer "paper_trail" do + # PaperTrail only has one initializer. + # + # We specify `before: "load_config_initializers"` to ensure that the PT + # initializer happens before "app initializers" (those defined in + # the app's `config/initalizers`). + initializer "paper_trail", before: "load_config_initializers" do # `on_load` is a "lazy load hook". It "declares a block that will be # executed when a Rails component is fully loaded". (See # `active_support/lazy_load_hooks.rb`) diff --git a/spec/dummy_app/config/application.rb b/spec/dummy_app/config/application.rb index 1626dd27..6f4de37d 100644 --- a/spec/dummy_app/config/application.rb +++ b/spec/dummy_app/config/application.rb @@ -2,12 +2,14 @@ require File.expand_path("boot", __dir__) -# Pick the frameworks you want: -require "active_record/railtie" -require "action_controller/railtie" +# Here a conventional app would load the Rails components it needs, but we have +# already loaded these in our spec_helper. +# require "active_record/railtie" +# require "action_controller/railtie" -Bundler.require(:default, Rails.env) -require "paper_trail" +# Here a conventional app would require gems, but again, we have already loaded +# these in our spec_helper. +# Bundler.require(:default, Rails.env) module Dummy class Application < Rails::Application diff --git a/spec/dummy_app/config/boot.rb b/spec/dummy_app/config/boot.rb index e7d5b0b3..23f3d709 100644 --- a/spec/dummy_app/config/boot.rb +++ b/spec/dummy_app/config/boot.rb @@ -1,18 +1,3 @@ # frozen_string_literal: true -require "rubygems" - -# When you run rake locally (not on travis) in this dummy app, set the -# BUNDLE_GEMFILE env. variable to ensure that the correct version of AR is used -# for e.g. migrations. See examples in CONTRIBUTING.md. -unless ENV.key?("BUNDLE_GEMFILE") - gemfile = File.expand_path("../../../Gemfile", __dir__) - if File.exist?(gemfile) - puts "Booting PT test dummy app: Using gemfile: #{gemfile}" - ENV["BUNDLE_GEMFILE"] = gemfile - end -end -require "bundler" -Bundler.setup - -$LOAD_PATH.unshift(File.expand_path("../../../lib", __dir__)) +# Unlike a conventional Rails app, our "dummy" app is booted by our spec_helper. diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6fce6544..e6e44a62 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -30,16 +30,45 @@ RSpec.configure do |config| Kernel.srand config.seed end -require File.expand_path("dummy_app/config/environment", __dir__) -require "rspec/rails" -require "paper_trail/frameworks/rspec" -require "ffaker" +# At this point, totally isolated unit tests could be run. But the PT test suite +# also has "integration" tests, via a "dummy" Rails app. Here, we boot that +# "dummy" app. The following process follows the same order, roughly, as a +# conventional Rails app. +# +# In the past, this boot process was partially implemented here, and partially +# in `dummy_app/config/*`. By consolidating it here, +# +# - It can better be understood, and documented in one place +# - It can more closely resememble a conventional app boot. For example, loading +# gems (like rspec-rails) _before_ loading the app. -# Migrate +# First, `config/boot.rb` would add gems to $LOAD_PATH. +Bundler.setup + +# Then, the chosen components of Rails would be loaded. In our case, we only +# test with AR and AC. +require "active_record/railtie" +require "action_controller/railtie" + +# Then, gems are loaded. In a conventional Rails app, this would be done with +# by the `Bundler.require` in `config/application.rb`. +require "paper_trail" +require "ffaker" +require "rspec/rails" +require "rails-controller-testing" + +# Now we can load our dummy app. Its boot process does not perfectly match a +# conventional Rails app, but it's what we were able to fit in our test suite. +require File.expand_path("dummy_app/config/environment", __dir__) + +# Now that AR has a connection pool, we can migrate the database. require_relative "support/paper_trail_spec_migrator" ::PaperTrailSpecMigrator.new.migrate +# This final section reselmbles what might be dummy_app's spec_helper, if it +# had one. +require "paper_trail/frameworks/rspec" RSpec.configure do |config| - config.fixture_path = "#{::Rails.root}/spec/fixtures" + config.fixture_path = nil # we use factories, not fixtures config.use_transactional_fixtures = true end