Rails 2.3 STI 返回所有子类

发布于 2024-12-05 07:20:33 字数 768 浏览 8 评论 0原文

我正在使用标准 STI,并希望在表单上创建一个输入选择,其选项都是父类的子类型。所以我希望 Parent.select_options 返回 ['Child1','Child2','Child3']

class Parent < ActiveRecord::Base
  # kinda what I'd like except the descendants method is undefined in rails 2.3
  def self.select_options
    descendants.map{ |c| c.to_s }.sort
  end
end

class Child1 < Parent
end

class Child2 < Parent
end

class Child3 < Parent
end

view.html.haml

= f.input :parent_id, :as => :select, :collection => Parent.select_options, :prompt => true

UPDATE

感谢 @nash 和 @jdeseno 只需使用 @jdeseno 方法添加以下初始值设定项:

%w[parent child1 child2 child3].each do |c|
  require_dependency File.join("app","models","#{c}.rb")
end

I am using standard STI and want to create an input select on a form whose options are all child type of the parent class. So I'd like Parent.select_options to return ['Child1','Child2','Child3']

class Parent < ActiveRecord::Base
  # kinda what I'd like except the descendants method is undefined in rails 2.3
  def self.select_options
    descendants.map{ |c| c.to_s }.sort
  end
end

class Child1 < Parent
end

class Child2 < Parent
end

class Child3 < Parent
end

view.html.haml

= f.input :parent_id, :as => :select, :collection => Parent.select_options, :prompt => true

UPDATE

Thanks to @nash and @jdeseno just need to add the following initializer using @jdeseno method:

%w[parent child1 child2 child3].each do |c|
  require_dependency File.join("app","models","#{c}.rb")
end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

迷荒 2024-12-12 07:20:33

您可以通过挂钩 Class.inherited 来添加后代方法:

class Parent
  @@descendants = []

  def self.inherited(klass)
    @@descendants << klass
  end

  def descendants
    @@descendants
  end
end

class A < Parent; end
class B < Parent; end
class C < Parent; end

例如:

irb> Parent.new.descendants
[A, B, C]

You can add a descendants method by hooking into Class.inherited:

class Parent
  @@descendants = []

  def self.inherited(klass)
    @@descendants << klass
  end

  def descendants
    @@descendants
  end
end

class A < Parent; end
class B < Parent; end
class C < Parent; end

Eg:

irb> Parent.new.descendants
[A, B, C]
去了角落 2024-12-12 07:20:33

实际上,即使在 Rails 2.3 中,自定义实现子类的跟踪也不是真正必要的。已经存在一个适当命名的方法“子类”,它由 ActiveSupport 注入到 Class 中,它按词法排序的顺序为您返回它们。所以你可以写

class Parent < ActiveRecord::Base
  def self.select_options
    subclasses.map{ |c| c.to_s }
  end
end

class Child3 < Parent
end

class Child1 < Parent
end

class Child2 < Parent
end

或者你可以使用与他们在那里相同的技巧并使用

class Parent < ActiveRecord::Base
  def self.select_options
    Object.subclasses_of(self).map{ |c| c.to_s }.sort
  end
end

Just verify this in Rails 2.3.14 (Ruby 1.8.7-p352) 并在两种情况下都得到了预期的结果:

>> Parent.select_options
=> ["Child1", "Child2", "Child3"]

预加载 STI child 的必要性开发环境中的类仍然适用。感谢 Alex Reisner 在他的博客中提供的提示。

Actually, custom-implementing the tracking of subclasses isn't really necessary even in Rails 2.3. There already exists an aptly named method "subclasses" injected into Class by ActiveSupport that returns them for you in lexically sorted order. So you could have written

class Parent < ActiveRecord::Base
  def self.select_options
    subclasses.map{ |c| c.to_s }
  end
end

class Child3 < Parent
end

class Child1 < Parent
end

class Child2 < Parent
end

Or you could have used the same trick as they did there and used

class Parent < ActiveRecord::Base
  def self.select_options
    Object.subclasses_of(self).map{ |c| c.to_s }.sort
  end
end

Just verified this in Rails 2.3.14 (Ruby 1.8.7-p352) and got the expected result in both cases:

>> Parent.select_options
=> ["Child1", "Child2", "Child3"]

The necessity to preload STI child classes in the development environment still applies. Kudos to Alex Reisner for the hint in his blog.

和我恋爱吧 2024-12-12 07:20:33

当您调用 Parent.select_options 方法时,您的子模型可能尚未加载。 添加如下内容:

class Parent < ActiveRecord::Base
  Dir[File.join(File.dirname(__FILE__), "*.rb")].each do |f|
    Parent.const_get(File.basename(f, '.rb').classify)
  end
end

因此,您可以在您的 Parent 模型中 现在您可以使用您的方法:

ruby-1.9.2-p290 :010 > Parent.descendants.map {|c| c.to_s}.sort
 => ["Child1", "Child2", "Child3"] 

When you invoke your Parent.select_options method your child models may not be loaded yet. So, you can add something like this:

class Parent < ActiveRecord::Base
  Dir[File.join(File.dirname(__FILE__), "*.rb")].each do |f|
    Parent.const_get(File.basename(f, '.rb').classify)
  end
end

in your Parent model. Now you can use your method:

ruby-1.9.2-p290 :010 > Parent.descendants.map {|c| c.to_s}.sort
 => ["Child1", "Child2", "Child3"] 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文