在Rails中与同一模型的多个关联

时间:2016-07-14 12:32:06

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

假设我有一只模型狗,每只狗只有2只猫“敌人”,enemy1enemy2,我如何编写迁移文件,以便我可以调用dog.enemy1检索第一个敌人并dog.enemy2检索第二个敌人? 我试过这个:

create_table :dog do |t|
    t.string :name
    t.timestamps null: false
    end
    add_index :dog, :name

    add_foreign_key :dogs, :cats, column: :enemy1_id
    add_foreign_key :dogs, :cats, column: :enemy2_id
end

我也尝试使用t.references方法,但无法使其正常工作。几个小时以来一直在研究这个问题。它在开发中工作正常但在Heroku Postgres上没有。 我得到的错误是

ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR:column     "enemy1_id" referenced in foreign key constraint does not exist.

有什么想法吗?

4 个答案:

答案 0 :(得分:3)

迁移:

Service

狗模型:

create_table :dog do |t|
  t.string :name
  t.integer :enemy1_id
  t.integer :enemy2_id
  t.timestamps null: false
end

答案 1 :(得分:0)

我刚刚解决了它,第一个答案进来后2秒...... 最后。

class CreateDogs < ActiveRecord::Migration
def change
    create_table :dogs do |t|
        t.string :name
        t.references :enemy1, index: true
        t.references :enemy2, index: true

        t.timestamps null: false
    end
    add_index :dogs, :name

    add_foreign_key :dogs, :cats, column: :enemy1_id
    add_foreign_key :dogs, :cats, column: :enemy2_id
end

答案 2 :(得分:0)

rails中没有'has_two'关联。所以你应该与has_many协会达成和解。

class Dog < ActiveRecord::Base
  has_many :cats, limit: 2

  scope :enemy1, Proc.new { |object| object.cats.first }
  scope :enemy2, Proc.new { |object| object.cats.last }
end
中的

class Cat < ActiveRecord::Base
  belongs_to :dog
end

现在,创建cat的迁移应该有

t.references :dog

您的狗模型中不需要外国字段。这应该可以解决你的问题。

答案 3 :(得分:0)

Rails Way不应该在迁移中这样做。我认为,迁移是一种定义数据将要存在的结构的工具。

Rails Way建议您在Cat的Dog类上建立一个has_many关联

class Dog < ApplicationRecord
  # ... other code ...
  has_many :enemies, class_name: Cat
  # ... other code ...
end

您还必须在Cat中定义归属关联

class Cat < ApplicationRecord
  # ... other code ...
  belongs_to :dog
  # ... other code ...
end

请注意,cats表应定义为对dogs表的引用。因此,您对cats表的迁移应显示为

class CreateCats < ActiveRecord::Migration[5.x]
  create_table :cats do |t|
    # ... other code ...
    t.references :dog
    # ... other code ...
  end
end

通过这些设置,您应该在Dog类中定义enemy_oneenemy_two

class Dog < ApplicationRecord
  # ... other code ...
  def enemy_one
    enemies.first
  end

  def enemy_two
    enemies.second
  end
  # ... other code ...
end

要使事情变得更加严格,您可以决定添加一个验证(创建时),该验证检查每只狗是否只有两个猫被创建为敌人。此外,当狗达到敌人的限制时,您可以隐藏创建按钮(或常规访问权限)。这是我的决定权。

p.s:所有这些限制也可以在数据库层中完成。但是应用程序层在这里将所有内容抽象出来。