config/initializers
昨日銀座Railsへ行きました。
そこでgemつくる前にconfig/initializers配下に.rbファイル作って試せるということを知りました!
さらにrailsを速く動かすために何を変えればいいかコードを追っているのをみて、自分も少しコードを見たくなったのでconfig/initializersについて調べつつ定義元を読んでみることにしました!
config/initializersとは
アプリを起動した際まとめてロードされるディレクトリです。
具体的には、フレームワークの読み込み&gemの読み込みが終わったタイミングで読み込まれます。
開発環境・テスト環境・本番環境全てで読み込まれます。
gemを入れるとそのgemの設定ファイルが追加されたりします。自分で.rbファイルを作成して追加することも可能です。
デフォルトで以下の.rbファイルが入ってます。
- application_controller_renderer.rb
- assets.rb
- backtrace_silencers.rb
- content_security_policy.rb
- cookies_serializer.rb
- filter_parameter_logging.rb
- inflections.rb
- mime_types.rb
- wrap_parameters.rb
どうやって読み込まれてるか
initializers配下の.rbファイルを読み込む設定はrails/rails側の、
rails/railties/lib/rails/initializable.rbで書かれています。
# frozen_string_literal: true
require "tsort"
module Rails
module Initializable
def self.included(base) #:nodoc:
base.extend ClassMethods
end
class Initializer
attr_reader :name, :block
def initialize(name, context, options, &block)
options[:group] ||= :default
@name, @context, @options, @block = name, context, options, block
end
def before
@options[:before]
end
def after
@options[:after]
end
def belongs_to?(group)
@options[:group] == group || @options[:group] == :all
end
def run(*args)
@context.instance_exec(*args, &block)
end
def bind(context)
return self if @context
Initializer.new(@name, context, @options, &block)
end
def context_class
@context.class
end
end
class Collection < Array
include TSort
alias :tsort_each_node :each
def tsort_each_child(initializer, &block)
select { |i| i.before == initializer.name || i.name == initializer.after }.each(&block)
end
def +(other)
Collection.new(to_a + other.to_a)
end
end
def run_initializers(group = :default, *args)
return if instance_variable_defined?(:@ran)
initializers.tsort_each do |initializer|
initializer.run(*args) if initializer.belongs_to?(group)
end
@ran = true
end
def initializers
@initializers ||= self.class.initializers_for(self)
end
module ClassMethods
def initializers
@initializers ||= Collection.new
end
def initializers_chain
initializers = Collection.new
ancestors.reverse_each do |klass|
next unless klass.respond_to?(:initializers)
initializers = initializers + klass.initializers
end
initializers
end
def initializers_for(binding)
Collection.new(initializers_chain.map { |i| i.bind(binding) })
end
def initializer(name, opts = {}, &blk)
raise ArgumentError, "A block must be passed when defining an initializer" unless blk
opts[:after] ||= initializers.last.name unless initializers.empty? || initializers.find { |i| i.name == opts[:before] }
initializers << Initializer.new(name, nil, opts, &blk)
end
end
end
end
def self.included(base) #:nodoc:
base.extend ClassMethods
end
この部分でRails::Initializableモジュールを生やしたクラスのクラスメソッドとして、ClassMethodsクラスに定義しているinitializers、initializers_chain、initializers_for、initializerメソッドを使えるようにしているのかな??
実際にそれらのメソッドが呼ばれるのは
rails/railties/lib/rails/application.rbのinitialize!メソッドの中のようです。
def initialize!(group = :default) #:nodoc:
raise "Application has been already initialized." if @initialized
run_initializers(group, self)
@initialized = true
self
end
さらにinitialize!メソッドが呼ばれるのはRailsアプリ側のconfig/environment.rbの中のようです。
# Load the Rails application.
require_relative 'application'
# Initialize the Rails application.
Rails.application.initialize!
感想その他
まだまだ追いきれておりませんが、今日は一旦ここまでにします。。。!!
明日以降続きや、initializersが呼ばれるより前の部分も見ていきたいと思います!!