我有一个带有STI型号的rails 4应用程序:
# models/person.rb
def Person < ActiveRecord::Base
end
# models/director.rb
def Director < Person
end
# models/actor.rb
def Director < Person
end
但是因为一个人可以同时扮演演员和导演,所以我希望STI有很多类型:
person = Person.first
person.type = "Director, Actor"
person.save
Actor.first.id => 1
Director.first.id => 1
轨道或宝石中是否有机制来实现这个目标?
答案 0 :(得分:0)
Rails不支持这一点,我不知道任何支持这个的宝石(即类型列中的多个子类名称)。
https://github.com/mhuggins/multiple_table_inheritance有一个gem,它为子类使用单独的表,你总是可以使用mixins作为继承的替代方法。
答案 1 :(得分:0)
我相信更多Rails惯用的做法类似的方法是通过scopes
,这将允许你这样做:
person = Person.first
person.position = 'Director, Actor'
person.save
person.directors.first.id => 1
person.actors.first.id => 1
您只需要在Person
类中定义一对范围:
scope :actors, -> { where('position like ?', '%Actor%') }
scope :directors, -> { where('position like ?', '%Director%') }
你会失去用person.is_a?
做这个的能力,但是Ruby并没有真正做多重继承,以至于无论如何都允许#is_a?
在传递兄弟类时返回true。您还可以通过简单的测试方法获得有效的类似功能:
def is_actor?
self.position =~ /Actor/
end
def is_director?
self.position =~ /Director/
end
编辑:我没有做过很多Rails 4,所以我的scope
语法可能不正确,我只是看了一下文档。但原则应该是合理的。
答案 2 :(得分:0)
感谢上面的所有回答者!
我找到了最适合我的解决方案: 我创建了hmt association Person-ProfessionsPerson-Profession并为Person类(导演和演员)留下了后代。
# models/profession.rb
Profession < ActiveRecord::Base
has_many :professions_people, dependent: :destroy
has_many :people, through: :professions_people
end
# models/person.rb
def Person < ActiveRecord::Base
has_many :professions_people, dependent: :destroy
has_many :professions, through: :professions_people
end
# models/director.rb
def Director < Person
include PeopleFromProfession
end
# models/actor.rb
def Actor < Person
include PeopleFromProfession
end
我已经为2个职业种下了“class_type”栏目(在应用程序的工作中不应该改变)“演员”和“导演” 我还添加了关注PeopleFromProfession以分享一些代码:
# models/concerns/actor.rb
module PeopleFromProfession
extend ActiveSupport::Concern
included do
default_scope { includes(:professions).where(professions: {class_type: self.name}) }
after_create :create_join_table_record
end
module ClassMethods
def model_name
Person.model_name
end
end
private
def create_join_table_record
self.professions << Profession.where(class_type: self.class.name).first
end
end
default_scope仅适用于具有特定职业的人,create_join_table_record回调是用于创建错过的联接表记录的monkey-patch。
类方法model_name被覆盖用于此目的,Best practices to handle routes for STI subclasses in rails
如果您在这种方法中遇到一些问题,请告诉我。