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

2022/11/27 23:24:56

本文主要是介绍如何在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,实现数据,基础数据 来源:

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。



这篇关于如何在Ruby on Rails中实现查询对象模式?的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程