Rails 与多个外键的关联 [英] Rails association with multiple foreign keys
问题描述
我希望能够在一张表上使用两列来定义关系.因此,以任务应用程序为例.
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 one 的 Task.first.owner
和返回 user 的 Task.first.assignee
两个 但 User.first.task
什么都不返回.这是因为任务不属于用户,它们属于owner 和assignee.所以,
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_tasks
和 owned_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屋!