2013-11-16 8 views
0

У меня есть рельсы 4 приложения с моделями STI:STI со многими типами

# 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

Благодарим всех ответчиков выше!

Я нашел решение, наиболее подходящее для меня: Я создал ассоциацию hmt Person-ProfessionsPerson-Profession и оставлю потомков для класса Person (Director and Actor).

# 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 предназначен для определения только людей с определенной профессией, call_join_table_record callback - это обезьяна-патч для создания пропущенной записи таблицы соединений.

метод класса model_name был перезапись для целей, которые покрыты здесь Best practices to handle routes for STI subclasses in rails

Если вы найдете какие-то проблемы в этом подходе, пожалуйста, сообщите мне.

0

Rails не поддерживает это, и я не знаю никаких драгоценных камней, которые поддерживают это, как описано (т. Е. Несколько подклассовых имен в столбце типа).

Существует жемчужина в https://github.com/mhuggins/multiple_table_inheritance, которая использует отдельные таблицы для подклассов, и вы всегда можете использовать mixins в качестве альтернативы наследованию.

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? с этим, но Руби действительно не делает множественное наследование таким образом, чтобы позволить #is_a? вернуть истинный, когда принятый класс родственный в любом случае. Вы также можете получить эффективно схожую функциональность с помощью простого метода испытаний:

def is_actor? 
    self.position =~ /Actor/ 
end 
def is_director? 
    self.position =~ /Director/ 
end 

EDIT: Я не сделал много Rails 4, так что мой scope синтаксис не может быть прав, я просто посмотрел на документы. Однако принцип должен звучать.

Смежные вопросы