Rails INNER JOIN 期望字段 "id" 尚不存在

Rails INNER JOIN expecting field "id" that does not yet exist

简短版本:我需要使用自定义内部联接在一个 table 中查找 ID,其中两个字段在 Rails 中的两个 table 中都匹配,但是 Rails inner join 对我不知道如何解决的关系做出假设。

长版:我接手了一个 Rails 项目,它有一个非规范化的数据库。我将一些信息提取到一个新的 table 中,现在我需要遍历每个条目并在原始 table 上放置一个外键,但我无法提出正确的 ActiveRecord 查询抢资料

在这种情况下,一个集合属于一个存储库,一个存储库可能有多个集合。

该项目最初将所有集合和存储库存储在同一个 table 中,如果它是一个存储库,则集合名称为 NULL,如果它是一个集合,则同时使用存储库名称和集合名称。我创建了一个迁移,它采用所有唯一的存储库名称并将它们粘贴在存储库 table 中。现在我需要做的是返回集合 table 并根据字符串 repname 从匹配的存储库中添加 id。

我在 SQL 中有一个提取正确数据的查询:

ActiveRecord::Base.connection.execute("SELECT r.id, r.repname FROM collections c, repositories r WHERE c.repname = r.repname")

然而,我在与该对象交互时遇到问题(出现 "undefined method 'last' for # Mysql2::Result..." 之类的错误),我更希望我知道 Rails 模型中的所有设置都正确。

当我尝试此操作时出现错误:

Repository.joins(:collections).where("collections.repname = repositories.repname")
Repository Load (1.0ms)  SELECT `repositories`.* FROM `repositories` INNER JOIN `collections` 
ON `collections`.`repository_id` = `repositories`.`id` WHERE (collections.repname = repositories.repname)

Mysql2::Error: Unknown column 'collections.repository_id' in 'on clause': SELECT `repositories`.* FROM `repositories` INNER JOIN `collections` ON `collections`.`repository_id` = `repositories`.`id` WHERE (collections.repname = repositories.repname)
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'collections.repository_id' in 'on clause': SELECT `repositories`.* FROM `repositories` INNER JOIN `collections` ON `collections`.`repository_id` = `repositories`.`id` WHERE (collections.repname = repositories.repname)

我对 Rails 和 SQL 都是新手,所以我认为我的问题实际上可能在于我如何设置模型。我正在使用数据库的现有命名约定...也许我应该改用 Rails repository_id 约定?

class Collection < ActiveRecord::Base
  has_many :archive_object_collections, :foreign_key => :collid, :primary_key => :collid
  has_many :archive_object, :through => :archive_object_collections
  belongs_to :repository, :foreign_key => "repid"
end

class Repository < ActiveRecord::Base
  has_many :collections
end

我担心切换到 repository_id 不会解决问题,但是,因为集合 table 上还没有任何类型的 ID。这就是为什么我需要 运行 这个查询,所以我可以找到该信息并将其作为外键插入到集合 table 中。我在集合 class 中尝试了没有 foreign_key 的内部连接查询,没有任何变化。

抱歉这个冗长而曲折的问题。有人有什么建议吗?谢谢!

我认为你应该在存储库模型中定义 foreign_key

class Repository < ActiveRecord::Base
  has_many :collections, :primay_key => 'somekey',  :foreign_key => 'repid'
end

然后您可以 运行 一个简单的连接查询,以根据您的查询获取结果。

Repository.select('repositories.*, collections.*').where("repositories.col1 = ? AND collections.col2 = ?", val1, val2)

否则,如果您想摆脱这些类型的键定义,那么最好开始使用 rails 约定。将外键定义为 model_id。在这种情况下,您不必定义键名。

我决定遍历集合和存储库 table 并手动匹配它们。这就是我最终做的:

class AddForeignKeyToColl < ActiveRecord::Migration
  def up
    # Add a repid to the collections
    add_column :collections, :repository_id, :integer

    # Need to go through all of the repositories
    # and match their name against the repname of the collections
    # Then, if they match, add the repository id to the collection as repid
    repos = Repository.all
    colls = Collection.all
    repos.each do |repo|
      rname = repo.repname
      colls.each do |coll|
        if coll.repname == rname
          coll.update_attributes(:repository_id => repo.id)
        end
      end
    end
  end

  def down
    raise ActiveRecord::IrreversibleMigration
  end
end

好像有用!