Rails: STI, herança e recarga! bug no ambiente de desenvolvimento

Criado em 2 jan. 2013  ·  3Comentários  ·  Fonte: rails/rails

Estou reabrindo a edição nº 868, pois ainda está presente hoje.

Usei ruby-1.9.3-p362 e rails 3.2.9

A única solução é exigir classes filhas ou usar config.cache_classes = true

> Support.all
 => [] 
> Employee
 => Employee(id: integer, type: string) 
> Administrator
 => Administrator(id: integer, type: string) 
> Support.all
 => [#<Administrator id: 1, type: "Administrator">, #<Employee id: 2, type: "Employee">] 
activerecord

Comentários muito úteis

Esta é a limitação conhecida de usar o STI no modo de desenvolvimento com carregamento lento de classes. Você precisa usar require_dependency para tornar o Rails ciente dessas subclasses, por exemplo:

# app/models/support.rb
class Support < User
end

require_dependency 'administrator'
require_dependency 'employee'

Se você tiver muitas dessas subclasses, poderá usar Dir[] e uma pasta especial em app para carregá-las todas, por exemplo:

# app/models/user.rb
class User < ActiveRecord::Base
end

Dir["#{Rails.root}/app/users/*.rb"].each do |file|
  require_dependency file
end

Ou uma terceira alternativa é codificar permanentemente a lista em Model.descendants , por exemplo:

# app/models/user.rb
class User < ActiveRecord::Base
  def self.descendants
    [Support, Administrator, Employee]
  end
end

Não usei o último pessoalmente, mas deve funcionar.

Todos 3 comentários

Eu reproduzi no trilho 4

Rails 4.0.0.beta
Ruby 1.9.3p194

1.9.3p194 :001 > Administrator.create

1.9.3p194 :003 > Employee.create

1.9.3p194 :008 > Support.all
  Support Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."type" IN ('Support', 'Administrator', 'Employee')
 => #<ActiveRecord::Relation [#<Administrator id: 1, type: "Administrator">, #<Employee id: 2, type: "Employee">]> 

1.9.3p194 :009 > reload!
Reloading...
 => true 

1.9.3p194 :010 > Support.all
  Support Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."type" IN ('Support')
 => #<ActiveRecord::Relation []> 

Esta é a limitação conhecida de usar o STI no modo de desenvolvimento com carregamento lento de classes. Você precisa usar require_dependency para tornar o Rails ciente dessas subclasses, por exemplo:

# app/models/support.rb
class Support < User
end

require_dependency 'administrator'
require_dependency 'employee'

Se você tiver muitas dessas subclasses, poderá usar Dir[] e uma pasta especial em app para carregá-las todas, por exemplo:

# app/models/user.rb
class User < ActiveRecord::Base
end

Dir["#{Rails.root}/app/users/*.rb"].each do |file|
  require_dependency file
end

Ou uma terceira alternativa é codificar permanentemente a lista em Model.descendants , por exemplo:

# app/models/user.rb
class User < ActiveRecord::Base
  def self.descendants
    [Support, Administrator, Employee]
  end
end

Não usei o último pessoalmente, mas deve funcionar.

Eu tenho esse tipo de problema e não consigo fazer funcionar. Meus modelos são A, B (e mais) <C, D (e mais) <B.
Após uma mudança de código, obtenho "constante B não inicializada". Tentei require_dependency de algumas maneiras, mas não sei realmente 1) quais classes exigir (B?) E 2) onde fazê-lo.
Esses modelos estão associados a outros modelos de várias maneiras, isso pode ter um impacto na ordem de carregamento também (por exemplo, A pertence_a X, X tem_muitos Bs e Cs)

Esta página foi útil?
0 / 5 - 0 avaliações