简体   繁体   中英

Use distinct method with order on a many to many relation with ActiveRecord

I have a classic many to many relationship defined like this in ActiveRecord:

class Developer < ApplicationRecord
  has_many :developers_code_reviews
  has_many :code_reviews, through: :developers_code_reviews
end

class DevelopersCodeReview < ApplicationRecord
  belongs_to :code_review
  belongs_to :developer
end

class CodeReview < ApplicationRecord
  has_many :developers_code_reviews
  has_many :developers, through: :developers_code_reviews
end

and I basically want to have a Developer array sorted by code_review.created_at without doubles.

My first attempt was the basic one: Developer.order('code_reviews.created_at': :asc) which triggers this error: ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'code_reviews.created' in 'order clause .

After a few googling I understood the join was not automatically performed by ActiveRecord so I added it: Developer.joins(:code_reviews).order('code_reviews.created_at': :asc) . This one works but has doubles inside. I need to have a developer to appear only once in this array.

If I try to create a distinct on that query, ActiveRecord/MySQL complains that the ORDER BY is not performed on a column that is in the SELECT. How can I solve this problem?

I googled it quite a lot I can't find anything.

NOTE

The MYSQL query which works but with doubles looks like this:

SELECT `developers`.*
FROM `developers`
INNER JOIN `developers_code_reviews` ON `developers_code_reviews`.`developer_id` = `developers`.`id`
INNER JOIN `code_reviews` ON `code_reviews`.`id` = `developers_code_reviews`.`code_review_id` 
ORDER BY `code_reviews`.`created_at` ASC

and I'd like to have a distinct on the developers.

I found the answer thanks to this clear example on MySQL sub queries: http://www.mysqltutorial.org/mysql-subquery/

With this example, I understood that I needed a sub query looking like this:

SELECT *
FROM developers
LEFT OUTER JOIN (
  SELECT developer_id, max(updated_at) max_updated_at
  FROM developers_code_reviews
  GROUP BY developer_id
) dcr
ON developers.id = dcr.developer_id
ORDER BY maxupdt

Translated to ruby in my case:

class DevelopersCodeReview < ApplicationRecord
  belongs_to :code_review
  belongs_to :developer

  class << self
    def developer_queue
      select('developer_id, max(updated_at) max_updated_at').
      group(:developer_id)
    end
  end
end

class Developer < ApplicationRecord
  belongs_to :slack_workspace
  belongs_to :project, optional: true

  class << self
    def queue
      developer_queue = DevelopersCodeReview.developer_queue.to_sql

      joins("LEFT OUTER JOIN (#{developer_queue}) dcr ON id = dcr.developer_id").
      order(max_updated_at: :asc)
    end
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM