Ruby on Rails在哪里查询关系

时间:2016-04-30 01:08:17

标签: sql ruby-on-rails ruby activerecord

我正在尝试使用带有关系的查询。

在这种情况下如何查询使用关系的位置?

这是模型

User
  has_many :projects
  has_many :reasons, through: :projects

Project
  belongs_to :user
  has_many :reasons

Reasons
  belongs_to :project

这是不起作用的代码

  # GET /reasons
  def index
    reasons     = current_user.reasons
    updated_at  = params[:updated_at]

    # Filter with updated_at for reloading from mobile app
    if updated_at.present?



      # This one doesn't work!!!!!!!!!!!!      
      reasons = reasons.includes(:projects).where("updated_at > ?", Time.at(updated_at.to_i))



    # Get all non deleted objects when logging in from mobile app
    else
      reasons = reasons.where(deleted: false)
    end

    render json: reasons
  end  

--- ---更新

这要归功于@AmitA。

reasons = reasons.joins(:project).where("projects.updated_at > ?", Time.at(updated_at.to_i))

1 个答案:

答案 0 :(得分:3)

如果要查询项目有一些限制的所有原因,则需要使用joins而不是includes

reasons = reasons.joins(:project).where("projects.updated_at > ?", Time.at(updated_at.to_i))

请注意,当includesjoins同时收到符号时,他们会使用该精确名称查找关联。这就是为什么您实际上无法includes(:projects),但必须includes(:project)joins(:project)

另请注意,where指定的联接表的约束必须引用表名,而不是关联名称。这就是为什么我使用projects.updated_at(复数形式)而不是其他任何东西。换句话说,当调用where方法时,你在" SQL域"。

includesjoins之间存在差异。 includes运行单独的查询以加载依赖项,然后将它们填充到获取的活动记录对象中。所以:

reasons = Reason.where('id IN (1, 2, 3)').includes(:project)

将执行以下操作:

  1. 运行查询SELECT * FROM reasons WHERE id IN (1,2,3),并为每条记录构建ActiveRecord对象Reason
  2. 查看获取的每个原因并提取其project_id。让我们说这些是11,12,13。然后运行查询SELECT * FROM projects WHERE id IN (11,12,13)并为每条记录构建ActiveRecord对象Project
  3. 预先填充在步骤1中获取的每个project ActiveRecord对象的Reason关联。
  4. 上一步意味着你可以安全地做到:

    reasons.first.project
    

    并且不会启动任何查询来获取第一个原因的项目。这就是includes用于解决N + 1个查询的原因。但请注意,SQL中没有JOIN子句 - 它们是单独的SQL。因此,在使用includes时无法添加SQL约束。

    joins所在的位置。它只是连接表,以便您可以在连接的表上添加where约束。但是,它不会预先填充您的关联。事实上,Reason.joins(:project)永远不会实例化Project ActiveRecord对象。

    如果您想同时执行joinsincludes,则可以使用名为eager_load的第三种方法。您可以阅读有关差异的更多信息here