Class: Jets::Application

Inherits:
Engine show all
Defined in:
lib/jets/application.rb,
lib/jets/application/finisher.rb,
lib/jets/application/bootstrap.rb,
lib/jets/application/configuration.rb,
lib/jets/application/routes_reloader.rb,
lib/jets/application/default_middleware_stack.rb

Defined Under Namespace

Modules: Bootstrap, Finisher Classes: Configuration, DefaultMiddlewareStack, RoutesReloader

Constant Summary collapse

INITIAL_VARIABLES =
[:config, :turbines, :routes_reloader, :reloaders,
:routes, :helpers, :app_env_config, :secrets]

Constants inherited from Turbine

Turbine::ABSTRACT_TURBINES

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Engine

#app, #call, endpoint, #endpoint, find, #helpers, isolate_namespace, #load_console, #load_generators, #load_runner, #load_seed, #load_server, #load_tasks, #routes, #routes?, #turbines

Methods inherited from Turbine

<=>, abstract_turbine?, #configure, configure, console, generators, #inspect, on_exception, #on_exception_blocks, rake_tasks, runner, server, subclasses, turbine_name, #turbine_namespace

Methods included from Initializable

included, #run_initializers

Constructor Details

#initialize(initial_variable_values = {}, &block) ⇒ Application

Returns a new instance of Application.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/jets/application.rb', line 51

def initialize(initial_variable_values = {}, &block)
  super()
  @initialized       = false
  @reloaders         = []
  @routes_reloader   = nil
  @app_env_config    = nil
  @ordered_turbines  = nil
  @turbines          = nil
  @message_verifiers = {}
  @ran_load_hooks    = false

  @executor          = Class.new(ActiveSupport::Executor)
  @reloader          = Class.new(ActiveSupport::Reloader)
  @reloader.executor = @executor

  @autoloaders = Jets::Autoloaders.new

  # are these actually used?
  @initial_variable_values = initial_variable_values
  @block = block
end

Instance Attribute Details

#assetsObject

Returns the value of attribute assets.



42
43
44
# File 'lib/jets/application.rb', line 42

def assets
  @assets
end

#autoloadersObject (readonly)

Returns the value of attribute autoloaders.



44
45
46
# File 'lib/jets/application.rb', line 44

def autoloaders
  @autoloaders
end

#configObject

:nodoc:



328
329
330
# File 'lib/jets/application.rb', line 328

def config # :nodoc:
  @config ||= Application::Configuration.new(self.class.find_root(self.class.called_from))
end

#credentialsObject

Returns an ActiveSupport::EncryptedConfiguration instance for the credentials file specified by config.credentials.content_path.

By default, config.credentials.content_path will point to either config/credentials/#{environment}.yml.enc for the current environment (for example, config/credentials/production.yml.enc for the production environment), or config/credentials.yml.enc if that file does not exist.

The encryption key is taken from either ENV["JETS_MASTER_KEY"], or from the file specified by config.credentials.key_path. By default, config.credentials.key_path will point to either config/credentials/#{environment}.key for the current environment, or config/master.key if that file does not exist.



384
385
386
# File 'lib/jets/application.rb', line 384

def credentials
  @credentials ||= encrypted(config.credentials.content_path, key_path: config.credentials.key_path)
end

#executorObject (readonly)

Returns the value of attribute executor.



44
45
46
# File 'lib/jets/application.rb', line 44

def executor
  @executor
end

#reloaderObject (readonly)

Returns the value of attribute reloader.



44
45
46
# File 'lib/jets/application.rb', line 44

def reloader
  @reloader
end

#reloadersObject (readonly)

Returns the value of attribute reloaders.



44
45
46
# File 'lib/jets/application.rb', line 44

def reloaders
  @reloaders
end

#sandboxObject Also known as: sandbox?

Returns the value of attribute sandbox.



42
43
44
# File 'lib/jets/application.rb', line 42

def sandbox
  @sandbox
end

#secretsObject



334
335
336
337
338
339
340
341
342
343
344
345
346
# File 'lib/jets/application.rb', line 334

def secrets
  @secrets ||= begin
    secrets = ActiveSupport::OrderedOptions.new
    files = config.paths["config/secrets"].existent
    files = files.reject { |path| path.end_with?(".enc") } unless config.read_encrypted_secrets
    secrets.merge! Jets::Secrets.parse(files, env: Jets.env)

    # Fallback to config.secret_key_base if secrets.secret_key_base isn't set
    secrets.secret_key_base ||= config.secret_key_base

    secrets
  end
end

Class Method Details

.add_lib_to_load_path!(root) ⇒ Object

