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

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

问题描述

我希望能够使用在一个表中的两列来定义关系。因此,使用任务的应用程序作为一个例子。

尝试1:

 类用户< ActiveRecord的::基地
  的has_many:任务
结束类任务< ActiveRecord的::基地
  belongs_to的:所有者,CLASS_NAME:用户,foreign_key:owner_id
  belongs_to的:受让人,CLASS_NAME:用户,foreign_key:assignee_id
结束

于是 Task.create(owner_id:1,assignee_id:2)

这让我执行 Task.first.owner 返回的用户的一个 Task.first.assignee 返回的用户两个的,但 User.first.task 返回任何内容。这是因为任务不属于用户,他们属于的所有者的和的受让人的。因此,

尝试二:

 类用户< ActiveRecord的::基地
  的has_many:任务,foreign_key:[:owner_id,:assignee_id]
结束类任务< ActiveRecord的::基地
  belongs_to的:用户
结束

这只是完全失败似乎作为两个外键不被支持。

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

基本上某种程度上构建将等于 Task.where(owner_id || assignee_id == 1)

的查询的关系

这可能吗?

更新

我不希望使用 finder_sql ,但这个问题的答案不被接受看起来接近我想要什么:导轨 - 多重索引键协会

所以这个方法是这样的,

尝试3:

 类任务< ActiveRecord的::基地
  高清self.by_person(人)
    其中(assignee_id = GT;:为person_id OR owner_id = GT;:为person_id:为person_id = GT; person.id
  结束
结束类Person< ActiveRecord的::基地  DEF任务
    Task.by_person(个体经营)
  结束
结束

虽然我可以得到它在<​​code>工作轨道4 ,我不断收到以下错误:

 的ActiveRecord :: preparedStatementInvalid:缺少值:在owner_id:donor_id =&GT; :为person_id OR assignee_id =&GT; :为person_id


解决方案

TL; DR

 类用户&LT; ActiveRecord的::基地
  DEF任务
    Task.where(owner_id = 2 OR assigneed_id =?,self.id,self.id)
  结束
结束

删除的has_many:任务用户


使用的has_many:任务没有任何意义的,因为我们没有任何名为列 USER_ID 中表任务

我所做的,解决这个问题在我的情况是:

 类用户&LT; ActiveRecord的::基地
  的has_many:owned_tasks,CLASS_NAME:'任务',foreign_key:owner_id
  的has_many:assigned_tasks,CLASS_NAME:'任务',foreign_key:assignee_id
结束类任务&LT; ActiveRecord的::基地
  belongs_to的:所有者,CLASS_NAME:用户,foreign_key:owner_id
  belongs_to的:受让人,CLASS_NAME:用户,foreign_key:assignee_id
  #`一提是foreign_keys`之中没有必要在这一类,因为
  #我们已经提到`belongs_to的:owner`和Rails会预期
  自动#foreign_keys。感谢@ jeffdill2的提这件事情
  #在注释。
结束

这样,你可以叫 User.first.assigned_tasks 以及 User.first.owned_tasks

现在,您可以定义一个名为方法任务返回 assigned_tasks 的组合和 owned_tasks

这可能是一个很好的解决方案,据可读性去,但是从性能的角度来看,它不会像现在这么多不错的,为了获得任务,两个查询将被代替发行一次,然后,需要这两个查询的结果将加入为好。

因此​​,为了得到属于用户的任务,我们将定义一个自定义的任务方法用户类的方式如下:

  DEF任务
  Task.where(owner_id = 2 OR assigneed_id =?,self.id,self.id)
结束

这个方式,它会取一个单一查询所有的结果,而我们不会有合并或合并任何结果。

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

Attempt 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

So then Task.create(owner_id:1, assignee_id: 2)

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,

Attempt 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.

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

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

Is that possible?

Update

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,

Attempt 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

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

Remove has_many :tasks in User class.


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

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

Now, you can define a method called tasks that returns the combination of assigned_tasks and owned_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.

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天全站免登陆