模拟Rails 3中通过行为嵌套的has_and_belongs_to_many [英] Simulating has_and_belongs_to_many nested through behavior in Rails 3
问题描述
因此,Rails不支持通过habtm关系的关联.有一些插件可以将其添加到Rails 2.x中,但是我使用的是Rails 3/Edge,并且只需要一种特定模型的关联.所以我想我会以Arel的美丽为自己绊倒.
So Rails doesn't have support for :through associations through a habtm relationship. There are plugins out there that will add this in for Rails 2.x, but I'm using Rails 3 / Edge, and only need the association for one particular model. So I thought I'd stump it out myself with the beauty that is Arel.
首先,模型:
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 =>卡片.
I want to get all the learnings that belong to a particular card set, :through => cards.
这是我到目前为止在CardSet模型中所拥有的:
This is what I have so far in my CardSet model:
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
这给了我(该死,阿雷尔很漂亮!):
which gives me (damn, Arel is beautiful!):
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`
这与我要达到的目标非常接近-只需在语句的FROM部分中的cards
表中添加.
which is oh so close to what I'm aiming for - just needs to add in the cards
table in the FROM part of the statement.
还有一个问题:我浏览了Arel的源代码,对于我的一生,我不知道如何在另一个表中进行添加.
And there's my question: I've looked through the Arel source, and for the life of me I can't figure out how to add in another table.
作为一个旁注,除了呈现到sql并使用find_by_sql作为查询来运行查询之外,还有一种更好的方法可以通过ActiveRecord从Arel运行结果(通常返回一个Arel :: Relation,我不希望这样做).我在干嘛?
As a sidenote, is there a better way to run the result from Arel (which usually returns an Arel::Relation, which I don't want) through ActiveRecord, other than rendering to sql and running the query with find_by_sql as I'm doing?
推荐答案
在我了解了Rails如何封装Arel从而不需要直接构建查询之后,这比我上面写的要容易.
This is easier than what I wrote above, after I learned how Rails encapsulates Arel so you don't need to build the query directly.
如果您要在CardSet模型中对嵌套的habtm进行存根处理,也称为:
If you're trying to stub nested habtm in the CardSet model, a.k.a.:
has_many :learnings, :through => :cards
然后您可以使用它来模拟行为:
then you can use this to simulate the behaviour:
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
然后这样的查询将起作用:
then a query like this will work:
CardSet.first.learnings
这篇关于模拟Rails 3中通过行为嵌套的has_and_belongs_to_many的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!