This method is called just after an application inherits from Jets::Application, allowing the developer to load classes in lib and use them during application configuration.

class MyApplication < Jets::Application
  require "my_backend" # in lib/my_backend
  config.i18n.backend = MyBackend
end

Notice this method takes into consideration the default root path. So if you are changing config.root inside your application definition or having a custom Jets application, you will need to add lib to $LOAD_PATH on your own in case you need to load files in lib/ during the application configuration as well.



284
285
286
287
288
289
# File 'lib/jets/application.rb', line 284

def self.add_lib_to_load_path!(root) # :nodoc:
  path = File.join root, "lib"
  if File.exist?(path) && !$LOAD_PATH.include?(path)
    $LOAD_PATH.unshift(path)
  end
end

.create(initial_variable_values = {}, &block) ⇒ Object



26
27
28
# File 'lib/jets/application.rb', line 26

def create(initial_variable_values = {}, &block)
  new(initial_variable_values, &block).run_load_hooks!
end

.find_root(from) ⇒ Object



30
31
32
# File 'lib/jets/application.rb', line 30

def find_root(from)
  find_root_with_flag "config.ru", from, Dir.pwd
end

.inherited(base) ⇒ Object



15
16
17
18
19
20
# File 'lib/jets/application.rb', line 15

def inherited(base)
  super
  Jets.app_class = base
  add_lib_to_load_path!(find_root(base.called_from))
  ActiveSupport.run_load_hooks(:before_configuration, base)
end

.instanceObject



22
23
24
# File 'lib/jets/application.rb', line 22

def instance
  super.run_load_hooks!
end

Instance Method Details

#awsObject

Added for Application::Configuration::Defaults



442
443
444
# File 'lib/jets/application.rb', line 442

def aws
  @aws ||= Jets::AwsInfo.new
end

#config_for(name, env: Jets.env) ⇒ Object

Convenience for loading config/foo.yml for the current Jets env.

Examples:

# config/exception_notification.yml:
production:
  url: http://127.0.0.1:8080
  namespace: my_app_production

development:
  url: http://localhost:3001
  namespace: my_app_development

# config/environments/production.rb
Jets.application.configure do
  config.middleware.use ExceptionNotifier, config_for(:exception_notification)
end

# You can also store configurations in a shared section which will be
# merged with the environment configuration

# config/example.yml
shared:
  foo:
    bar:
      baz: 1

development:
  foo:
    bar:
      qux: 2

# development environment
Jets.application.config_for(:example)[:foo][:bar]
# => { baz: 1, qux: 2 }


166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/jets/application.rb', line 166

def config_for(name, env: Jets.env)
  yaml = name.is_a?(Pathname) ? name : Pathname.new("#{paths["config"].existent.first}/#{name}.yml")

  if yaml.exist?
    require "erb"
    all_configs    = ActiveSupport::ConfigurationFile.parse(yaml).deep_symbolize_keys
    config, shared = all_configs[env.to_sym], all_configs[:shared]

    if shared
      config = {} if config.nil? && shared.is_a?(Hash)
      if config.is_a?(Hash) && shared.is_a?(Hash)
        config = shared.deep_merge(config)
      elsif config.nil?
        config = shared
      end
    end

    if config.is_a?(Hash)
      config = ActiveSupport::OrderedOptions.new.update(config)
    end

    config
  else
    raise "Could not load configuration. No such file - #{yaml}"
  end
end

#console(&blk) ⇒ Object

Sends any console called in the instance of a new application up to the console method defined in Jets::Turbine.



248
249
250
# File 'lib/jets/application.rb', line 248

def console(&blk)
  self.class.console(&blk)
end

#eager_load!Object

Eager loads the application code.



437
438
439
# File 'lib/jets/application.rb', line 437

def eager_load!
  Jets.autoloaders.each(&:eager_load)
end

#encrypted(path, key_path: "config/master.key", env_key: "JETS_MASTER_KEY") ⇒ Object

Returns an ActiveSupport::EncryptedConfiguration instance for an encrypted file. By default, the encryption key is taken from either ENV["JETS_MASTER_KEY"], or from the config/master.key file.

my_config = Jets.application.encrypted("config/my_config.enc")

my_config.read
# => "foo:\n  bar: 123\n"

my_config.foo.bar
# => 123

Encrypted files can be edited with the bin/jets encrypted:edit command. (See the output of bin/jets encrypted:edit --help for more information.)



403
404
405
406
407
408
409
410
# File 'lib/jets/application.rb', line 403

def encrypted(path, key_path: "config/master.key", env_key: "JETS_MASTER_KEY")
  ActiveSupport::EncryptedConfiguration.new(
    config_path: Jets.root.join(path),
    key_path: Jets.root.join(key_path),
    env_key: env_key,
    raise_if_missing_key: config.require_master_key
  )
