doorkeeper-gem/doorkeeper

FactoryBot doesn't see Doorkeeper classes

slim1979 opened this issue ยท 21 comments

good day for everyone
when using doorkeeper-4.3.0, a have a problem with FactoryBot. He refused to see doorkeeper classes:

NameError:
  uninitialized constant Doorkeeper::AccessToken
NameError:
  uninitialized constant Doorkeeper::Application

and other
rollback to 4.2.6 solve this problem

Doorkeeper 4.3 uses FactoryBot, and Doorkeeper 4.2.6 uses FactoryGirl. What gem do you have?

Also, could you please provide your Gemfile.lock and spec_helper.rb?

i'm now use 4.2.6 with FactoryBot.

Gemfile.lock
GIT
  remote: https://github.com/thoughtbot/shoulda-matchers.git
  revision: 4b160bd19ecca7f97d7ac22dccd5fde9b0da5a9f
  branch: rails-5
  specs:
    shoulda-matchers (3.1.2)
      activesupport (>= 4.2.0)

GEM
  remote: https://rubygems.org/
  specs:
    actioncable (5.1.4)
      actionpack (= 5.1.4)
      nio4r (~> 2.0)
      websocket-driver (~> 0.6.1)
    actionmailer (5.1.4)
      actionpack (= 5.1.4)
      actionview (= 5.1.4)
      activejob (= 5.1.4)
      mail (~> 2.5, >= 2.5.4)
      rails-dom-testing (~> 2.0)
    actionpack (5.1.4)
      actionview (= 5.1.4)
      activesupport (= 5.1.4)
      rack (~> 2.0)
      rack-test (>= 0.6.3)
      rails-dom-testing (~> 2.0)
      rails-html-sanitizer (~> 1.0, >= 1.0.2)
    actionview (5.1.4)
      activesupport (= 5.1.4)
      builder (~> 3.1)
      erubi (~> 1.4)
      rails-dom-testing (~> 2.0)
      rails-html-sanitizer (~> 1.0, >= 1.0.3)
    activejob (5.1.4)
      activesupport (= 5.1.4)
      globalid (>= 0.3.6)
    activemodel (5.1.4)
      activesupport (= 5.1.4)
    activerecord (5.1.4)
      activemodel (= 5.1.4)
      activesupport (= 5.1.4)
      arel (~> 8.0)
    activesupport (5.1.4)
      concurrent-ruby (~> 1.0, >= 1.0.2)
      i18n (~> 0.7)
      minitest (~> 5.1)
      tzinfo (~> 1.1)
    addressable (2.5.2)
      public_suffix (>= 2.0.2, < 4.0)
    arel (8.0.0)
    bcrypt (3.1.11)
    bindex (0.5.0)
    builder (3.2.3)
    byebug (9.1.0)
    cancancan (2.1.3)
    capybara (2.17.0)
      addressable
      mini_mime (>= 0.1.3)
      nokogiri (>= 1.3.3)
      rack (>= 1.0.0)
      rack-test (>= 0.5.4)
      xpath (>= 2.0, < 4.0)
    capybara-email (2.5.0)
      capybara (~> 2.4)
      mail
    capybara-webkit (1.1.0)
      capybara (~> 2.0, >= 2.0.2)
      json
    carrierwave (1.2.2)
      activemodel (>= 4.0.0)
      activesupport (>= 4.0.0)
      mime-types (>= 1.16)
    cliver (0.3.2)
    coderay (1.1.2)
    coffee-rails (4.2.2)
      coffee-script (>= 2.2.0)
      railties (>= 4.0.0)
    coffee-script (2.4.1)
      coffee-script-source
      execjs
    coffee-script-source (1.12.2)
    commonjs (0.2.7)
    concurrent-ruby (1.0.5)
    crass (1.0.3)
    database_cleaner (1.6.2)
    devise (4.4.0)
      bcrypt (~> 3.0)
      orm_adapter (~> 0.1)
      railties (>= 4.1.0, < 5.2)
      responders
      warden (~> 1.2.3)
    diff-lcs (1.3)
    doorkeeper (4.2.6)
      railties (>= 4.2)
    erubi (1.7.0)
    execjs (2.7.0)
    factory_bot (4.8.2)
      activesupport (>= 3.0.0)
    factory_bot_rails (4.8.2)
      factory_bot (~> 4.8.2)
      railties (>= 3.0.0)
    faraday (0.12.2)
      multipart-post (>= 1.2, < 3)
    ffi (1.9.18)
    formatador (0.2.5)
    globalid (0.4.1)
      activesupport (>= 4.2.0)
    gon (6.2.0)
      actionpack (>= 3.0)
      multi_json
      request_store (>= 1.0)
    guard (2.14.2)
      formatador (>= 0.2.4)
      listen (>= 2.7, < 4.0)
      lumberjack (>= 1.0.12, < 2.0)
      nenv (~> 0.1)
      notiffany (~> 0.0)
      pry (>= 0.9.12)
      shellany (~> 0.0)
      thor (>= 0.18.1)
    guard-compat (1.2.1)
    guard-rspec (4.7.3)
      guard (~> 2.1)
      guard-compat (~> 1.1)
      rspec (>= 2.99.0, < 4.0)
    hashie (3.5.7)
    i18n (0.9.1)
      concurrent-ruby (~> 1.0)
    jbuilder (2.7.0)
      activesupport (>= 4.2.0)
      multi_json (>= 1.2)
    jquery-rails (4.3.1)
      rails-dom-testing (>= 1, < 3)
      railties (>= 4.2.0)
      thor (>= 0.14, < 2.0)
    jquery-ui-rails (6.0.1)
      railties (>= 3.2.16)
    json (2.1.0)
    jwt (1.5.6)
    launchy (2.4.3)
      addressable (~> 2.3)
    less (2.6.0)
      commonjs (~> 0.2.7)
    less-rails (2.8.0)
      actionpack (>= 4.0)
      less (~> 2.6.0)
      sprockets (> 2, < 4)
      tilt
    letter_opener (1.4.1)
      launchy (~> 2.2)
    libv8 (3.16.14.19)
    listen (3.1.5)
      rb-fsevent (~> 0.9, >= 0.9.4)
      rb-inotify (~> 0.9, >= 0.9.7)
      ruby_dep (~> 1.2)
    loofah (2.1.1)
      crass (~> 1.0.2)
      nokogiri (>= 1.5.9)
    lumberjack (1.0.12)
    mail (2.7.0)
      mini_mime (>= 0.1.1)
    method_source (0.9.0)
    mime-types (3.1)
      mime-types-data (~> 3.2015)
    mime-types-data (3.2016.0521)
    mini_mime (1.0.0)
    mini_portile2 (2.3.0)
    minitest (5.11.1)
    multi_json (1.13.1)
    multi_xml (0.6.0)
    multipart-post (2.0.0)
    nenv (0.3.0)
    nested_form (0.3.2)
    nio4r (2.2.0)
    nokogiri (1.8.1)
      mini_portile2 (~> 2.3.0)
    notiffany (0.1.1)
      nenv (~> 0.1)
      shellany (~> 0.0)
    oauth (0.5.4)
    oauth2 (1.4.0)
      faraday (>= 0.8, < 0.13)
      jwt (~> 1.0)
      multi_json (~> 1.3)
      multi_xml (~> 0.5)
      rack (>= 1.2, < 3)
    omniauth (1.8.1)
      hashie (>= 3.4.6, < 3.6.0)
      rack (>= 1.6.2, < 3)
    omniauth-facebook (4.0.0)
      omniauth-oauth2 (~> 1.2)
    omniauth-oauth (1.1.0)
      oauth
      omniauth (~> 1.0)
    omniauth-oauth2 (1.5.0)
      oauth2 (~> 1.1)
      omniauth (~> 1.2)
    omniauth-twitter (1.4.0)
      omniauth-oauth (~> 1.1)
      rack
    orm_adapter (0.5.0)
    pg (0.21.0)
    poltergeist (1.17.0)
      capybara (~> 2.1)
      cliver (~> 0.3.1)
      websocket-driver (>= 0.2.0)
    pry (0.11.3)
      coderay (~> 1.1.0)
      method_source (~> 0.9.0)
    pry-byebug (3.5.1)
      byebug (~> 9.1)
      pry (~> 0.10)
    pry-rails (0.3.6)
      pry (>= 0.10.4)
    public_suffix (3.0.1)
    puma (3.11.0)
    rack (2.0.3)
    rack-test (0.8.2)
      rack (>= 1.0, < 3)
    rails (5.1.4)
      actioncable (= 5.1.4)
      actionmailer (= 5.1.4)
      actionpack (= 5.1.4)
      actionview (= 5.1.4)
      activejob (= 5.1.4)
      activemodel (= 5.1.4)
      activerecord (= 5.1.4)
      activesupport (= 5.1.4)
      bundler (>= 1.3.0)
      railties (= 5.1.4)
      sprockets-rails (>= 2.0.0)
    rails-controller-testing (1.0.2)
      actionpack (~> 5.x, >= 5.0.1)
      actionview (~> 5.x, >= 5.0.1)
      activesupport (~> 5.x)
    rails-dom-testing (2.0.3)
      activesupport (>= 4.2.0)
      nokogiri (>= 1.6)
    rails-html-sanitizer (1.0.3)
      loofah (~> 2.0)
    railties (5.1.4)
      actionpack (= 5.1.4)
      activesupport (= 5.1.4)
      method_source
      rake (>= 0.8.7)
      thor (>= 0.18.1, < 2.0)
    rake (12.3.0)
    rb-fsevent (0.10.2)
    rb-inotify (0.9.10)
      ffi (>= 0.5.0, < 2)
    ref (2.0.0)
    remotipart (1.3.1)
    request_store (1.4.0)
      rack (>= 1.4)
    responders (2.4.0)
      actionpack (>= 4.2.0, < 5.3)
      railties (>= 4.2.0, < 5.3)
    rspec (3.7.0)
      rspec-core (~> 3.7.0)
      rspec-expectations (~> 3.7.0)
      rspec-mocks (~> 3.7.0)
    rspec-core (3.7.1)
      rspec-support (~> 3.7.0)
    rspec-expectations (3.7.0)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (~> 3.7.0)
    rspec-mocks (3.7.0)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (~> 3.7.0)
    rspec-rails (3.7.2)
      actionpack (>= 3.0)
      activesupport (>= 3.0)
      railties (>= 3.0)
      rspec-core (~> 3.7.0)
      rspec-expectations (~> 3.7.0)
      rspec-mocks (~> 3.7.0)
      rspec-support (~> 3.7.0)
    rspec-support (3.7.0)
    ruby_dep (1.5.0)
    sass (3.5.5)
      sass-listen (~> 4.0.0)
    sass-listen (4.0.0)
      rb-fsevent (~> 0.9, >= 0.9.4)
      rb-inotify (~> 0.9, >= 0.9.7)
    sass-rails (5.0.7)
      railties (>= 4.0.0, < 6)
      sass (~> 3.1)
      sprockets (>= 2.8, < 4.0)
      sprockets-rails (>= 2.0, < 4.0)
      tilt (>= 1.1, < 3)
    shellany (0.0.1)
    skim (0.10.0)
      coffee-script
      coffee-script-source (>= 1.2.0)
      slim (>= 3.0)
      sprockets (>= 2, < 4)
    slim (3.0.9)
      temple (>= 0.7.6, < 0.9)
      tilt (>= 1.3.3, < 2.1)
    slim-rails (3.1.3)
      actionpack (>= 3.1)
      railties (>= 3.1)
      slim (~> 3.0)
    spring (2.0.2)
      activesupport (>= 4.2)
    spring-commands-rspec (1.0.4)
      spring (>= 0.9.1)
    spring-watcher-listen (2.0.1)
      listen (>= 2.7, < 4.0)
      spring (>= 1.2, < 3.0)
    sprockets (3.6.3)
      concurrent-ruby (~> 1.0)
      rack (> 1, < 3)
    sprockets-rails (3.2.1)
      actionpack (>= 4.0)
      activesupport (>= 4.0)
      sprockets (>= 3.0.0)
    temple (0.8.0)
    therubyracer (0.12.3)
      libv8 (~> 3.16.14.15)
      ref
    thor (0.20.0)
    thread_safe (0.3.6)
    tilt (2.0.8)
    turbolinks (5.1.0)
      turbolinks-source (~> 5.1)
    turbolinks-source (5.1.0)
    twitter-bootstrap-rails (4.0.0)
      actionpack (~> 5.0, >= 5.0.1)
      execjs (~> 2.7)
      less-rails (~> 2.8, >= 2.8.0)
      railties (~> 5.0, >= 5.0.1)
    tzinfo (1.2.4)
      thread_safe (~> 0.1)
    uglifier (4.1.3)
      execjs (>= 0.3.0, < 3)
    warden (1.2.7)
      rack (>= 1.0)
    web-console (3.5.1)
      actionview (>= 5.0)
      activemodel (>= 5.0)
      bindex (>= 0.4.0)
      railties (>= 5.0)
    websocket-driver (0.6.5)
      websocket-extensions (>= 0.1.0)
    websocket-extensions (0.1.3)
    xpath (3.0.0)
      nokogiri (~> 1.8)

