Rails 与多个外键的关联 [英] Rails association with multiple foreign keys

查看:23
本文介绍了Rails 与多个外键的关联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够在一张表上使用两列来定义关系.因此,以任务应用程序为例.

I want to be able to use two columns on one table to define a relationship. So using a task app as an example.

尝试 1:

class User < ActiveRecord::Base
  has_many :tasks
end

class Task < ActiveRecord::Base
  belongs_to :owner, class_name: "User", foreign_key: "owner_id"
  belongs_to :assignee, class_name: "User", foreign_key: "assignee_id"
end

那么Task.create(owner_id:1,assignee_id:2)

这允许我执行返回 user oneTask.first.owner 和返回 user 的 Task.first.assignee两个User.first.task 什么都不返回.这是因为任务不属于用户,它们属于ownerassignee.所以,

This allows me to perform Task.first.owner which returns user one and Task.first.assignee which returns user two but User.first.task returns nothing. Which is because task doesn't belong to a user, they belong to owner and assignee. So,

尝试 2:

class User < ActiveRecord::Base
  has_many :tasks, foreign_key: [:owner_id, :assignee_id]
end

class Task < ActiveRecord::Base
  belongs_to :user
end

这完全失败了,因为似乎不支持两个外键.

That just fails altogether as two foreign keys don't seem to be supported.

所以我想要的是能够说 User.tasks 并获得用户拥有和分配的任务.

So what I want is to be able to say User.tasks and get both the users owned and assigned tasks.

基本上以某种方式建立一个关系,它等于查询Task.where(owner_id ||assignee_id == 1)

Basically somehow build a relationship that would equal a query of Task.where(owner_id || assignee_id == 1)

这可能吗?

我不打算使用 finder_sql,但这个问题的未接受答案看起来与我想要的很接近:Rails - 多索引键关联

I'm not looking to use finder_sql, but this issue's unaccepted answer looks to be close to what I want: Rails - Multiple Index Key Association

所以这个方法看起来像这样,

So this method would look like this,

尝试 3:

class Task < ActiveRecord::Base
  def self.by_person(person)
    where("assignee_id => :person_id OR owner_id => :person_id", :person_id => person.id
  end 
end

class Person < ActiveRecord::Base

  def tasks
    Task.by_person(self)
  end 
end

虽然我可以让它在 Rails 4 中工作,但我不断收到以下错误:

Though I can get it to work in Rails 4, I keep getting the following error:

ActiveRecord::PreparedStatementInvalid: missing value for :owner_id in :donor_id => :person_id OR assignee_id => :person_id

推荐答案

TL;DR

class User < ActiveRecord::Base
  def tasks
    Task.where("owner_id = ? OR assigneed_id = ?", self.id, self.id)
  end
end

删除User 类中的has_many :tasks.

使用 has_many :tasks 完全没有意义,因为我们在表 tasks 中没有任何名为 user_id 的列.

Using has_many :tasks doesn't make sense at all as we do not have any column named user_id in table tasks.

我为解决这个问题所做的工作是:

What I did to solve the issue in my case is:

class User < ActiveRecord::Base
  has_many :owned_tasks,    class_name: "Task", foreign_key: "owner_id"
  has_many :assigned_tasks, class_name: "Task", foreign_key: "assignee_id"
end

class Task < ActiveRecord::Base
  belongs_to :owner,    class_name: "User", foreign_key: "owner_id"
  belongs_to :assignee, class_name: "User", foreign_key: "assignee_id"
  # Mentioning `foreign_keys` is not necessary in this class, since
  # we've already mentioned `belongs_to :owner`, and Rails will anticipate
  # foreign_keys automatically. Thanks to @jeffdill2 for mentioning this thing 
  # in the comment.
end

这样,您可以调用User.first.assigned_tasks 以及User.first.owned_tasks.

This way, you can call User.first.assigned_tasks as well as User.first.owned_tasks.

现在,您可以定义一个名为 tasks 的方法,该方法返回 assigned_tasksowned_tasks 的组合.

Now, you can define a method called tasks that returns the combination of assigned_tasks and owned_tasks.

就可读性而言,这可能是一个很好的解决方案,但从性能的角度来看,它不会像现在那么好,为了获得 tasks,两个查询将被发出而不是一次,然后,这两个查询的结果也需要连接起来.

That could be a good solution as far the readability goes, but from performance point of view, it wouldn't be that much good as now, in order to get the tasks, two queries will be issued instead of once, and then, the result of those two queries need to be joined as well.

因此,为了获取属于用户的任务,我们将在 User 类中定义一个自定义的 tasks 方法,如下所示:

So in order to get the tasks that belong to a user, we would define a custom tasks method in User class in the following way:

def tasks
  Task.where("owner_id = ? OR assigneed_id = ?", self.id, self.id)
end

这样,它将在一个查询中获取所有结果,而我们不必合并或组合任何结果.

This way, it will fetch all the results in one single query, and we wouldn't have to merge or combine any results.

这篇关于Rails 与多个外键的关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