LoginSignup
5
6

More than 5 years have passed since last update.

Railsは、開発環境では直前までモデルやコントローラーを読み込まない

Last updated at Posted at 2015-02-19

結構詰まったので記録しておく。
今作っているアプリケーションの構造的に、あるモデル(Parent)がたくさん従属要素をもっていて、そのたびにhas_manyを書く必要があった。そこで、下のactive_record_extenstion.rbを作ってlib/以下においた。

active_record_extension.rb

ActiveRecord::Base.class_eval do
  def self.scoped_to_tenant
    belongs_to :parent
    association_name = self.to_s.downcase.pluralize
    Parent.has_many association_name.to_sym, class_name: self.to_s
  end
end

そんで、子モデルの方に、こんな感じで書いた。

child.rb
require Rails.root.join("lib/active_record_extension.rb"
class Child < ActiveRecord::Base
  scoped_to_parent
end

こう書いとけば、子の方で親の分もまとめて定義できる。そう思って、子供の一覧を表示するコントローラーを下のように書いた。(current_parentは別に定義)

parents_controller.rb
class ParentsController < ApplicationController
  def index
    @children = current_parent.children.all
  end
end

そしたら、一覧ページを訪れた時に

undefined:children <class: parent>

てなようなエラーが出た。


ここからが本題。

エラーが出たわけで、pryを使ってデバッグしてみたり、色々原因を探ってみた。いつもこのエラーが出るわけじゃなくて、何回か更新したら出ない時もあった。試行錯誤していくと、コントローラー入ったところでChildを一回呼び出したらエラーが出なくなることに気がついた。

ここで、あれ、もしかしてChild modelが読み込まれてないんじゃ...?とピンときて、「rails model 読み込み」とかでググってみたら、model一覧を

Activerecord::Base.subclasses

で取得できると知った。デバッグ中に実行してみたら、案の定Parentしか表示されない。
なんでや!って思い、さらにググったら、タイトルのことが判明した。
この設定はconfig/environments/development.rbでしてあった。

config/environments/development.rb
  # In the development environment your application's code is reloaded on
  # every request. This slows down response time but is perfect for development
  # since you don't have to restart the web server when you make code changes.

  config.cache_classes = false

  # Do not eager load code on boot.

  config.eager_load = false

この2つの設定、production.rbではこうなってる。

config/environments/production.rb
  # Code is not reloaded between requests.
  config.cache_classes = true

  # Eager load code on boot. This eager loads most of Rails and
  # your application in memory, allowing both threaded web servers
  # and those relying on copy on write to perform better.
  # Rake tasks automatically ignore this option for performance.
  config.eager_load = true

本番環境では起動時にクラスをすべて読み込んで、キャッシュも使うけど、もし開発環境でそうしてしまうとファイルを更新するたびにサーバーを再起動させなくてはならないのでやらない。とのこと。

だから開発環境で一覧ページを訪問した時は、childモデルが読み込まれてなくて、parentにもhas_manyが適用されていなかったというわけ。結局parentにhas_manyを追加しましたとさ。

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6