PLATFORMS
  ruby

DEPENDENCIES
  cancancan
  capybara (~> 2.13)
  capybara-email
  capybara-webkit
  carrierwave
  coffee-rails (~> 4.2)
  database_cleaner
  devise
  doorkeeper (= 4.2.6)
  factory_bot_rails
  gon
  guard-rspec
  jbuilder (~> 2.5)
  jquery-rails
  jquery-ui-rails
  launchy
  less-rails
  letter_opener
  listen (>= 3.0.5, < 3.2)
  nested_form
  omniauth
  omniauth-facebook
  omniauth-twitter
  pg (~> 0.18)
  poltergeist
  pry-byebug
  pry-rails
  puma (~> 3.7)
  rails (~> 5.1.4)
  rails-controller-testing
  remotipart
  responders
  rspec-rails
  sass-rails (~> 5.0)
  shoulda-matchers!
  skim
  slim-rails
  spring
  spring-commands-rspec
  spring-watcher-listen (~> 2.0.0)
  sprockets (= 3.6.3)
  therubyracer
  turbolinks (~> 5)
  twitter-bootstrap-rails
  tzinfo-data
  uglifier (>= 1.3.0)
  web-console (>= 3.3.0)

BUNDLED WITH
   1.16.0.pre.3
spec_helper.rb
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# The generated `.rspec` file contains `--require spec_helper` which will cause
# this file to always be loaded, without a need to explicitly require it in any
# files.
#
# Given that it is always loaded, you are encouraged to keep this file as
# light-weight as possible. Requiring heavyweight dependencies from this file
# will add to the boot time of your test suite on EVERY test run, even for an
# individual file that may not need all of that loaded. Instead, consider making
# a separate helper file that requires the additional dependencies and performs
# the additional setup, and require it from the spec files that actually need
# it.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
  # rspec-expectations config goes here. You can use an alternate
  # assertion/expectation library such as wrong or the stdlib/minitest
  # assertions if you prefer.
  config.expect_with :rspec do |expectations|
    # This option will default to `true` in RSpec 4. It makes the `description`
    # and `failure_message` of custom matchers include text for helper methods
    # defined using `chain`, e.g.:
    #     be_bigger_than(2).and_smaller_than(4).description
    #     # => "be bigger than 2 and smaller than 4"
    # ...rather than:
    #     # => "be bigger than 2"
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
  end

  # rspec-mocks config goes here. You can use an alternate test double
  # library (such as bogus or mocha) by changing the `mock_with` option here.
  config.mock_with :rspec do |mocks|
    # Prevents you from mocking or stubbing a method that does not exist on
    # a real object. This is generally recommended, and will default to
    # `true` in RSpec 4.
    mocks.verify_partial_doubles = true
  end

  # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
  # have no way to turn it off -- the option exists only for backwards
  # compatibility in RSpec 3). It causes shared context metadata to be
  # inherited by the metadata hash of host groups and examples, rather than
  # triggering implicit auto-inclusion in groups with matching metadata.
  config.shared_context_metadata_behavior = :apply_to_host_groups

