2

编辑于 30 日,03:16,以显示改进的迁移和模型

我有一个元素表,每个元素都可以连接到许多其他元素。在 Rails 的迁移和模型中可以做到这一点吗?(以下是用SQL实现的)

元素表:具有整数 id 主键字段以及其他字段。

元素间链接表:

CREATE TABLE inter_element_links
(
  element1_id integer NOT NULL,
  element2_id integer NOT NULL,
  CONSTRAINT inter_element_links_pkey PRIMARY KEY (element1_id, element2_id),
  CONSTRAINT foreign_key_on_id1 FOREIGN KEY (element1_id)
      REFERENCES elements (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT foreign_key_on_id2 FOREIGN KEY (element2_id)
      REFERENCES elements (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

此查询返回通过其 id 链接到特定元素的所有元素,例如 3:

SELECT *
FROM elements
INNER JOIN inter_element_links ON (elements.id = inter_element_links.element1_id
  OR elements.id = inter_element_links.element2_id)
WHERE (inter_element_links.element1_id = 3 OR inter_element_links.element2_id = 3)
AND elements.id <> 3

这在 Postgres 中有效,我想翻译成 Rails,但正在努力为 Rails 找到解决方案……我在做什么是愚蠢的,还是只是不那么常见?

到目前为止,我有迁移(它有一个假的复合主键,没有引用 elements.id 的外键):

class CreateInterElementLinks < ActiveRecord::Migration
  def self.up
    create_table :inter_element_links, :id => false do |t|
      t.integer :element1_id, :null => false
      t.integer :element2_id, :null => false
    end
    add_index :inter_element_links, [:element1_id, :element2_id], :unique => true
  end

  def self.down
    remove_index :inter_element_links, [:element1_id, :element2_id]
    drop_table :inter_element_links
  end
end

并有以下型号:

class Element < ActiveRecord::Base
  belongs_to :user
  has_many :inter_element_links1, :foreign_key => 'element1_id', :class_name => 'InterElementLink', :dependent => :destroy
  has_many :inter_element_links2, :foreign_key => 'element2_id', :class_name => 'InterElementLink', :dependent => :destroy
  has_many :elements1, :through => :inter_element_links1
  has_many :elements2, :through => :inter_element_links2

  def inter_element_links  ## Unless there's a more elegant rails solution, I will try to extend ActiveRecord::HasManyThroughAssociation, so things like:  an_element.destroy, will destroy the entry in the inter_element_links table, and calls to an_element.elements will work.
    inter_element_links1 + inter_element_links2
  end

  def elements
    elements1 + elements2
  end
end

class InterElementLink < ActiveRecord::Base
  set_primary_keys :element1_id, :element2_id   ## I have included the 'composite_primary_keys', '=3.1.0' gem
  belongs_to :element
end

任何想法将不胜感激!


在过去的 24 小时内,我发现了一些似乎很接近但还没有完全让我明白的事情:

非常感谢!

4

0 回答 0