如何使用"其中"动态构建realation

时间:2015-10-14 01:28:53

标签: ruby-on-rails ruby ruby-on-rails-4 activerecord

Sry for broken english

我有2个餐桌水果和浆果,2个模型水果和浆果,两个都是主键,浆果的ID是水果的外键。

意思是果子的味道是浆果"浆果"然后这个水果将有hp,atk,def。其他只是一个普通的水果,他们没有hp,atk,def。

我"在哪里"但不起作用,我不知道添加外键来迁移文件

任何解决方案都可以解决这个问题

水果

+-----+------------+-----------+
| id  |    name    |   attr    |
+-----+------------+-----------+
| 123 | Blueberry  | berry     |
| 932 | Apple      | not berry |
| 429 | Banana     | not berry |
| 563 | Strawberry | berry     |
+-----+------------+-----------+

浆果

+-----+----+-----+-----+
| id  | hp | atk | def |
+-----+----+-----+-----+
| 123 | 15 |   5 |   5 |
| 563 |  7 |  10 |   3 |
+-----+----+-----+-----+

水果

class Fruit < ActiveRecord::Base
has_one :berry, -> { where attr: "berry"}, foreign_key: 'id'
end

浆果

class Berry < ActiveRecord::Base
belongs_to :fruit
end

2 个答案:

答案 0 :(得分:1)

首先,bannanas被视为berries ......有时候

至少有两种方法可以做到这一点  Single Table Inheritance(STI)  Multiple Table Inheritance

在STI中,您只在数据库中创建水果表,但添加Berry类所需的所有列。即使这种方法会在数据库中留下许多空白空间,水果也不是浆果,我推荐它,因为它非常直接并且由铁轨支撑。要使用它,请将attr列更改为type,并在迁移中添加hpatkdef列:

rails g migration AddAttrsToFruit hp:integer atk:integer def:integer
rails g migration ChangeAttrToType

由于迁移生成器不会像使用Add一样使用单词Change进行迁移,因此您必须在其创建的迁移中编辑更改函数,如下所示:

rename_column :fruits, :attr, :type

然后将您的Berry类更改为继承自Fruit而不是ActiveRecord :: Base

class Berry < ActiveRecord::Base
  belongs_to :fruit
end

现在当你创建一个Berry

Berry.create(name: 'Coconut', hp:100, atk:5, def:999)

Rails在Fruit表中创建一个记录,其中包含所有属性:

#<ActiveRecord::Relation [#<Berry id: 1, name: nil, type: "Berry", created_at: "2015-10-14 02:38:09", updated_at: "2015-10-14 02:38:09", hp: 1, atk: nil, def: nil>]>

对于MTI,您可以阅读链接。 祝你好运:)

答案 1 :(得分:1)

来自robertoplancarte的精彩回答 - 为您解释一下,您希望使用has_many/belongs_to关系:

enter image description here

#app/models/fruit.rb
class Fruit < ActiveRecord::Base
   has_many :berries
end

#app/models/berry.rb
class Berry < ActiveRecord::Base
   belongs_to :fruit
end

您可以按如下方式在数据库中进行设置:

#fruits
+-----+------------+-----------+
| id  |    name    |   attr    |
+-----+------------+-----------+
| 123 | Blueberry  | berry     |
| 932 | Apple      | not berry |
| 429 | Banana     | not berry |
| 563 | Strawberry | berry     |
+-----+------------+-----------+

#berries
+-----+----------+----+-----+-----+
| id  | fruit_id | hp | atk | def |
+-----+----------+----+-----+-----+
| 1   | 123      | 15 |   5 |   5 |
| 2   | 932      | 10 |   3 |   x |
+-----+----+-----+----+-----+-----+

这将允许您致电...

@fruit = Fruit.find params[:id]
@fruit.berries

robertoplancarte说的是你当前的设置非常弱:

  
      
  1. 你手动识别哪种“水果”是浆果
  2.   
  3. 然后,您将使用可以放入第一个
  4. 的数据填充另一个模型   

解决这个问题的方法是使用名为STI - Single Table Inheritance的东西。

这是使用单个模型定义多个类型数据的Railsy方法:

#app/models/fruit.rb
class Fruit < ActiveRecord::Base
   #columns id | type | name | hp | atk | def | created_at | updated_at 
end

#app/models/berry.rb
class Berry < Fruit
end

这将使您能够致电:

@berry = Berry.find x

这更符合您的要求;有点先进,但StackOverflow上的任何问题都不会被打败。