# The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content.
=begin
  # This allows you to limit a spec run to individual examples or groups
  # you care about by tagging them with `:focus` metadata. When nothing
  # is tagged with `:focus`, all examples get run. RSpec also provides
  # aliases for `it`, `describe`, and `context` that include `:focus`
  # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
  config.filter_run_when_matching :focus

  # Allows RSpec to persist some state between runs in order to support
  # the `--only-failures` and `--next-failure` CLI options. We recommend
  # you configure your source control system to ignore this file.
  config.example_status_persistence_file_path = "spec/examples.txt"

  # Limits the available syntax to the non-monkey patched syntax that is
  # recommended. For more details, see:
  #   - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
  #   - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
  #   - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
  config.disable_monkey_patching!

  # Many RSpec users commonly either run the entire suite or an individual
  # file, and it's useful to allow more verbose output when running an
  # individual spec file.
  if config.files_to_run.one?
    # Use the documentation formatter for detailed output,
    # unless a formatter has already been configured
    # (e.g. via a command-line flag).
    config.default_formatter = "doc"
  end

  # Print the 10 slowest examples and example groups at the
  # end of the spec run, to help surface which specs are running
  # particularly slow.
  config.profile_examples = 10

  # Run specs in random order to surface order dependencies. If you find an
  # order dependency and want to debug it, you can fix the order by providing
  # the seed, which is printed after each run.
  #     --seed 1234
  config.order = :random

  # Seed global randomization in this process using the `--seed` CLI option.
  # Setting this allows you to use `--seed` to deterministically reproduce
  # test failures related to randomization by passing the same `--seed` value
  # as the one that triggered the failure.
  Kernel.srand config.seed
