Rails: Почему дочерние классы не загружаются при использовании метода класса для возврата атрибутов о дочерних классах? - PullRequest
0 голосов
/ 02 февраля 2011

Здравствуйте. Я некоторое время искал решение для этого. Использование Rails 2.3.5

У меня есть родительский класс с несколькими дочерними классами, и из-за отсутствия файла длиной 1500 строк, дочерние классы хранятся в подкаталоге каталога app / models.

До недавнего времени, когда я просматривал этот пост: здесь

Я даже не мог загрузить дочерние классы

Теперь я хочу получить доступ к каждому ребенку способом, использующим метод класса self.inherited как это:

class Project < ActiveRecord::Base

  CHILDREN = []
  def self.inherited(child)
    super
    CHILDREN << child
    puts "CHILDREN.inspect: #{CHILDREN.inspect}"
  end
  def self.valid_child_types
    CHILDREN.collect{ |child| child.project_type}
  end
end

Временно я поместил несколько отладочных операторов, чтобы получить более полное представление о том, как все загружается. Я запустил консоль и заметил следующее:

>> Project
require_or_load /Users/frankdrebin/Sites/cerp/app/models/project.rb
loading /Users/frankdrebin/Sites/cerp/app/models/project
require_or_load /Users/frankdrebin/Sites/cerp/app/models/status.rb
loading /Users/frankdrebin/Sites/cerp/app/models/status

=> Project(id: integer, url: string, deadline: date, state: string, type: string,  priority: integer, status_id: integer)
>> Project::CHILDREN
=> []
>> ArticleProject
require_or_load /Users/frankdrebin/Sites/cerp/app/models/projects/article_project.rb
loading /Users/frankdrebin/Sites/cerp/app/models/projects/article_project
CHILDREN.inspect: [ArticleProject(id: integer, url: string, deadline: date, state:  string, type: string, priority: integer, status_id: integer)]
require_or_load /Users/frankdrebin/Sites/cerp/vendor/gems/state_machine-  0.7.3/lib/state_machine.rb
loading /Users/frankdrebin/Sites/cerp/vendor/gems/state_machine-0.7.3/lib/state_machine

=> ArticleProject(id: integer, url: string, deadline: date, state: string, type: string,   priority: integer, status_id: integer)
>> Project::CHILDREN
=> [ArticleProject(id: integer, url: string, deadline: date, state: string, type: string,  priority: integer, status_id: integer)]
>> 

Я уверен, что есть менее изящные решения, такие как помещение дочерних классов обратно в один гигантский файл, но я бы хотел избежать этого, если это вообще возможно.

Спасибо

Ответы [ 2 ]

1 голос
/ 02 февраля 2011

У вас есть все виды проблем:

  1. ДЕТИ - это константа в Ruby, потому что она начинается с заглавной буквы, вы этого не хотите.
  2. Далее, если вы измените его на дочерние, то это будет локальная переменная, но вам понадобится переменная экземпляра для экземпляра определения родительского класса, поэтому вам нужно использовать @children.
  3. Вы должны сделать @children доступным на уровне класса (возможно, именно поэтому вы пытались использовать ДЕТИ).

Вот как вы это сделаете:

class Parent

  @children = []

  # Make the attr_reader for the class not an instance of the class
  class << self
    attr_reader :children
  end

  def self.inherited(child)
    puts "Parent inherited by child: #{child.inspect}"
    @children << child
    super
  end
end

class Child1 < Parent
end
puts "Child1 class created"

class Child2 < Parent
end
puts "Child2 class created"

c1 = Child1.new
c2 = Child2.new

puts "Parent.children: #{Parent.children}"

Вывод:

Parent inherited by child: Child1
Child1 class created
Parent inherited by child: Child2
Child2 class created
Parent.children: [Child1, Child2]
1 голос
/ 02 февраля 2011

Возможно, вам нужно сделать шаг назад и спросить себя, чего вы на самом деле пытаетесь достичь, и является ли наследование лучшим / единственным способом? Модули / Примеси?

...