Class: Bible270::Generators::InstallGenerator

Inherits:
Rails::Generators::Base
  • Object
show all
Defined in:
lib/generators/bible270/install/install_generator.rb

Overview

Interactive installer:

bin/rails generate bible270:install

Walks through the mount point, authentication, initializers, routing, migrations and (optionally) running them. Every prompt has a default, so holding Enter gives a working install. Pass --defaults to skip the prompts entirely, or set any answer up front with a flag:

bin/rails generate bible270:install --defaults \
--mount-at=/daily-bread --providers=github,google_oauth2 \
--mailer-from=no-reply@example.org

Constant Summary collapse

MOUNT_LINE =
'mount Bible270::Engine, at: Bible270.config.mount_at'
DEFAULT_MOUNT =
'/daily-bread'
DEFAULT_PROVIDERS =
'github'
KNOWN_PROVIDERS =
{
  'github' => 'omniauth-github',
  'google_oauth2' => 'omniauth-google-oauth2',
  'facebook' => 'omniauth-facebook',
  'twitter' => 'omniauth-twitter',
  'linkedin' => 'omniauth-linkedin-oauth2',
  'gitlab' => 'omniauth-gitlab',
  'discord' => 'omniauth-discord',
  'apple' => 'omniauth-apple',
  'saml' => 'omniauth-saml',
  'openid_connect' => 'omniauth_openid_connect'
}.freeze

Instance Method Summary collapse

Instance Method Details

#add_routeObject

---- 8. routing -------------------------------------------------------



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/generators/bible270/install/install_generator.rb', line 192

def add_route
  if routes_mounted?
    say "  config/routes.rb already mounts Bible270::Engine — left as is.#{cms_order_hint}", :yellow
    return
  end

  route MOUNT_LINE

  # Thor's route action injects after the `Rails.application.routes.draw do`
  # sentinel and quietly does nothing if it can't find it (routes split
  # across files, an unusual layout, a missing file). Verify rather than
  # assume, since a silent miss leaves the plan unreachable.
  if routes_mounted?
    say "  Mounted in config/routes.rb.#{cms_order_hint}", :green
  else
    @route_failed = true
    say '  Could not edit config/routes.rb automatically.', :red
    say '  Add this line yourself, inside Rails.application.routes.draw:', :red
    say "    #{MOUNT_LINE}"
  end
end

#add_strategy_gemsObject

---- 4. strategy gems -------------------------------------------------



97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/generators/bible270/install/install_generator.rb', line 97

def add_strategy_gems
  return if @providers.empty?

  missing = @providers.filter_map { |p| KNOWN_PROVIDERS[p] }.reject { |g| gemfile_has?(g) }
  unknown = @providers.reject { |p| KNOWN_PROVIDERS.key?(p) }

  missing.each { |name| gem name }

  return if unknown.empty?

  say "  Unrecognised provider(s): #{unknown.join(', ')}. Add their strategy gems yourself.", :yellow
end

#ask_authenticationObject

---- 3. authentication ----------------------------------------------



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/generators/bible270/install/install_generator.rb', line 73

def ask_authentication
  say 'Authentication', :yellow
  say 'Readers must sign in to tick off readings and comment. Browsing is always public.'

  @email = decide(:email, 'Enable email sign-in (a one-time link, no password)?', true)
  @mailer_from = ask_mailer_from if @email

  @providers = decide_providers

  unless @email || @providers.any?
    say ''
    say '  No sign-in method chosen — readers would be unable to take part.', :red
    @email = confirm?('Enable email sign-in after all?', true)
  end

  # Covers the case where email was turned on by the question above.
  @mailer_from = ask_mailer_from if @email && @mailer_from.nil?

  report_auth_choice
  say ''
end

#ask_mount_pointObject

---- 2. where to mount ----------------------------------------------



59
60
61
62
63
64
65
66
67
68
69
# File 'lib/generators/bible270/install/install_generator.rb', line 59

