Ruby on rails 两次连接到表时的何处条件
我有一个Bug类,分析人员和提交者都在用户表中Ruby on rails 两次连接到表时的何处条件,ruby-on-rails,join,activerecord,Ruby On Rails,Join,Activerecord,我有一个Bug类,分析人员和提交者都在用户表中 class Bug < ApplicationRecord belongs_to :analyst, class_name: 'User' belongs_to :committer, class_name: 'User' ... end 同样,如果我搜索提交者,我得到的SQL analyst = 'amcdonnell' Bug.joins(:committer).where(users: {username: committ
class Bug < ApplicationRecord
belongs_to :analyst, class_name: 'User'
belongs_to :committer, class_name: 'User'
...
end
同样,如果我搜索提交者,我得到的SQL
analyst = 'amcdonnell'
Bug.joins(:committer).where(users: {username: committer}).to_sql
=> "SELECT `bugs`.* FROM `bugs`
INNER JOIN `users` ON `users`.`id` = `bugs`.`committer_id`
WHERE `users`.`username` = 'amcdonnell'"
但是如果我同时搜索两者,where调用不能同时使用users
。表有别名,我需要使用别名
Bug.joins(:analyst, :committer)
.where(users: {username: committer})
.where(committers_bugs: {username: committer}).to_sql
=> "SELECT `bugs`.* FROM `bugs`
INNER JOIN `users` ON `users`.`id` = `bugs`.`analyst_id`
INNER JOIN `users` `committers_bugs` ON `committers_bugs`.`id` = `bugs`.`committer_id`
WHERE `users`.`username` = 'abenge'
AND `committers_bugs`.`cvs_username` = 'amcdonnell'"
所以我的问题是,“当一种情况下是用户
而另一种情况下是提交者(bugs
)时,我如何知道在我的where子句中使用哪个键作为提交者的用户名?”
我希望代码是这样的:
relation = Bug
analyst = params['analyst']
if analyst.present?
relation = relation.joins(:analyst).where(user: {username: analyst})
end
committer = params['committer']
if committer.present?
relation = relation.joins(:committer).where(committers_bugs: {username: committer})
end
问题是,如果他们同时搜索这两个,上面的方法会起作用。但是,如果他们搜索提交者而不搜索分析师,那么active record会使用用户
作为加入到提交者
的表名,如果您的每个人都有“bug”“与两个用户相关您的Bug表需要通过两个不同的外键进行关联:
迁移
class CreateBug < ActiveRecord::Migration
def change
create_table :bugs do |t|
# ...
t.references :analyst_id, index: true, foreign_key: {to_table: :users}
t.references :committer_id, index: true, foreign_key: {to_table: :users}
end
end
end
class CreateBug
型号
class Bug < ActiveRecord
belongs_to :analyst, class_name: 'User', foreign_key: 'analyst_id'
belongs_to :committer, class_name: 'User', foreign_key: 'committer_id'
end
class Bug
如果您的每个“Bug”都与两个用户相关,那么您的Bug表需要通过两个不同的外键进行关联:
迁移
class CreateBug < ActiveRecord::Migration
def change
create_table :bugs do |t|
# ...
t.references :analyst_id, index: true, foreign_key: {to_table: :users}
t.references :committer_id, index: true, foreign_key: {to_table: :users}
end
end
end
class CreateBug
型号
class Bug < ActiveRecord
belongs_to :analyst, class_name: 'User', foreign_key: 'analyst_id'
belongs_to :committer, class_name: 'User', foreign_key: 'committer_id'
end
class Bug
Committer和analyst都只是同一个表中的SQL别名。如果在WHERE语句中使用它们中的任何一个,结果总是相同的。如果要将条件限制为特定联接,则必须将该条件添加到ON语句中
我喜欢使用的一个选项是向关系添加lambda:
class Bug < ActiveRecord
belongs_to :analyst, -> { where(username: 'Haruki Murakami') }, class_name: 'User'
end
问题是,只要我有搜索功能,你就不能将参数传递给这个lambda,但你仍然可以做一些不那么漂亮但功能强大的事情,比如:
Bug.joins("LEFT JOIN users ON bugs.user_id = user.id AND users.username = ?", params['committer'])
…在您的示例中必须实现为:
relation = Bug
analyst = params['analyst']
if analyst.present?
relation = relation.joins("LEFT JOIN users A ON bugs.analyst_id = A.id AND A.username = ?", analyst)
end
committer = params['committer']
if committer.present?
relation = relation.joins("LEFT JOIN users C ON bugs.committer_id = C.id AND C.username= ?", committer)
end
也许您希望将此代码移动到您的模型中,如:
class Bug < ActiveRecord
def self.who_analyses(name)
Bug.joins("LEFT JOIN users A ON bugs.analyst_id = A.id AND A.username = ?", name)
end
def self.who_have_commited(name)
Bug.joins("LEFT JOIN users C ON bugs.committer_id = C.id AND C.username= ?", name)
end
end
analyst = params['analyst']
committer = params['committer']
if analyst.present?
relation = relation.who_analyses(analyst)
end
if committer.present?
relation = relation.who_have_commited(committer)
end
class Bug
Committer和analyst都只是同一个表中的SQL别名。如果在WHERE语句中使用它们中的任何一个,结果总是相同的。如果要将条件限制为特定联接,则必须将该条件添加到ON语句中
我喜欢使用的一个选项是向关系添加lambda:
class Bug < ActiveRecord
belongs_to :analyst, -> { where(username: 'Haruki Murakami') }, class_name: 'User'
end
问题是,只要我有搜索功能,你就不能将参数传递给这个lambda,但你仍然可以做一些不那么漂亮但功能强大的事情,比如:
Bug.joins("LEFT JOIN users ON bugs.user_id = user.id AND users.username = ?", params['committer'])
…在您的示例中必须实现为:
relation = Bug
analyst = params['analyst']
if analyst.present?
relation = relation.joins("LEFT JOIN users A ON bugs.analyst_id = A.id AND A.username = ?", analyst)
end
committer = params['committer']
if committer.present?
relation = relation.joins("LEFT JOIN users C ON bugs.committer_id = C.id AND C.username= ?", committer)
end
也许您希望将此代码移动到您的模型中,如:
class Bug < ActiveRecord
def self.who_analyses(name)
Bug.joins("LEFT JOIN users A ON bugs.analyst_id = A.id AND A.username = ?", name)
end
def self.who_have_commited(name)
Bug.joins("LEFT JOIN users C ON bugs.committer_id = C.id AND C.username= ?", name)
end
end
analyst = params['analyst']
committer = params['committer']
if analyst.present?
relation = relation.who_analyses(analyst)
end
if committer.present?
relation = relation.who_have_commited(committer)
end
class Bug
这已经对我起作用了。我在表中有两个外键,这两个属于
语句默认为正确的外键。问题是如何指定where子句。我不确定我是否理解,您在SQL级别想要的可能是在JOIN语句而不是where语句中获取条件,以便获得正确的筛选记录?我是说,当我在两个关联上都加入时,它使用committers\u bugs
作为第二次联接的表别名,但当我仅在committer
关联上联接时,我需要在where isusers
中使用的表。那我怎么知道是哪一个呢?这已经对我起作用了。我在表中有两个外键,这两个属于
语句默认为正确的外键。问题是如何指定where子句。我不确定我是否理解,您在SQL级别想要的可能是在JOIN语句而不是where语句中获取条件,以便获得正确的筛选记录?我是说,当我在两个关联上都加入时,它使用committers\u bugs
作为第二次联接的表别名,但当我仅在committer
关联上联接时,我需要在where isusers
中使用的表。那么我怎么知道是哪个呢?这个答案的问题是您使用了bugs.user\u id
,但是bugs
表没有user\u id
外键,它有