使用ActiveRecord关系包含每行对象的多个实例

时间:2013-04-18 19:54:13

标签: ruby-on-rails ruby activerecord relationships

我试图弄清楚如何使用ActiveRecord关系来关联可以在一行中包含另一个模型的多个实例的模型。例如,在一个模型中使用has_many:dogs,在另一个模型中使用belongs_to:dog表示在一个模型中,“dog_id”将引用一个实例:dog。但是,我希望能够在我的相关(has_many)模型中有多个:dog实例,例如dog_id1,dog_id2,dog_id3等。请参阅下面的代码以了解我的意思。我怎么能这样做?

我有以下型号:

--tp.rb
class Tp < ActiveRecord::Base
  has_many :dogs
  has_many :cats
  has_many :stars
  attr_accessible :dog_id1, :dog_id2, :dog_id3, :dog_id4, :cat_id1, :cat_id2, :cat_id3, :cat_id4, :star_id, :tp_id
end

--dog.rb
class Dog < ActiveRecord::
  belongs_to :tp
  attr_accessible :dog_id, :dog_name
end

--cat.rb
class Cat < ActiveRecord::Base
  belongs_to :tp
  attr_accessible :cat_id, :cat_name
end

--star.rb
 class Star < ActiveRecord::Base
   belongs_to :tp
   attr_accessible :patient_id
 end

3 个答案:

答案 0 :(得分:1)

我认为你的belongs_to / has_many有点倒退了。

belongs_to和has_many

对于您的示例,

class Tp < ActiveRecord::Base
  has_many :dogs
  has_many :cats
  has_many :stars
end

Tp在其数据库行中没有任何dog_idcat_idstar_id。在其他模型中设置belongs_to时,

class Dog < ActiveRecord::Base
  belongs_to :tp
end

class Cat < ActiveRecord::Base
  belongs_to :tp
end

class Star < ActiveRecord::Base
  belongs_to :tp
end

您应该为每个模型(tp_id表,dogs表和cats表添加stars

然后,拨打

tp = Tp.find(123)

查找Tp id等于123

SELECT * FROM tps WHERE id = 123;

并致电

cats = tp.cats
dogs = tp.dogs
stars = tp.stars

查找所有CatDogStar个实例tp_id等于123

SELECT * FROM cats WHERE tp_id = 123;
SELECT * FROM dogs WHERE tp_id = 123;
SELECT * FROM stars WHERE tp_id = 123;

如果您需要Cat个实例属于许多Tp个实例,而Tp个实例需要有许多Cat个实例,那么您应该查看Rails的{{3 }或has_and_belongs_to_many

has_and_belongs_to_many

has_and_belongs_to关系需要新表cats_tpsdogs_tpsstars_tps。这些表的架构为

cats_tps
  cat_id
  tp_id
dogs_tps
  dog_id
  tp_id
stars_tps
  star_id
  tp_id

然后在你的模特中

class Tp < ActiveRecord::Base
  has_and_belongs_to_many :dogs
  has_and_belongs_to_many :cats
  has_and_belongs_to_many :stars
end

class Dog < ActiveRecord::Base
  has_and_belongs_to_many :tps
end

class Cat < ActiveRecord::Base
  has_and_belongs_to_many :tps
end

class Star < ActiveRecord::Base
  has_and_belongs_to_many :tps
end

现在,正在运行

tp = Tp.find(123)
cats = tp.cats

生成SQL

SELECT "cats".* FROM "cats" INNER JOIN "cats_tps" ON "cats"."id" = "cats_tps"."cat_id" WHERE "cats_tps"."tp_id" = 123;

这是查询的必要条件(给我一个属于Tp 123的所有cat_ids的列表)然后(给我所有匹配这些猫ID的猫)。

生成cats_tps联接表可以通过像

这样的迁移来完成
class CreateCatsTps < ActiveRecord::Migration
  def change
    create_table :cats_tps, :id => false do |t|
      t.belongs_to :cat
      t.belongs_to :tp
    end
  end
end

这适用于简单连接,但您可能希望使用has_many :through。这是因为cats_tps表格中没有关于此Cat何时或为何属于Tp或此Tp属于Cat的信息。同样,如果您添加BirdHorseFrogSnake模型,则必须创建birds_tpshorses_tps,{{ 1}}和frogs_tps表。呸。

has_many:通过

要创建snakes_tps关系,您需要创建一个在语义上有意义的新模型,该模型将has_many :through链接到Tp。例如,让我们说Cat走猫。您可以创建一个Tp模型,将WalkCat相关联。

Tp

现在,该关系类似于class Walk < ActiveRecord::Base belongs_to :cat belongs_to :tp attr_accessible :price, :duration, :interval # these attributes describe the Walk relationship end class Cat < ActiveRecord::Base has_many :walks has_many :tps, :through => :walks end class Tp < ActiveRecord::Base has_many :walks has_many :cats, :through => :walks end ,但您可以包含有关步行关系的元数据。另外,假设has_and_belongs_to_many还会遛狗。您可以将Tp转换为多态belongs_to :cat关系,以便belongs_to :animal可以走猫,狗,老鼠,兔子,马......你的名字。

Tp

此关系是使用

等迁移创建的
class Walk < ActiveRecord::Base
  belongs_to :animal, :polymorphic => true
  belongs_to :tp
  attr_accessible :price, :duration, :interval # these attributes describe the Walk relationship
end

class Cat < ActiveRecord::Base
  has_many :walks, :as => :animal
  has_many :tps, :through => :walks
end

class Dog < ActiveRecord::Base
  has_many :walks, :as => :animal
  has_many :tps, :through => :walks
end

class Tp < ActiveRecord::Base
  has_many :walks
  has_many :cats, :through => :walks, :source => :animal, :source_type => 'Cat'
  has_many :dogs, :through => :walks, :source => :animal, :source_type => 'Dog'
end

答案 1 :(得分:0)

这是错误的

attr_accessible :dog_id1, :dog_id2, :dog_id3, :dog_id4, :cat_id1, :cat_id2, :cat_id3, :cat_id4, :star_id, :tp_id

您的狗模型有一个tp_idhas_manybelongs_to允许您tp_instance.dogs获取一系列匹配的{{1}狗模型}

答案 2 :(得分:0)

从TP模型中移除:dog_id(s)并将:tp_id放入您的狗模型中。这将允许您从TP到Dog有一对多的关系