def ask_mount_point
  @mount_at = normalize_mount(options[:mount_at] || prompt('Mount the plan at which path?', DEFAULT_MOUNT))

  until valid_mount?(@mount_at)
    say "  '#{@mount_at}' isn't a usable path.", :red
    @mount_at = normalize_mount(prompt('Mount the plan at which path?', DEFAULT_MOUNT))
  end

  say "  Plan will live at #{@mount_at}", :green
  say ''
end

#copy_migrationsObject

Migrations run before the initializers are written, so a problem in the generated config can never block the database work.



155
156
157
158
159
160
161
# File 'lib/generators/bible270/install/install_generator.rb', line 155

def copy_migrations
  return if skip_rails_commands?

  say ''
  say 'Copying migrations into db/migrate', :yellow
  rails_command 'bible270:install:migrations'
end

#create_engine_initializerObject

---- 7. initializers ---------------------------------------------------



180
181
182
# File 'lib/generators/bible270/install/install_generator.rb', line 180

def create_engine_initializer
  create_file 'config/initializers/bible270.rb', engine_initializer
end

#create_omniauth_initializerObject



184
185
186
187
188
# File 'lib/generators/bible270/install/install_generator.rb', line 184

def create_omniauth_initializer
  return if @providers.empty?

  create_file 'config/initializers/omniauth.rb', omniauth_initializer
end

#ensure_active_storageObject

---- 5. Active Storage ------------------------------------------------

Picture uploads need it. rails new enables the framework but the tables come from a migration that must be installed, so check for that migration rather than assuming a fresh app has it.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/generators/bible270/install/install_generator.rb', line 123

def ensure_active_storage
  return if skip_rails_commands?

  unless active_storage_enabled?
    @active_storage = :unavailable
    say ''
    say '  Active Storage is not enabled here, so picture uploads will be off.', :yellow
    say '  (Was this app generated with --skip-active-storage?)'
    return
  end

  if active_storage_installed?
    @active_storage = :present
    say '  Active Storage already installed.', :green
    return
  end

  unless decide(:active_storage, 'Install Active Storage, so readers can upload a picture?', true)
    @active_storage = :declined
    return
  end

  say ''
  say 'Installing Active Storage', :yellow
  rails_command 'active_storage:install'
  @active_storage = :installed
end

#greetObject

---- 1. greeting ----------------------------------------------------



49
50
51
52
53
54
55
# File 'lib/generators/bible270/install/install_generator.rb', line 49

def greet
  say ''
  say 'Installing bible270', :green
  say 'A 270-day Bible reading plan, mounted into this application.'
  say 'Press Enter to accept the [default] at any prompt.' unless quiet?
  say ''
end

#install_bundleObject



110
111
112
113
114
115
# File 'lib/generators/bible270/install/install_generator.rb', line 110

def install_bundle
  return if @providers.empty?

  @bundled = decide(:bundle, 'Run bundle install now (needed before the app can boot)?', true)
  run 'bundle install' if @bundled
end

#run_migrationsObject



163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/generators/bible270/install/install_generator.rb', line 163

def run_migrations
  if skip_rails_commands?
    @migrated = false
    return
  end

  @migrated = decide(:migrate, 'Run the database migrations now?', true)

  if @migrated
    rails_command 'db:migrate'
  else
    say '  Skipped. Run bin/rails db:migrate when ready.', :yellow
  end
end

#summaryObject

---- 9. what is left to do -------------------------------------------



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/generators/bible270/install/install_generator.rb', line 216

def summary
  say ''
  say 'bible270 installed.', :green
  say ''
  say "  Plan mounted at   #{@mount_at}"
  say "  Sign-in           #{auth_summary}"
  say "  Initializers      #{initializer_summary}"
  say "  Migrations        #{@migrated ? 'copied and run' : 'copied (not yet run)'}"
  say "  Picture uploads   #{active_storage_summary}"
  say ''

  remaining = outstanding_steps
  if remaining.any?
    say 'Still to do:', :yellow
    remaining.each_with_index { |step, i| say "  #{i + 1}. #{step}" }
    say ''
  end

  say "Start the server and visit #{@mount_at}", :green
  say ''
end