我正在使用续集数据库后端构建一个sinatra Web应用程序。此应用程序的主要任务是收集来自不同机器人的状态消息,将它们存储在数据库中并提供各种方法来查看它们。这些消息的一个共同点是,它们提供纬度/经度的WGS84位置。
现在我想提供各种过滤器来根据它们的位置查询消息,但是我想只编写一次这些过滤器,只测试一次,但是在带有lat / lon条目的所有模型类中重复使用它们。 / p>
将其归结为一个非常简单的例子:
Sequel.migration do
up do
create_table(:auvmessages) do
primary_key :id
Float :lat
Float :lon
String :message
end
create_table(:asvmessages) do
primary_key :id
Float :lat
Float :lon
Integer :chargestate
end
end
end
class Auvessage < Sequel::Model
dataset_module do
def north_of(lat)
self.where{ latitude > lat}
end
end
end
class Asvessage < Sequel::Model
dataset_module do
def north_of(lat)
self.where{ latitude > lat}
end
end
end
在两个模型类中都有north_of(lat)
来过滤来自给定纬度以北的消息。这个功能相当简单,您可以轻松地重复两到三次,但更复杂的情况呢?
我使用dataset_module
之外的模块玩了一下,但似乎没什么。
是否有一种首选方法可以在不同型号上重复使用滤镜?我搜索了很多,但没有找到任何令人满意的答案。
修改
为了使我的问题更精确:我想将所有函数(如north_of(lat)
(有一个 lot 更多))移动到服务类中。我现在想知道的是将该服务类集成到续集模型中的最佳方法:
答案 0 :(得分:1)
以下是Bob叔叔的Screaming Architecture博文的链接,可能会有所帮助。
现在,在回答您的问题时,似乎north_of
以及许多其他方法实际上是您的域逻辑的一部分。这个逻辑不应该用于持久性抽象,控制器或视图等。
设计,构建和编写用于解决问题域语言问题的对象集的测试。然后,您将拥有一组丰富的功能,您可以在Model
,Controller
,CLI等上使用这些功能。
我通常将我的服务对象放在lib/
目录中并编写简单的单元测试,而没有任何设置测试数据库的持久性样板。他们通常也跑得很快。
答案 1 :(得分:1)
您可以将现有模块传递给dataset_module
:
module NorthOf
def north_of(lat)
where{latitude > lat}
end
end
Auvessage.dataset_module NorthOf
Asvessage.dataset_module NorthOf
答案 2 :(得分:1)
作为后续:我采取了@ jeremy-evans answer并通过模块的参数化方案对其进行了扩展。所以从现在开始,我可以通过模拟测试我的过滤器,我的模型类只有一个包含在他们的dataset_module中的列表。
我喜欢它。
作为解释我稍加修改的例子:
Sequel.migration do
up do
create_table(:auvmessages) do
primary_key :id
Float :lat
Float :lon
String :message
end
create_table(:asvmessages) do
primary_key :id
Float :gps_lat
Float :gps_lon
Integer :chargestate
end
end
end
module GPSFilter
def self.create(lat_name, lon_name)
Module.new do
include GPS
define_method :lat_col_name do
lat_name
end
define_method :lon_col_name do
lon_name
end
end
end
def north_of(lat)
where( "#{lat_col_name} > #{lat}" )
end
##### default parameters #####
def lon_col_name
"lon"
end
def lat_col_name
"lat"
end
end
class Auvmessage < Sequel::Model
dataset_module do
include GPSFilter
end
end
class Asvmessage < Sequel::Model
dataset_module do
include GPSFilter.create :gps_lat, :gps_lon
end
end