跳至内容 跳至搜索

一个 Engine,负责协调整个启动过程。

初始化

Rails::Application 负责执行所有 railties 和 engines 的初始化程序。它还会执行一些引导初始化程序(查看 Rails::Application::Bootstrap)和完成初始化程序,在所有其他初始化程序执行完毕后执行(查看 Rails::Application::Finisher)。

配置

除了提供与 Rails::EngineRails::Railtie 相同的配置外,应用程序对象还有几个特定配置,例如 enable_reloadingconsider_all_requests_localfilter_parameterslogger 等。

查看 Rails::Application::Configuration 以查看所有配置。

路由

应用程序对象还负责在开发过程中保持路由并重新加载路由,只要文件发生更改。

中间件

Application 还负责构建中间件堆栈。

启动过程

应用程序还负责设置和执行启动过程。从在应用中需要 config/application.rb 的那一刻起,启动过程如下

  1. require "config/boot.rb" 以设置加载路径。

  2. require railties 和 engines。

  3. Rails.application 定义为 class MyApp::Application < Rails::Application

  4. 运行 config.before_configuration 回调。

  5. 加载 config/environments/ENV.rb

  6. 运行 config.before_initialize 回调。

  7. 运行由轨道、引擎和应用程序定义的 Railtie#initializer。每个引擎逐一设置其加载路径和路由,并运行其 config/initializers/* 文件。

  8. 执行由轨道、引擎和应用程序添加的自定义 Railtie#initializers

  9. 构建中间件堆栈并运行 to_prepare 回调。

  10. 如果 eager_loadtrue,则运行 config.before_eager_loadeager_load!

  11. 运行 config.after_initialize 回调。

命名空间
方法
C
D
E
F
G
I
K
M
N
R
S
V

属性

[RW] assets
[R] autoloaders
[W] config
[W] credentials
[R] executor
[R] reloader
[R] reloaders
[RW] sandbox
[RW] sandbox?
[W] secrets

类公共方法

create(initial_variable_values = {}, &block)

# File railties/lib/rails/application.rb, line 84
def create(initial_variable_values = {}, &block)
  new(initial_variable_values, &block).run_load_hooks!
end

find_root(from)

# File railties/lib/rails/application.rb, line 88
def find_root(from)
  find_root_with_flag "config.ru", from, Dir.pwd
end

inherited(base)

# File railties/lib/rails/application.rb, line 71
def inherited(base)
  super
  Rails.app_class = base
  # lib has to be added to $LOAD_PATH unconditionally, even if it's in the
  # autoload paths and config.add_autoload_paths_to_load_path is false.
  add_lib_to_load_path!(find_root(base.called_from))
  ActiveSupport.run_load_hooks(:before_configuration, base)
end

instance()

# File railties/lib/rails/application.rb, line 80
def instance
  super.run_load_hooks!
end

new(initial_variable_values = {}, &block)

# File railties/lib/rails/application.rb, line 109
def initialize(initial_variable_values = {}, &block)
  super()
  @initialized       = false
  @reloaders         = []
  @routes_reloader   = nil
  @app_env_config    = nil
  @ordered_railties  = nil
  @railties          = nil
  @key_generators    = {}
  @message_verifiers = nil
  @deprecators       = nil
  @ran_load_hooks    = false

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

  @autoloaders = Rails::Autoloaders.new

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

实例公共方法

config_for(name, env: Rails.env)

方便为当前 Rails 环境加载 config/foo.yml。示例

# 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
Rails.application.configure do
  config.middleware.use ExceptionNotifier, config_for(:exception_notification)
end

您还可以将配置存储在共享部分中,该部分将与环境配置合并

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

development:
  foo:
    bar:
      qux: 2

# development environment
Rails.application.config_for(:example)[:foo][:bar]
# => { baz: 1, qux: 2 }
# File railties/lib/rails/application.rb, line 274
def config_for(name, env: Rails.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)

将新应用程序实例中调用的任何控制台发送到 Rails::Railtie 中定义的 console 方法。

# File railties/lib/rails/application.rb, line 357
def console(&blk)
  self.class.console(&blk)
end

credentials()

返回一个 ActiveSupport::EncryptedConfiguration 实例,用于 config.credentials.content_path 指定的凭据文件。

默认情况下,config.credentials.content_path 将指向当前环境的 config/credentials/#{environment}.yml.enc(例如,production 环境的 config/credentials/production.yml.enc),或如果该文件不存在,则指向 config/credentials.yml.enc

加密密钥取自 ENV["RAILS_MASTER_KEY"]config.credentials.key_path 指定的文件。默认情况下,config.credentials.key_path 将指向当前环境的 config/credentials/#{environment}.key,或如果该文件不存在,则指向 config/master.key

