Ruby on rails 两次连接到表时的何处条件

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

我有一个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: 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 is
users
中使用的表。那我怎么知道是哪一个呢?这已经对我起作用了。我在表中有两个外键,这两个
属于
语句默认为正确的外键。问题是如何指定where子句。我不确定我是否理解,您在SQL级别想要的可能是在JOIN语句而不是where语句中获取条件,以便获得正确的筛选记录?我是说,当我在两个关联上都加入时,它使用
committers\u bugs
作为第二次联接的表别名,但当我仅在
committer
关联上联接时,我需要在where is
users
中使用的表。那么我怎么知道是哪个呢?这个答案的问题是您使用了
bugs.user\u id
,但是
bugs
表没有
user\u id
外键,它有