ruby-on-rails - Rails - 多索引键关联

标签 ruby-on-rails database-design activerecord indexing

似乎有多种方法可以处理多外键关联。我处理这个问题的每一种方式都有其缺点,因为我是 Rails 的新手,我相信其他人也遇到过类似的情况,我可能正在研究很久以前解决的问题。

我的问题是:

处理多索引键关联的有效方法是什么,同时仍保留所有其他 Rails sql 修饰符(例如 :include 等)?

我的场景是:

我有一个表关联如下(简化),用于通过链接将人们与其他人联系起来:

People
+----+-----------+
| id | name      |
+----+-----------+
| 1  | Joe       |
+----+-----------+
| 2  | Sally     |
+----+-----------+
| 3  | Bob       |
+----+-----------+                

Links
+----+-----------+---------+
| id | origin_id | rcvd_id |
+----+-----------+---------+
| 1  | 2         | 1       |
+----+-----------+---------+
| 2  | 1         | 3       |
+----+-----------+---------+                        
| 3  | 3         | 2       |
+----+-----------+---------+                        

从上面链接表的第 1 行,可以看到一个人(Sally = 2)链接到另一个人(Joe = 1)。

如果我的外键是“origin_id”,我很容易找到所有人员链接。但这只会显示发起链接的人。在我的场景中,我需要查看所有链接,无论它们是由个人发起还是接收的。例如,如果我要询问 Sally 的所有链接(Sally = 2),我想要的结果是:
Links
+----+-----------+---------+
| id | origin_id | rcvd_id |
+----+-----------+---------+
| 1  | 2         | 1       |
+----+-----------+---------+                        
| 3  | 3         | 2       |
+----+-----------+---------+                        

因此我有 2 个索引键,“origin_id”和“rcvd_id”。

可以解决的一种方法是使用方法:
class Person < ActiveRecord::Base
  has_many  :link_origins,  :class_name => "Link", :foreign_key => :origin_id, :dependent => :destroy
  has_many  :link_rcvds,    :class_name => "Link", :foreign_key => :rcvd_id, :dependent => :destroy

def links
  origin_person + rcvd_person
end

然而,这效率不高。例如,这需要从数据库中收集整个集合,然后才能使用 paginate 方法(我正在使用 will_paginate gem),因为 paginate 应该通过限制调用的记录数来加速该过程。整个收集完成后不限制记录。

此外,上面不允许我调用例如 Joe.links(:first).origin_id.name。不完全是这段代码,但意味着我无法在所选链接的 origin_id 上调用 Person 详细信息,因为 links 方法不知道 origin_id 与 People 表相关。

到目前为止,最可行的解决方案似乎是 :finder_sql。
class Person < ActiveRecord::Base
  has_many :links, :finder_sql => 'SELECT * FROM links WHERE (links.origin_id = #{id} or links.rcvd_id = #{id})'

这给出了 Person_id 匹配 Links.origin_id 或 Links.rcvd_id 的所有链接。

此选项的缺点是使用 :finder_sql 排除了自 Rails 以来的所有其他 sql 修饰符
不知道如何解析和修改您提供的 SQL。例如,我将无法将 :include 选项与 :finder_sql 一起使用。

所以,现在我正在使用 :finder_sql, 解决方案。但似乎以不需要 :finder_sql 的方式完成此关联可能还有一段距离。例如,有没有办法在保留 Active Record 提供的 Rails sql 修饰符的同时编写自定义 sql 字符串。

对以上有什么想法吗?

最佳答案

我确实找到了解决方案,但结果证明我可能问错了问题。我没有发现有多个索引键,因为我没有实现一些自定义 sql 来破坏不同的 Rails 助手。

我想我的问题仍然存在,但我如何解决这个问题是从不同的角度看待问题。我刚刚创建了关联,因为它们是:

belongs_to :rcvd_person, :class_name => 'Person', :foreign_key => :rcvd_id
belongs_to :origin_person, :class_name => 'Person', :foreign_key => :origin_id

和一个自定义的 sql 语句:
class Person...
  has_many :links, :finder_sql => 'SELECT * FROM links WHERE origin_id = #{id} OR rcvd_id = #{id}'
end

然后我就可以在我的视野中以我想要的方式操纵记录。如果其他人正在做类似的事情,我做了:
<% person.links.each do |link| %> 

  <% if link.origin_id == person.id %>
    <%= link.rcvd_person.given_name %>
  <% else %>
    <%= link.origin_person.given_name %>
  <% end  %>

<% end %>

关于ruby-on-rails - Rails - 多索引键关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3421873/

相关文章:

ruby-on-rails - 避免 `save!` on Has Many Through Association

ruby-on-rails - 从文件系统而不是数据库提供我的文本?

mysql - ruby on Rails 数据库错误

ruby-on-rails - ActiveRecord - 嵌套包含

mysql - 当其他链接表中的行更新时如何自动更新时间戳

mysql - 如果其中一个连接表具有另一个连接表的外键,如何执行两个连接表的连接?

ruby-on-rails - 在 Ruby on Rails 5 中禁用 ActiveRecord

ruby-on-rails - Rails 中的 Gmail 推送通知

ruby-on-rails - 如何使用 nokogiri 生成器生成 xml

node.js - 这是一个好的 Web 应用程序架构吗?