# File railties/lib/rails/application.rb, line 516
def credentials
  @credentials ||= encrypted(config.credentials.content_path, key_path: config.credentials.key_path)
end

deprecators()

已弃用的管理集合 (ActiveSupport::Deprecation::Deprecators)。集合的配置方法会影响集合中的所有已弃用项。此外,集合的 silence 方法会使集合中的所有已弃用项在给定块持续时间内保持沉默。

# File railties/lib/rails/application.rb, line 230
def deprecators
  @deprecators ||= ActiveSupport::Deprecation::Deprecators.new.tap do |deprecators|
    deprecators[:railties] = Rails.deprecator
  end
end

eager_load!()

急切加载应用程序代码。

# File railties/lib/rails/application.rb, line 574
def eager_load!
  Rails.autoloaders.each(&:eager_load)
end

encrypted(path, key_path: "config/master.key", env_key: "RAILS_MASTER_KEY")

为加密文件返回一个 ActiveSupport::EncryptedConfiguration 实例。默认情况下,加密密钥取自 ENV["RAILS_MASTER_KEY"]config/master.key 文件。

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

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

my_config.foo.bar
# => 123

可以使用 bin/rails encrypted:edit 命令编辑加密文件。(有关更多信息,请参见 bin/rails encrypted:edit --help 的输出。)

# File railties/lib/rails/application.rb, line 535
def encrypted(path, key_path: "config/master.key", env_key: "RAILS_MASTER_KEY")
  ActiveSupport::EncryptedConfiguration.new(
    config_path: Rails.root.join(path),
    key_path: Rails.root.join(key_path),
    env_key: env_key,
    raise_if_missing_key: config.require_master_key
  )
end

env_config()

存储一些 Rails 初始环境参数,这些参数将由中间件和引擎用于配置自身。

# File railties/lib/rails/application.rb, line 303
def env_config
  @app_env_config ||= super.merge(
      "action_dispatch.parameter_filter" => 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.debug_exception_log_level" => ActiveSupport::Logger.const_get(config.action_dispatch.debug_exception_log_level.to_s.upcase),
      "action_dispatch.logger" => Rails.logger,
      "action_dispatch.backtrace_cleaner" => Rails.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.use_cookies_with_metadata,
      "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)

将新应用程序实例中调用的任何生成器发送到 Rails::Railtie 中定义的 generators 方法。

# File railties/lib/rails/application.rb, line 363
def generators(&blk)
  self.class.generators(&blk)
end

initialized?()

如果应用程序已初始化,则返回 true。

# File railties/lib/rails/application.rb, line 134
def initialized?
  @initialized
end

initializer(name, opts = {}, &block)

将初始化器发送到 Rails::Initializable 模块中定义的 initializer 方法。每个 Rails::Application 类都有自己的初始化器集,由 Initializable 模块定义。

# File railties/lib/rails/application.rb, line 345
def initializer(name, opts = {}, &block)
  self.class.initializer(name, opts, &block)
end

isolate_namespace(mod)

isolate_namespace 方法发送到类方法。

# File railties/lib/rails/application.rb, line 374
def isolate_namespace(mod)
  self.class.isolate_namespace(mod)
end

key_generator(secret_key_base = self.secret_key_base)

为指定的 secret_key_base 返回一个键生成器 (ActiveSupport::CachingKeyGenerator)。返回值被记忆,因此使用相同 secret_key_base 的其他调用将返回相同的键生成器实例。

# File railties/lib/rails/application.rb, line 161
def key_generator(secret_key_base = self.secret_key_base)
  # number of iterations selected based on consultation with the google security
  # team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220
  @key_generators[secret_key_base] ||= ActiveSupport::CachingKeyGenerator.new(
    ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)
  )
end

message_verifier(verifier_name)

返回一个消息验证器对象。

此验证器可用于在应用程序中生成和验证签名消息。

建议不要将同一个验证器用于不同的事物,因此你可以传递 verifier_name 参数来获取不同的验证器。

参数

  • verifier_name - 消息验证器的名称。

示例

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

有关更多信息,请参阅 ActiveSupport::MessageVerifier 文档。

# File railties/lib/rails/application.rb, line 222
def message_verifier(verifier_name)
  message_verifiers[verifier_name]
end

message_verifiers()

返回一个消息验证器工厂 (ActiveSupport::MessageVerifiers)。此工厂可用作配置和创建应用程序的消息验证器 (ActiveSupport::MessageVerifier) 的中心点。

默认情况下,此工厂创建的消息验证器将使用默认 ActiveSupport::MessageVerifier 选项生成消息。您可以使用 ActiveSupport::MessageVerifiers#clear_rotationsActiveSupport::MessageVerifiers#rotate 的组合覆盖这些选项。但是,这必须在构建任何消息验证器实例之前完成。例如,在 before_initialize 块中

