其他分享
首页 > 其他分享> > 如何在Ruby on Rails中实现查询对象模式?

如何在Ruby on Rails中实现查询对象模式?

作者:互联网

我们为什么需要它,这种模式可以解决什么问题?

有时我们有非常复杂的查询,直接在业务逻辑中使用。例如,可以在不同的控制器和服务对象中多次使用以下查询:

def index
  seasons = Season.joins(league: :country).where("countries.name = 'England'")

  render json: seasons
end

这给我们带来了什么问题?

那么我们能做些什么来解决这个问题呢?

如果我们决定选择第一个选项并使用模型,有两种方法可以实现这一点:

类方法

# frozen_string_literal: true

class Season < ApplicationRecord

  def self.by_league(league)
    where(league: league)
  end

  def self.by_status(status)
    where(status: status)
  end

end

Season.by_league(league)
Season.by_status(status)

范围

class Season < ApplicationRecord

  scope :by_league, -> (league) { where(league: league) }
  scope :by_status, -> (status) { where(status: status) }

end

Season.by_league(league)
Season.by_status(status)

界面看起来不错,但我们仍然有一些问题。最重要的一个是违反了单一责任原则。模型变得太大太胖。我们一年可以获得100多种方法。因此,阅读、更改和维护将非常困难。拥有相同的接口会很好,但将该逻辑移动到单独的类中。

我们该怎么做呢?

创建查询对象模式就是为了解决此问题。

让我们从最简单的查询对象开始。

# app/units/queries/season.rb

module Queries
  class Season

    class << self
      def by_league(league)
        ::Season.where(league: league)
      end

      def by_status(status)
        ::Season.where(status: status)
      end
    end

  end
end

Queries::Season.by_league(league)
Queries::Season.by_status(status)

接口看起来不错,但有一个重要的问题 - 方法不可链接,我们每次都必须重复前缀。例如,如果你想写这样的东西,它是行不通的。::SeasonQueries::Season.by_league(league).by_status(status)

那么,我们如何解决它呢?

Rails有一个有趣的方法。此方法允许您在模型上添加任何方法并将它们链接起来。例如,以下工作正常。

标签:数据,系统,系统架构,saas,实现数据,基础数据
来源: