[英]Rails query using more then one has_many through associations
Hi I have 6 models with relations with each other: 嗨,我有6个相互关联的模型:
Spell model which can have many tags and elements and one ring(aka level) 可以具有多个标签和元素以及一个环(也称为级别)的咒语模型
class Spell < ActiveRecord::Base
belongs_to :spell_ring
has_many :element_of_spells, dependent: :destroy
has_many :spell_elements, through: :element_of_spells
has_many :tag_of_spells, dependent: :destroy
has_many :spell_tags, through: :tag_of_spells
validates_presence_of :name
end
Spell element which can have many spells 可以有很多咒语的咒语元素
class SpellElement < ActiveRecord::Base
has_many :element_of_spells, dependent: :destroy
has_many :spells, through: :element_of_spells
end
Spell tag, which can have many spells: 咒语标记,可以包含许多咒语:
class SpellTag < ActiveRecord::Base
has_many :tag_of_spells, dependent: :destroy
has_many :spells, through: :tag_of_spells
end
Spell ring: 咒语环:
class SpellRing < ActiveRecord::Base
has_many :spells
end
And join models: 并加入模型:
class ElementOfSpell < ActiveRecord::Base
belongs_to :spell
belongs_to :spell_element
end
class TagOfSpell < ActiveRecord::Base
belongs_to :spell
belongs_to :spell_tag
end
Ok now I want to put them to good use :) 好吧,现在我想好好利用它们了:)
What I know: 我知道的:
That if I take any spell_tag or spell_element or spell_ring object, I can get all associated spells. 如果我带了任何spell_tag或spell_element或spell_ring对象,那么我可以获得所有关联的咒语。
element = SpellElement.first
spells_of_element = element.spells >> give me all associated spells
I know I can scope this with spell_ring_id
since it is part of the spell object. 我知道我可以使用
spell_ring_id
范围,因为它是spell对象的一部分。
spell_ring = SpellRing.first
spells_of_element_and_ring = spells_of_element.where( spell_ring_id: spell_ring.id ) >> returns spells of given element and ring
What I don`t know: 我不知道的是:
How to scope spells_of_element_and_ring
with given tag. 如何用给定的标签来
spells_of_element_and_ring
范围。
tag = SpellTag.first
spells_of_element_ring_and_tag = ??
Updated 更新
What I want? 我想要的是?
Is to be able to query spells: 是为了能够查询拼写:
and any combination of those three models. 以及这三个模型的任意组合。
It's a good idea, when posting to StackOverflow, to weed out as much code as possible, and really boil your question down to the simplest possible example. 在发布到StackOverflow时,最好删除尽可能多的代码,然后将您的问题归结为最简单的示例,这是一个好主意。 This will get quicker answers, and also be useful to more people.
这将获得更快的答案,并且对更多人有用。
Let's start out with the simpler example of a school, which has many classrooms, and each classroom has many students. 让我们从一个简单的学校示例开始,该学校有很多教室,每个教室有很多学生。
Let's create our models: 让我们创建模型:
rails generate model school name:string
rails generate model classroom school_id:integer grade:integer
rails generate model student name:string classroom_id:integer
Now let's create our associations: 现在让我们创建关联:
class School < ActiveRecord::Base
has_many :classrooms
has_many :students, through: :classrooms
end
class Classroom < ActiveRecord::Base
belongs_to :school
has_many :students
end
class Student < ActiveRecord::Base
belongs_to :classroom
end
Finally, we'll create three quick records: 最后,我们将创建三个快速记录:
school = School.create name: 'City Elementary'
classroom = school.classrooms.create grade: 4
student = classroom.students.create name: 'Bob'
Now we can get a list of all students at the school like so: 现在,我们可以像这样获取学校所有学生的列表:
school.students
This works because a school has_many
students, through
classrooms. 之所以
has_many
,是因为学校through
教室有很多学生。
I think what you actually want is a little more complicated - a spell can have many elements, and an element can belong to many spells. 我认为您实际想要的有点复杂-一个咒语可以包含许多元素,而一个元素可以属于许多咒语。 In this case, you need a "join table".
在这种情况下,您需要一个“联接表”。 Let's simplify your example by eliminating everything except spells and elements.
让我们通过消除除咒语和元素之外的所有内容来简化示例。
We start by creating our models: 我们首先创建模型:
rails generate model spell name:string
rails generate model element name:string
Now we create a join table, which keeps track of which spells and elements belong to each other: 现在,我们创建一个联接表,该表跟踪哪些咒语和元素彼此所属:
rails generate migration create_elements_spells element_id:integer spell_id:integer
Now we define our associations (relationships): 现在,我们定义关联(关系):
class Element < ActiveRecord::Base
has_and_belongs_to_many :spells
end
class Spell < ActiveRecord::Base
has_and_belongs_to_many :elements
end
has_and_belongs_to_many
automatically looks for a table with the combined name of the two models, in plural form, in alphabetical order. has_and_belongs_to_many
自动以字母顺序以复数形式查找具有两个模型的组合名称的表。 Now we can do things like: 现在我们可以做类似的事情:
spell = Spell.create name: 'set on fire'
flint = Element.create name: 'flint'
steel = Element.create name: 'steel'
spell.elements << flint
spell.elements << steel
Now, spell.elements
lists both flint and steel. 现在,
spell.elements
列出了火石和钢铁。 flint.spells
will list our 'set on fire' spell. flint.spells
将列出我们的“放火”咒语。 steel.spells
will also list our spell. steel.spells
也会列出我们的咒语。 You can expand from there. 您可以从那里扩展。
But what if you need to know more than just what element - what if you need to know how much? 但是,如果您不仅需要了解什么元素,该怎么办-如果您需要了解多少,该怎么办? now you have extra data that doesn't belong in the Spell record or the Element record.
现在您有了额外的数据,这些数据不属于Spell记录或Element记录。 It belongs on the association itself.
它属于协会本身。 We might call an element/amount combo an "ingredient", and create a table for it like so:
我们可以将元素/数量组合称为“成分”,并为其创建一个表,如下所示:
rails generate model ingredient spell_id:integer element_id:integer amount:string
And we update our associations: 并且我们更新了关联:
class Element < ActiveRecord::Base
has_many :ingredients
has_many :spells, through: :ingredients
end
class Spell < ActiveRecord::Base
has_many :ingredients
has_many :elements, through: :ingredients
end
class Ingredient < ActiveRecord::Base
belongs_to :element
belongs_to :spell
end
Now we can add ingredients to our spell: 现在,我们可以为我们的咒语添加成分:
spell.ingredients.create element: flint, amount: '1 gram'
spell.ingredients.create element: steel, amount: '1 piece'
So spell.ingredients
will list both flint and steel, and the amounts for each. 因此,
spell.ingredients
将同时列出火石和钢铁,以及每种的含量。 This should get you well on your way to building you application. 这应该使您在构建应用程序的过程中顺利进行。
@Jaime explain querying through the whole process very good. @Jaime解释了整个查询过程非常好。 But I wanted my query to be more flexible.
但是我希望查询更加灵活。
I don't know it this is the Rails way. 我不知道这是Rails的方式。 But I found something like this to fit me the best.
但是我发现这样的东西最适合我。
Because SpellElement.spells, SpellRing.spells, SpellTag.spells all returns an array. 因为SpellElement.spells,SpellRing.spells,SpellTag.spells都返回一个数组。 My idea is to just compare them and return only matched elements as a result.
我的想法是只比较它们,结果只返回匹配的元素。
So 所以
spell_element_ring_and_tag = some_spell_element.spells & some_spell_ring.spells & some_spell_tag.spells
Will return only spell objects shared by all three arrays. 将仅返回所有三个数组共享的咒语对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.