# Use `url_safe: true` when generating messages
config.before_initialize do |app|
  app.message_verifiers.clear_rotations
  app.message_verifiers.rotate(url_safe: true)
end

此工厂创建的消息验证器在生成消息时始终会使用从 secret_key_base 派生的密钥。clear_rotations 不会影响此行为。但是,可以轮换较旧的 secret_key_base 值以验证消息

# Fall back to old `secret_key_base` when verifying messages
config.before_initialize do |app|
  app.message_verifiers.rotate(secret_key_base: "old secret_key_base")
end
# File railties/lib/rails/application.rb, line 197
def message_verifiers
  @message_verifiers ||=
    ActiveSupport::MessageVerifiers.new do |salt, secret_key_base: self.secret_key_base|
      key_generator(secret_key_base).generate_key(salt)
    end.rotate_defaults
end

rake_tasks(&block)

如果您尝试在实例上定义一组 Rake 任务,这些任务将传递到应用程序类上定义的 Rake 任务。

# File railties/lib/rails/application.rb, line 338
def rake_tasks(&block)
  self.class.rake_tasks(&block)
end

reload_routes!()

重新加载应用程序路由,无论它们是否已更改。

# File railties/lib/rails/application.rb, line 153
def reload_routes!
  routes_reloader.reload!
end

runner(&blk)

将新应用程序实例中调用的任何运行器发送到 Rails::Railtie 中定义的 runner 方法。

# File railties/lib/rails/application.rb, line 351
def runner(&blk)
  self.class.runner(&blk)
end

secret_key_base()

secret_key_base 用作应用程序密钥生成器的输入密钥,该密钥生成器又用于创建所有 ActiveSupport::MessageVerifierActiveSupport::MessageEncryptor 实例,包括对 cookie 进行签名和加密的实例。

在开发和测试中,这是随机生成的并存储在 tmp/local_secret.txt 中的一个临时文件中。

您还可以设置 ENV["SECRET_KEY_BASE_DUMMY"] 以触发使用随机生成的 secret_key_base,该密钥存储在临时文件中。当预编译生产资产作为构建步骤的一部分时,这非常有用,而该构建步骤不需要访问生产密钥。

Dockerfile 示例:RUN SECRET_KEY_BASE_DUMMY=1 bundle exec rails assets:precompile

在所有其他环境中,我们首先在 ENV["SECRET_KEY_BASE"] 中查找它,然后在 credentials.secret_key_base 中查找,最后在 secrets.secret_key_base 中查找。对于大多数应用程序,存储它的正确位置是加密的凭证文件中。

# File railties/lib/rails/application.rb, line 478
    def secret_key_base
      if Rails.env.local? || ENV["SECRET_KEY_BASE_DUMMY"]
        config.secret_key_base ||= generate_local_secret
      else
        validate_secret_key_base(
          ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || begin
            secret_skb = secrets_secret_key_base

            if secret_skb.equal?(config.secret_key_base)
              config.secret_key_base
            else
              Rails.deprecator.warn(<<~MSG.squish)
                Your `secret_key_base` is configured in `Rails.application.secrets`,
                which is deprecated in favor of `Rails.application.credentials` and
                will be removed in Rails 7.2.
              MSG

              secret_skb
            end
          end
        )
      end
    end

secrets()

# File railties/lib/rails/application.rb, line 443
    def secrets
      Rails.deprecator.warn(<<~MSG.squish)
        `Rails.application.secrets` is deprecated in favor of `Rails.application.credentials` and will be removed in Rails 7.2.
      MSG
      @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! Rails::Secrets.parse(files, env: Rails.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

server(&blk)

将新应用程序实例中调用的任何服务器发送到 Rails::Railtie 中定义的 server 方法。

# File railties/lib/rails/application.rb, line 369
def server(&blk)
  self.class.server(&blk)
end

实例受保护的方法

ensure_generator_templates_added()

# File railties/lib/rails/application.rb, line 662
def ensure_generator_templates_added
  configured_paths = config.generators.templates
  configured_paths.unshift(*(paths["lib/templates"].existent - configured_paths))
end

validate_secret_key_base(secret_key_base)

# File railties/lib/rails/application.rb, line 652
def validate_secret_key_base(secret_key_base)
  if secret_key_base.is_a?(String) && secret_key_base.present?
    secret_key_base
  elsif secret_key_base
    raise ArgumentError, "`secret_key_base` for #{Rails.env} environment must be a type of String`"
  else
    raise ArgumentError, "Missing `secret_key_base` for '#{Rails.env}' environment, set this string with `bin/rails credentials:edit`"
  end
end