=end
end

And what about yhe factories?

Do you have

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods

  config.before(:suite) do
    FactoryBot.find_definitions
  end
end

?

i got

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods

in rails_helper.rb

I don't have that record:

config.before(:suite) do
FactoryBot.find_definitions
end

will this solve problem?

It loads factories for the gem and suggested by the official docs. I will try to reproduce the error a little bit later

must say, that doesnt work for me

It is a brandly new app or some legacy project?

Did you do rails generate doorkeeper:install ? Without Doorkeeper initializer it's models wouldn't be loaded.

I created a new project with next Gemfile:

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.3.1'

gem 'rails', '~> 5.2.0.beta2'
gem 'sqlite3'
gem 'puma', '~> 3.11'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'duktape'
gem 'doorkeeper', '~> 4.3'

group :development, :test do
  gem 'factory_bot_rails'
  gem 'rspec-rails', '~> 3.7'
end

group :development do
  gem 'web-console', '>= 3.3.0'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
  • Default Doorkeeper initilizer.

  • Factory:

# spec/factories/access_token.rb
FactoryBot.define do
  factory :access_token, class: Doorkeeper::AccessToken do
  end
end

And spec:

# spec/models/token_spec.rb
require 'rails_helper'

RSpec.describe 'token' do 
   it 'test' do
      expect(FactoryBot.build(:access_token)).to be_valid
   end
