Ruby on Rails — has_many в зависимости от типа

Я новичок в Ruby on Rails, поэтому не так много знаю об ассоциации моделей. Но вот моя проблема:

У меня есть ресурс проекта, который содержит "has_many :items". У каждого элемента есть имя и тип (вид определяет тип элемента). Я хочу создавать разные ассоциации на основе значения "вида"... вот так:

class Item < ActiveRecord::Base
  belongs_to :project, :dependent => :destroy

  has_many :sports, :class_name => 'NormalSport' # if kind = 'normal_sport'
  has_many :sports, :class_name => 'SuperSport' # if kind = 'super_sport'
  has_many :sheep # if kind = 'sheep'
  has_many :drinks # if kind = 'drink'
end

Таким образом, это означает, что предмет может быть либо "normal_sport", либо "super_sport", либо "sheep", либо "drink". Итак, если предмет является normal_sport, я хотел бы иметь возможность сказать (что-то вроде):

Project.first.items.first.sports.all

А потом «спорт» переходит в класс «Нормальный спорт».

Но, возможно, это НЕПРАВИЛЬНЫЙ способ сделать это. Я искал полиморфные ассоциации... но не похоже, что это такая ассоциация. Что это за ассоциация? Где «Предмет» — это просто какая-то «модель посредника»?

Спасибо! (и извините за мой плохой английский)

С уважением Александр


Спасибо вам обоим за ответ. Но, похоже, ему не нравятся маршруты. Если я скажу что-то вроде (в частичном элементе, который зацикливает все элементы для проекта):

<%= link_to 'Destroy', [@project, item], :confirm => 'Are you sure?', :method => :delete %>

Он не ведет себя так, как этого хочется. Если это элемент «SuperSport», он использует URL:

/projects/1/super_sport/4

И если это предмет "Овца", он идет в

/projects/1/sheep/5

Как я могу сказать, что они ВСЕ должны идти в:

/projects/:project_id/items/:item_id

Все они используют ItemsController. Было бы хорошо, если бы они все могли использовать этот маршрут. Я пробовал с этим хаком:

class Item < ActiveRecord::Base
  belongs_to :project
  validates_uniqueness_of :type, :scope => :project_id

  # Hack.
  def self.model_name
    name = 'item'
    name.instance_eval do
      def plural;   pluralize;   end
      def singular; singularize; end
    end
    return name
  end
end

Но тогда проверка прерывается. Я надеюсь, вы понимаете мою проблему!


person Alexander    schedule 04.12.2010    source источник


Ответы (2)


Похоже, вы хотите STI, поэтому есть базовый класс с общей функциональностью, но разные типы моделей, которые наследуются от него. STI легко реализовать:

class Sport < ActiveRecord::Base
  belongs_to :item
end

class NormalSport < Sport
end

class SuperSport < Sport
end

class Item < ActiveRecord::Base
  has_many :sports
  has_many :normal_sports
  has_many :super_sports
end

Используя правильный класс, Rails автоматически отфильтрует для вас таблицу sports. Если использование разных классов обременительно, вы также можете использовать базовый класс Sport и отфильтровать поле type вручную.

person Adam Lassek    schedule 04.12.2010

Если полиморфные ассоциации не соответствуют вашим потребностям, вы также можете изучить наследование одной таблицы (STI).

Другой подход заключается в определении границ выбора дочерних моделей.

person Jakub Hampl    schedule 04.12.2010