end

#env_configObject

Stores some of the Jets initial environment parameters which will be used by middlewares and engines to configure themselves.



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/jets/application.rb', line 195

def env_config
  @app_env_config ||= super.merge(
      "action_dispatch.parameter_filter" => config.filter_parameters,
      "action_dispatch.redirect_filter" => config.filter_redirect,
      "action_dispatch.secret_key_base" => secret_key_base,
      "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions,
      "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local,
      "action_dispatch.log_rescued_responses" => config.action_dispatch.log_rescued_responses,
      "action_dispatch.logger" => Jets.logger,
      "action_dispatch.backtrace_cleaner" => Jets.backtrace_cleaner,
      "action_dispatch.key_generator" => key_generator,
      "action_dispatch.http_auth_salt" => config.action_dispatch.http_auth_salt,
      "action_dispatch.signed_cookie_salt" => config.action_dispatch.signed_cookie_salt,
      "action_dispatch.encrypted_cookie_salt" => config.action_dispatch.encrypted_cookie_salt,
      "action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt,
      "action_dispatch.authenticated_encrypted_cookie_salt" => config.action_dispatch.authenticated_encrypted_cookie_salt,
      "action_dispatch.use_authenticated_cookie_encryption" => config.action_dispatch.use_authenticated_cookie_encryption,
      "action_dispatch.encrypted_cookie_cipher" => config.action_dispatch.encrypted_cookie_cipher,
      "action_dispatch.signed_cookie_digest" => config.action_dispatch.signed_cookie_digest,
      "action_dispatch.cookies_serializer" => config.action_dispatch.cookies_serializer,
      "action_dispatch.cookies_digest" => config.action_dispatch.cookies_digest,
      "action_dispatch.cookies_rotations" => config.action_dispatch.cookies_rotations,
      "action_dispatch.cookies_same_site_protection" => coerce_same_site_protection(config.action_dispatch.cookies_same_site_protection),
      "action_dispatch.use_cookies_with_metadata" => config.action_dispatch.,
      "action_dispatch.content_security_policy" => config.content_security_policy,
      "action_dispatch.content_security_policy_report_only" => config.content_security_policy_report_only,
      "action_dispatch.content_security_policy_nonce_generator" => config.content_security_policy_nonce_generator,
      "action_dispatch.content_security_policy_nonce_directives" => config.content_security_policy_nonce_directives,
      "action_dispatch.permissions_policy" => config.permissions_policy,
    )
end

#generators(&blk) ⇒ Object

Sends any generators called in the instance of a new application up to the generators method defined in Jets::Turbine.



254
255
256
# File 'lib/jets/application.rb', line 254

def generators(&blk)
  self.class.generators(&blk)
end

#helpers_pathsObject

:nodoc:



416
417
418
# File 'lib/jets/application.rb', line 416

def helpers_paths # :nodoc:
  config.helpers_paths
end

#initialize!(group = :default) ⇒ Object

Initialize the application passing the given group. By default, the group is :default



315
316
317
318
319
320
# File 'lib/jets/application.rb', line 315

def initialize!(group = :default) # :nodoc:
  raise "Application has been already initialized." if @initialized
  run_initializers(group, self)
  @initialized = true
  self
end

#initialized?Boolean

Returns true if the application is initialized.

Returns:

  • (Boolean)


74
75
76
# File 'lib/jets/application.rb', line 74

def initialized?
  @initialized
end

#initializer(name, opts = {}, &block) ⇒ Object

Sends the initializers to the initializer method defined in the Jets::Initializable module. Each Jets::Application class has its own set of initializers, as defined by the Initializable module.



236
237
238
# File 'lib/jets/application.rb', line 236

def initializer(name, opts = {}, &block)
  self.class.initializer(name, opts, &block)
end

#initializersObject

:nodoc:



322
323
324
325
326
# File 'lib/jets/application.rb', line 322

def initializers # :nodoc:
  Bootstrap.initializers_for(self) +
  turbines_initializers(super) +
  Finisher.initializers_for(self)
end

#isolate_namespace(mod) ⇒ Object

Sends the isolate_namespace method up to the class method.



265
266
267
# File 'lib/jets/application.rb', line 265

def isolate_namespace(mod)
  self.class.isolate_namespace(mod)
end

#key_generatorObject

Returns the application’s KeyGenerator



98
99
100
101
102
103
104
# File 'lib/jets/application.rb', line 98

