spring
spring copied to clipboard
Rails STI subclasses being "forgotten" when env auto-reloads
Consider the following structure:
class Section < ActiveRecord::Base
belongs_to :sectionable, polymorphic: true
end
class MarketSection < Section
end
class MarketNotesSection < MarketSection
end
When doing a query for sectionables that have has_many :market_sections, as: :sectionable
, on the first run after the environment is loaded, it correctly performs sections.type IN ('MarketSection', 'MarketNotesSection')
, because i added an initializer to preload the classes in development, as suggested in http://www.alexreisner.com/code/single-table-inheritance-in-rails for example.
However, as soon as i edit and save a bit of code (a controller for example), the environment "forgets" about the subclass of marketsection and stops including it in the query.
I'd be happy to provide more details if needed.
Same problem. The following sometimes helps (in 'config/initializers/reload.rb'), but not always. I'm on rails 4.1.5, spring 1.1.3 and ruby 1.9.3.
Rails.application.config.to_prepare do
require ...sti_file_here...
end
This happens to me as well. Does anyone have any idea what causes this?
I forgot about this issue, but I have a working solution. The key is to use require_dependency and not require.
The reason this happens is the way ruby looks up the classes traversing the class/module nesting. If you are looking for B in scope A, it will first try A::B and then fallback to ::B. This behaviour is called before the rails autoloader, thus if A::B is not loaded (or unloaded by rails), ::B is found (which is what you don't want). The solution is to tell the Rails autoloader to reload A::B on each request in development/test.
#config/initializers/reload.rb
Rails.application.config.to_prepare do
require_dependency 'a/b'
require_dependency 'b'
end
The safest approach however is to never reuse class names which also exist in a lesser nested scope. e.g. A::B & C::B are safe and never conflict, since ::B doesn't exist the rails autoloader kicks in loading the class on demand.
However, I care more about my naming than these loader specifics, so I mostly end up using the config.to_prepare approach.
This is apparently still an issue, but I think it's an issue in rails not spring. I ran into the issue in an app that did not use spring.
@lostapathy This just bit me as well. The suggested to_prepare
solution seemed to work for me.
Yeah, I think it is a general Rails issue, and is kind of sort of documented in the autoloading Guide. It is a gotcha with STI and dev-mode auto-loading.
https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#autoloading-and-sti