belongs_to_required_by_defaultが効かない。

Rails 5.0.0からbelongs_toがデフォルトで必須になったはずなのだけれど、そうなっていなかったので調べた。
結論から言うと「config/initializers/new_framework_defaults.rb」に置いたままではダメで、「config/application.rb」に書かないといけない。
理由は読まれるタイミングと使われるタイミング。(またこれか)

最初に、belongs_toの必須が定義されるのはここで、「model.belongs_to_required_by_default」が元になっている。
activerecord-5.0.0.1/lib/active_record/associations/builder/belongs_to.rb

128       if reflection.options[:optional].nil?
129         required = model.belongs_to_required_by_default
130       else
131         required = !reflection.options[:optional]
132       end

で、上の「model.belongs_to_required_by_default」がどこでセットされるかというと、ここ。追加したコメントはあとで出てきます。
activesupport-5.0.0.1/lib/active_support/core_ext/module/attribute_accessors.rb

123       class_eval(<<-EOS, __FILE__, __LINE__ + 1)
124         @@#{sym} = nil unless defined? @@#{sym}
125
126         def self.#{sym}=(obj)
127 #{if sym == :belongs_to_required_by_default
128 'puts "#{name}.#{__method__} # ここで決まる!"'
129 end}
130           @@#{sym} = obj
131         end
132       EOS

って書いても分かりにくいので、コメントを仕込んでタイミングを表示してみた。こんな感じ。

config/application.rb

20 puts "#{__FILE__.sub("#{Rails.root}/", '')}:#{__LINE__} Rails.application.config.active_record.belongs_to_required_by_default #=> #{Rails.application.config.active_record.belongs_to_required_by_default}"
 21   config.active_record.belongs_to_required_by_default = true # ここに書かないとダメ!
 22 puts "#{__FILE__.sub("#{Rails.root}/", '')}:#{__LINE__} Rails.application.config.active_record.belongs_to_required_by_default #=> #{Rails.application.config.active_record.belongs_to_required_by_default}"

config/initializers/new_framework_defaults.rb

17 # Require `belongs_to` associations by default. Previous versions had false.
 18 puts "#{__FILE__.sub("#{Rails.root}/", '')}:#{__LINE__} Rails.application.config.active_record.belongs_to_required_by_default #=> #{Rails.application.config.active_record.belongs_to_required_by_default}"
 19 Rails.application.config.active_record.belongs_to_required_by_default = true
 20 puts "#{__FILE__.sub("#{Rails.root}/", '')}:#{__LINE__} Rails.application.config.active_record.belongs_to_required_by_default #=> #{Rails.application.config.active_record.belongs_to_required_by_default}"

まずは「config/application.rb」に書かなかった場合

% bundle exec rails c
config/application.rb:20 Rails.application.config.active_record.belongs_to_required_by_default #=>
config/application.rb:22 Rails.application.config.active_record.belongs_to_required_by_default #=>
config/initializers/new_framework_defaults.rb:18 Rails.application.config.active_record.belongs_to_required_by_default #=>
config/initializers/new_framework_defaults.rb:20 Rails.application.config.active_record.belongs_to_required_by_default #=> true
Loading development environment (Rails 5.0.0.1)
irb(main):001:0> ActiveRecord::Base.belongs_to_required_by_default
=> nil

つぎに「config/application.rb」に書いた場合

% bundle exec rails c
config/application.rb:20 Rails.application.config.active_record.belongs_to_required_by_default #=>
config/application.rb:22 Rails.application.config.active_record.belongs_to_required_by_default #=> true
ActiveRecord::Base.belongs_to_required_by_default= # ここで決まる!
config/initializers/new_framework_defaults.rb:18 Rails.application.config.active_record.belongs_to_required_by_default #=> true
config/initializers/new_framework_defaults.rb:20 Rails.application.config.active_record.belongs_to_required_by_default #=> true
Loading development environment (Rails 5.0.0.1)
irb(main):001:0> ActiveRecord::Base.belongs_to_required_by_default
=> true

config/application.rb」に書かないとnilのままなんだね・・・。

って、すぐ遭遇しそうなことなので、自分が基本的なことを見落としている気がしてきたぞ。

タイトルとURLをコピーしました