end

Everything is OK.

default

It is a brandly new app or some legacy project?

educational app

Did you do rails generate doorkeeper:install?

yes, i did. i have config/initializers/doorkeeper.rb

Everything is OK.

lucky you)
i can provide link to branch, which contain broken code. maybe, this can help?

Yep, it would be great if you have this one public!

@slim1979 yes, I see the problem, but can't find the source of it. As I can see from the trace debugging, ActiveSupport lazy hooks are not invoked, so models didn't loaded. Can't find the reason why it is happens, maybe some initializer / configuration / gem side effects..

If you will add ActiveRecord::Base.inspect as a first line of access_tokens factory, then it will work :\

Analyzed trace and it looks like in your case AS doesn't load dependencies or do it in other way https://gist.github.com/nbulaj/5ce408c58a6fde239b8e71653ce5d568

I was using Rails 5.2, and it uses ActiveStorage that depends on ActiveRecord. So it loads AR somehow and my tests were green. If I remove config.active_storage.service = :test from the config/environments/test.rb - then I got your error O_o

my mentor thinking, that this is about lazy_load helper, which will load all only if AS initialized, but factories loads earlier and this cause a problem

He is right about the helpers. Doorkeeper models must be loaded at the time when ActiveRecord are loaded using ActiveSupport lazy hooks (in this case we can configure some AR options before Doorkeeper models would be loaded). ActiveRecord::Base has autoloading and would be initialized only on first call. When tests are invoked, factories run before the ActiveRecord loaded (because nobody touches ActiveRecord::Base, so it is not loaded yet), so this is why we get this error (on this moment Doorkeeper::AccessToken and other models still not required).

