Ruby复杂查询优雅解决方案

时间:2013-10-08 15:09:57

标签: ruby-on-rails ruby ruby-on-rails-4

在我的rails 4项目中,我有以下表格 enter image description here

在此SO question中,我搜索了一个SQL查询,以使用实际的项目状态ID = XX获取项目。实际上,我指的是具有max(created_at)的那个。

我的查询答案是

select p.* from projects p
     left join projects_status_projects psp on (psp.project_id = p.id)
     where created_at = (select max(created_at) from projects_status_projects 
           where project_id = p.id)    
     and project_status_id = XX

我的模型已定义

class Project < ActiveRecord::Base
   has_many :projects_status_projects
   has_many :projects_statuses, :through => :projects_status_projects
end

class ProjectStatus < ActiveRecord::Base
   has_many :projects_status_projects
   has_many :projects, :through => :projects_status_projects
end

class ProjectsStatusType < ActiveRecord::Base
   belongs_to :project
   belongs_to :project_status
end

在我的 Project 模型中,我有以下方法

def self.with_status(status)
   joins(:projects_status_projects)
       .where('projects_status_projects.created_at = (select max(created_at) from 
                    projects_status_projects where project_id = p.id)')
       .where('projects_status_projects.project_status_id = ?', status)
end

虽然查询正确,但收到的结果已经过滤,我觉得这个解决方案很糟糕,而且根本不优雅。

有没有办法在范围内获得相同的结果?

感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

您如何看待

scope :with_status, -> (status) { 
   ProjectsStatusType.where(:project_status_id, status).order(:created_at).last.project 
}

根据评论编辑:

正如sockmonk所说,范围应该是可链接的。这是一种更简洁的方法,如果没有找到项目,也可以解决问题。

# ProjectStatusType model
scope :with_ordered_status, -> (status) { 
   where(:project_status_id, status).order(:created_at)
}

# Project model
def self.find_by_status(status)
  project_statuses = ProjectsStatusType.with_ordered_status(status)
  project_statuses.any? ? project_statuses.last.project : nil
end

答案 1 :(得分:0)

怎么样?

scope :with_status, ->(status = "default_status") {
    joins(:projects_status_projects).
    where('projects_status_projects.project_status_id = ?', status).
    order("projects_status_projects.created_at DESC").first
  }

答案 2 :(得分:0)

scope :with_status, ->(status = "default_status") {
  joins(:projects_status_projects)
  .where('projects_status_projects.project_status_id = ?', status)
  .order("projects_status_projects.created_at DESC")    
}

当你打电话给它时,你会想要在它的末尾加上'.first';不能在范围本身中包含.first,因为这会使它变得不可用。