def key_generator
  # number of iterations selected based on consultation with the google security
  # team. Details at https://github.com/jets/jets/pull/6952#issuecomment-7661220
  @caching_key_generator ||= ActiveSupport::CachingKeyGenerator.new(
    ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)
  )
end

#message_verifier(verifier_name) ⇒ Object

Returns a message verifier object.

This verifier can be used to generate and verify signed messages in the application.

It is recommended not to use the same verifier for different things, so you can get different verifiers passing the verifier_name argument.

Parameters

  • verifier_name - the name of the message verifier.

Examples

message = Jets.application.message_verifier('sensitive_data').generate('my sensible data')
Jets.application.message_verifier('sensitive_data').verify(message)
# => 'my sensible data'

See the ActiveSupport::MessageVerifier documentation for more information.



124
125
126
127
128
129
# File 'lib/jets/application.rb', line 124

def message_verifier(verifier_name)
  @message_verifiers[verifier_name] ||= begin
    secret = key_generator.generate_key(verifier_name.to_s)
    ActiveSupport::MessageVerifier.new(secret)
  end
end

#migration_turbinesObject

Return an array of turbines respecting the order they’re loaded and the order specified by the turbines_order config.

While running initializers we need engines in reverse order here when copying migrations from turbines ; we need them in the order given by turbines_order.



432
433
434
# File 'lib/jets/application.rb', line 432

def migration_turbines # :nodoc:
  ordered_turbines.flatten - [self]
end

#rake_tasks(&block) ⇒ Object

If you try to define a set of Rake tasks on the instance, these will get passed up to the Rake tasks defined on the application’s class.



229
230
231
# File 'lib/jets/application.rb', line 229

def rake_tasks(&block)
  self.class.rake_tasks(&block)
end

#reload_routes!Object

Reload application routes regardless if they changed or not.



93
94
95
# File 'lib/jets/application.rb', line 93

def reload_routes!
  routes_reloader.reload!
end

#require_environment!Object

:nodoc:



291
292
293
294
# File 'lib/jets/application.rb', line 291

def require_environment! # :nodoc:
  environment = paths["config/environment"].existent.first
  require environment if environment
end

#routes_reloaderObject

:nodoc:



296
297
298
# File 'lib/jets/application.rb', line 296

def routes_reloader # :nodoc:
  @routes_reloader ||= RoutesReloader.new
end

#run_load_hooks!Object

:nodoc:



78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/jets/application.rb', line 78

def run_load_hooks! # :nodoc:
  return self if @ran_load_hooks
  @ran_load_hooks = true

  @initial_variable_values.each do |variable_name, value|
    if INITIAL_VARIABLES.include?(variable_name)
      instance_variable_set("@#{variable_name}", value)
    end
  end

  instance_eval(&@block) if @block
  self
end

#runner(&blk) ⇒ Object

Sends any runner called in the instance of a new application up to the runner method defined in Jets::Turbine.



242
243
244
# File 'lib/jets/application.rb', line 242

def runner(&blk)
  self.class.runner(&blk)
end

#secret_key_baseObject

The secret_key_base is used as the input secret to the application’s key generator, which in turn is used to create all ActiveSupport::MessageVerifier and ActiveSupport::MessageEncryptor instances, including the ones that sign and encrypt cookies.

In development and test, this is randomly generated and stored in a temporary file in tmp/development_secret.txt.

In all other environments, we look for it first in ENV["SECRET_KEY_BASE"], then credentials.secret_key_base, and finally secrets.secret_key_base. For most applications, the correct place to store it is in the encrypted credentials file.



360
361
362
363
364
365
366
367
368
# File 'lib/jets/application.rb', line 360

def secret_key_base
  if Jets.env.development? || Jets.env.test?
    secrets.secret_key_base ||= generate_development_secret
  else
    validate_secret_key_base(
      ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
    )
  end
end

#server(&blk) ⇒ Object

Sends any server called in the instance of a new application up to the server method defined in Jets::Turbine.



260
261
262
# File 'lib/jets/application.rb', line 260

def server(&blk)
  self.class.server(&blk)
end

#to_appObject

:nodoc:



412
413
414
# File 'lib/jets/application.rb', line 412

def to_app # :nodoc:
  self
end

#watchable_argsObject

Returns an array of file paths appended with a hash of directories-extensions suitable for ActiveSupport::FileUpdateChecker API.



303
304
305
306
307
308
309
310
311
# File 'lib/jets/application.rb', line 303

def watchable_args # :nodoc:
  files, dirs = config.watchable_files.dup, config.watchable_dirs.dup

  ActiveSupport::Dependencies.autoload_paths.each do |path|
    File.file?(path) ? files << path.to_s : dirs[path.to_s] = [:rb]
  end

  [files, dirs]
end