I'l try to investigate the problem and solve it for 4.3.1 release.

Hi @slim1979 . The problem is in factory_bot_rails gem. It has an railtie that tries to find factory definitions (and load them) after engine initialization, and this cause the error because models is not loaded yet, the same as ActiveRecord.

To solve this problem you can replace factory_bot_rails gem with just factory_bot and everything will work (I tried for your branch).

Related issue exists on the factory_bot_rails gem itself thoughtbot/factory_bot_rails#134 , but it is closed and nobody seems to fix it.

P.S. I recommend you to move require statements in your rails_helper.rb (like 'capybara/rspec' or 'shoulda/matchers') under require 'rspec/rails' as it suggested by the official RSpec gem docs (you can even find the corresponding comment # Add additional requires below this line. Rails is not loaded until this point!). And you don't need to require 'doorkeeper' as it would be loaded by your app (require File.expand_path('../../config/environment', __FILE__))

will try it later.... thanks a lot for your investigation)

@slim1979 any news here?

@nbulaj, hi there. no, nothing new... i had an conversation with my mentor about this situation and he told me, what this will never been solved by any sides, because noone want to change its product, as saying. this is noone bug, just incompatibility. i willn't change my doorkeeper version right now, because it doesn't make sense for me. maybe, someone will see problem solvation in this issue... i will be glad

So because of it is not a bug in Doorkeeper itself I will close this issue now. The only solution I see (for Doorkeeper) is to manually trigger AR::Base (before factory bot rails initializer), but you are right - I don't think I would do this for some testing gem.

As factory_bot_rails is just about 8 lines of code - I don't think it is a big problem to replace it with native factory_bot. But if somebody will see this issue and want to propose some solution to fix it - feel free to send a PR :)

I tried this, will work for you until this issue is solved on factory_bot_rails. Create the file lib/factory_bot_rails/railtie.rb on your project - we're actually copying the current railtie contents and modifying one line:

require 'factory_bot'
require 'factory_bot_rails/generator'
require 'rails'

module FactoryBot
  class Railtie < Rails::Railtie

    initializer "factory_bot.set_fixture_replacement" do
      FactoryBotRails::Generator.new(config).run
    end

    initializer "factory_bot.set_factory_paths" do
      FactoryBot.definition_file_paths = [
        Rails.root.join('factories'),
        Rails.root.join('test', 'factories'),
        Rails.root.join('spec', 'factories')
      ]
    end

    config.after_initialize do
      # This line is the one that fixes it:
      ActiveSupport.on_load(:active_record) { FactoryBot.find_definitions }

      if defined?(Spring)
        Spring.after_fork { FactoryBot.reload }
      end
    end
  end
end

I'll post this as a PR on Factory Bot Rails repo

I was able to get around this issue by putting quotes around the class name when defining the factory:

factory :access_token, class: 'Doorkeeper::AccessToken' do
  ...
end

High five to @sman591 for this excellent commit message:

As described in doorkeeper-gem#1043,
factories defined by doorkeeper are unable to be loaded by host apps
using the `factory_bot_rails` gem (receiving errors such as
`uninitialized constant Doorkeeper::AccessGrant`)

Documentation for factory_bot was later added to explain an easy fix for
this: instead of defining the factory's `class: ` with a named constant,
wrap the constant in a string. By doing so, the constant isn't evaluated
until the factory actually runs, at which point the `Doorkeeper::` models
have all been loaded.