2015-02-27 2 views
0

У меня есть набор классов что-то вроде этого:Rails STI и Active Record находит

class Owner 
    has_one :animal 
end 

class Animal < AR::Base 
    TYPES = ['Lion','Cat'] 
    # has a type field 

    belongs_to :owner 
end 

class Lion < Animal 
    def speak 
    'roar' 
    end 
end 

class Cat < Animal 
    def speak 
    'meow' 
    end 
end 

Так у меня есть связь с владельцами и животных, и каждое животное имеет тип. Это все работает, пока я не сделать вызов, как это:

owner.animal.speak 

Это возвращает объект типа «Animal», а затем пытается вызвать метод «говорить», который является неопределенным для родителей. Как мне получить Rails для возврата соответствующего подкласса вместо родительского класса?

+0

У вас есть столбец с именем «тип» в таблице животных? – Doguita

+0

Вы уверены, что у данного вида животных есть тип? Вы проверяете наличие типа? – evanbikes

+1

Rails должен инициализировать экземпляр правильного подкласса. http://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html У вас есть свои модели правильно? – messanjah

ответ

0

ActiveRecord и Arel нелегко обрабатывать такие подклассы. Лучше всего, чтобы класс Animal отслеживал свой собственный тип. Итак:

class Animal < AR::Base 
    TYPES = ['Lion','Cat'] 

    belongs_to :owner 

    def speak 
    case self.type 
    when "Lion" 
     "roar" 
    when "Cat" 
     "meow" 
    end 
    end 
end 
+0

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

0

Я только что развернул новый проект Rails и использовал ваш пример, и он работал, как ожидалось. В столбце type вы уверены, что тип "Cat" или "Lion", а не нижняя или нижняя версия?

Я бы предложил добавить has_one :cat и has_one :lion в Owner. Затем, чтобы создать их экземпляр, вы можете вызвать Rails 'owner.build_cat, который является способом создания нового экземпляра has_one. (В has_many это будет owner.cats.build.)

Таким образом, вы уверены, что type выполнен правильно.

Это то, что я получаю.

> owner.animal 
=> nil 
> owner.cat 
=> nil 
> owner.build_cat 
=> #<Cat id: nil, owner_id: 1, type: "Cat" ... 
> owner.cat.save 
=> true 
> owner.cat 
=> #<Cat id: 1, owner_id: 1, type: "Cat" ... 
> owner.animal 
=> nil # Whaaaa? 

(Экземпляр владелец имеет кэш-память об ассоциации, и, так как мы уже назвали животное, и это была равна нулю, то в кэш, как ноль)

> owner.clear_association_cache 
=> {} 
> owner.animal 
=> #<Cat id: 1, owner_id: 1, type: "Cat" ... 
> owner.animal.speak 
=> 'meow' 
> owner.animal.class 
=> Cat 
> owner.animal.class.to_s == owner.animal.type 
=> true 

Надежда, что помогает!

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