Моделирование has_and_belongs_to_many, вложенного через поведение в Rails 3

Таким образом, Rails не поддерживает ассоциации :through через отношения habtm. Существуют плагины, которые добавят это для Rails 2.x, но я использую Rails 3/Edge, и мне нужна ассоциация только для одной конкретной модели. Так что я подумал, что сам покончу с красотой, которой является Арел.

Во-первых, модели:

class CardSet < ActiveRecord::Base
  has_and_belongs_to_many :cards, :uniq => true
end

class Card < ActiveRecord::Base
  has_and_belongs_to_many :card_sets, :uniq => true
  has_many :learnings, :dependent => :destroy
end

class Learning < ActiveRecord::Base
  belongs_to :card
end

Я хочу получить все знания, которые относятся к определенному набору карточек, :through =>cards.

Это то, что у меня есть до сих пор в моей модели CardSet:

def learnings
  c = Table(Card.table_name)
  l = Table(Learning.table_name)
  j = Table(self.class.send(:join_table_name, Card.table_name, CardSet.table_name))
  learning_sql = l.where(l[:card_id].eq(c[:id])).where(c[:id].eq(j[:card_id])).join(j).on(j[:card_set_id].eq(self.id)).to_sql
  Learning.find_by_sql(learning_sql)
end

что дает мне (черт возьми, Арель прекрасна!):

SELECT     `learnings`.`id`, `learnings`.`card_id`, `learnings`.`user_id`, `learnings`.`ef`, `learnings`.`times_seen`, `learnings`.`next_to_be_seen`, `learnings`.`interval`, `learnings`.`reps`, `learnings`.`created_at`, `learnings`.`updated_at`, `card_sets_cards`.`card_set_id`, `card_sets_cards`.`card_id` FROM       `learnings` INNER JOIN `card_sets_cards` ON `card_sets_cards`.`card_set_id` = 1 WHERE     `learnings`.`card_id` = `cards`.`id` AND `cards`.`id` = `card_sets_cards`.`card_id`

что так близко к тому, к чему я стремлюсь - просто нужно добавить в таблицу cards в части оператора FROM.

И вот мой вопрос: я просмотрел источник Arel, и для жизни я не могу понять, как добавить в другую таблицу.

В качестве примечания, есть ли лучший способ запустить результат от Arel (который обычно возвращает Arel::Relation, что мне не нужно) через ActiveRecord, кроме рендеринга в sql и выполнения запроса с помощью find_by_sql, поскольку я делает?


person bouchard    schedule 30.07.2010    source источник


Ответы (2)


Я не знаком с Arel, но не справится ли:

l.includes(:card)
person AKWF    schedule 05.10.2010
comment
Это вытянет все знания, а не только те, которые связаны с картами, связанными с набором карт (он же вложенный хабтм). - person bouchard; 07.10.2010

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

Если вы пытаетесь заглушить вложенный habtm в модели CardSet, также известный как:

has_many :learnings, :through => :cards

то вы можете использовать это для имитации поведения:

class CardSet < ActiveRecord::Base

  has_and_belongs_to_many :cards, :uniq => true

  def learnings
    Learning.joins(:card).where(:cards => { :id => self.card_ids })
  end
end

тогда будет работать такой запрос:

CardSet.first.learnings
person bouchard    schedule 06.10.2010