我们为什么需要它,这种模式可以解决什么问题?
有时我们有非常复杂的查询,直接在业务逻辑中使用。例如,可以在不同的控制器和服务对象中多次使用以下查询:
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)
接口看起来不错,但有一个重要的问题 – 方法不可链接,我们每次都必须重复前缀。例如,如果你想写这样的东西,它是行不通的。::Season
Queries::Season.by_league(league).by_status(status)
那么,我们如何解决它呢?
Rails有一个有趣的方法。此方法允许您在模型上添加任何方法并将它们链接起来。例如,以下工作正常。
本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/293832.html