通过关联

时间:2016-03-09 06:00:34

标签: ruby-on-rails database

您好我有6个模特彼此关系:

拼写模型,可以有许多标签和元素以及一个戒指(也称为等级)

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

可以有多个法术的法术元素

class SpellElement < ActiveRecord::Base

  has_many :element_of_spells, dependent: :destroy
  has_many :spells, through: :element_of_spells
end

法术标记,可以有多个法术:

class SpellTag < ActiveRecord::Base

  has_many :tag_of_spells, dependent: :destroy
  has_many :spells, through: :tag_of_spells
end

法术戒指:

class SpellRing < ActiveRecord::Base

  has_many :spells
end

加入模特:

class ElementOfSpell < ActiveRecord::Base
  belongs_to :spell
  belongs_to :spell_element
end

class TagOfSpell < ActiveRecord::Base
  belongs_to :spell
  belongs_to :spell_tag
end

好的,现在我想好好利用它们:)

我所知道的:

如果我使用任何spell_tag或spell_element或spell_ring对象,我可以获得所有相关法术。

element = SpellElement.first
spells_of_element = element.spells >> give me all associated spells

我知道我可以用spell_ring_id来限制它,因为它是拼写对象的一部分。

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

我不知道的事情:

如何使用给定标记范围spells_of_element_and_ring

tag = SpellTag.first

spells_of_element_ring_and_tag = ?? 

更新

我想要什么?

能够查询法术:

  • by spell_tags
  • by spell_rings
  • by spell_elements

以及这三种模式的任意组合。

2 个答案:

答案 0 :(得分:1)

在发布到StackOverflow时,最好尽可能多地清除代码,并将问题归结为最简单的示例。这将获得更快的答案,也对更多人有用。

让我们从一个简单的学校例子开始,这个学校有很多教室,每个教室都有很多学生。

让我们创建我们的模型:

rails generate model school name:string
rails generate model classroom school_id:integer grade:integer
rails generate model student name:string classroom_id:integer

现在让我们创建我们的关联:

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

最后,我们将创建三个快速记录:

school = School.create name: 'City Elementary'
classroom = school.classrooms.create grade: 4
student = classroom.students.create name: 'Bob'

现在我们可以像这样得到学校所有学生的名单:

school.students

这是因为学校has_many学生,through教室。

我认为你真正想要的是一点点复杂 - 一个咒语可以有很多元素,一个元素可以属于许多咒语。在这种情况下,您需要一个“连接表”。让我们通过消除除法术和元素之外的所有内容来简化您的示例。

我们首先创建模型:

rails generate model spell name:string
rails generate model element name:string

现在我们创建一个连接表,跟踪哪些法术和元素彼此属于:

rails generate migration create_elements_spells element_id:integer spell_id:integer

现在我们定义我们的关联(关系):

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按字母顺序自动查找具有两个模型组合名称的表格,复数形式。现在我们可以做以下事情:

spell = Spell.create name: 'set on fire'

flint = Element.create name: 'flint'
steel = Element.create name: 'steel'

spell.elements << flint
spell.elements << steel

现在,spell.elements列出了燧石和钢铁。 flint.spells会列出我们的'火上浇油'法术。 steel.spells也会列出我们的咒语。你可以从那里扩展。

但是如果你需要了解的不仅仅是什么元素 - 如果你需要知道多少呢?现在您有额外的数据不属于拼写记录或元素记录。它属于协会本身。我们可能将元素/数量组合称为“成分”,并为其创建一个表格,如下所示:

rails generate model ingredient spell_id:integer element_id:integer amount:string

我们更新了我们的协会:

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

现在我们可以为我们的法术添加成分:

spell.ingredients.create element: flint, amount: '1 gram'
spell.ingredients.create element: steel, amount: '1 piece'

因此spell.ingredients将列出燧石和钢材,以及每种材料的数量。这应该可以帮助您构建应用程序。

答案 1 :(得分:0)

@Jaime解释整个过程非常好。但我希望我的查询更灵活。

我不知道这是Rails方式。但我发现这样的东西最适合我。

因为SpellElement.spells,SpellRing.spells,SpellTag.spells都返回一个数组。我的想法是只比较它们并仅返回匹配的元素。

所以

spell_element_ring_and_tag = some_spell_element.spells & some_spell_ring.spells & some_spell_tag.spells

将仅返回所有三个阵列共享的拼写对象。