首页 > 解决方案 > 如何将实例方法转换为关联?

问题描述

型号Subscription has_many :versions

我正在编写一个查询来获取订阅并按关联的versions最后日期对其进行排序,但是由于and语句authorized_at,我不确定该查询是否可以多次返回相同的订阅。joinsgroup

Subscription
      .joins(:versions)
      .group("subscriptions.id, users.id")
      .order("MAX(versions.authorized_at) ASC")

另一方面,我有返回最后一个授权的Subscription实例方法。current_versionversion

订阅.rb

  def current_version
    versions.authorized.last
  end

我认为关联(而不是实例方法)可以帮助我,这样我就可以加入订阅和版本表,并按关联表授权日期对结果进行排序。

但是我如何设法编写一个像类方法一样执行查询的关联呢?

我尝试做类似的事情:

has_one     :current_version,
              -> { versions.authorized.last },
              class_name: "Version", inverse_of: "Subscription"

但我越来越NameError: undefined local variable or method 'versions' for #<Version::ActiveRecord_Relation

标签: ruby-on-railsrubydatabasepostgresql

解决方案


读取性能的最佳解决方案是在表中添加单独的外键列作为捷径:

add_reference :subscriptions, 
              :current_version,
              foreign_key: {
                to_table: :versions  ​
             ​}
class Subscription < ApplicationRecord
  has_many :versions, 
    after_add: :set_current_version
  belongs_to :current_version,
    class_name: 'Version'

  def set_current_version(version)
     update_attribute(:current_version_id, version.id) 
  end
end

这使用关联回调来设置关联,但您也可以使用数据库触发器或服务对象来处理它。

如果你真的想使用has_one,你需要使用hackery,比如子查询、窗口函数或横向连接

class Subscription
  has_one :current_version, 
    -> {
      where(
        id: Version.select(:id)
                   .group(:subscription_id)
                   .order("MAX(versions.authorized_at) ASC")
      )
    },
    class_name: 'Version'
end

推荐阅读