Joã*_*iel 6 ruby architecture oop design-patterns ruby-on-rails
我有一个PORO(Plain Old Ruby Object)来处理一些业务逻辑.它接收一个ActiveRecord对象并对其进行分类.为简单起见,请以下面的示例为例:
class Classificator
STATES = {
1 => "Positive",
2 => "Neutral",
3 => "Negative"
}
def initializer(item)
@item = item
end
def name
STATES.fetch(state_id)
end
private
def state_id
return 1 if @item.value > 0
return 2 if @item.value == 0
return 3 if @item.value < 0
end
end
Run Code Online (Sandbox Code Playgroud)
但是,我还想进行基于这些state_id"虚拟属性" 对对象进行分组的查询.我目前正在通过在SQL查询中创建此属性并在GROUP BY语句中使用它来处理它.看例子:
class Classificator::Query
SQL_CONDITIONS = {
1 => "items.value > 0",
2 => "items.value = 0",
3 => "items.value < 0"
}
def initialize(relation = Item.all)
@relation = relation
end
def count
@relation.select(group_conditions).group('state_id').count
end
private
def group_conditions
'CASE ' + SQL_CONDITIONS.map do |k, v|
'WHEN ' + v.to_s + " THEN " + k.to_s
end.join(' ') + " END AS state_id"
end
end
Run Code Online (Sandbox Code Playgroud)
这样,我可以将此业务逻辑转换为SQL,并以非常有效的方式进行此类查询.
问题是:我有重复的业务逻辑.它存在于"ruby"代码中,用于对单个对象进行分类,也在"SQL"中对数据库级别的对象集合进行分类.
这是一种不好的做法吗?有办法避免这种情况吗?我实际上能够做到这一点,做到以下几点:
item = Item.find(4)
items.select(group_conditions).where(id: item.id).select('state_id')
Run Code Online (Sandbox Code Playgroud)
但是通过这样做,我失去了对未在数据库中持久化的对象进行分类的能力.另一种方法是使用迭代器对ruby中的每个对象进行分类,但之后我将失去数据库性能.
如果我需要两种情况中的最佳情况,那么保持重复的业务逻辑似乎是不可避免的.但我只是想确定这一点.:)
谢谢!
Ale*_*kin -1
有没有机会在数据库中引入触发器?如果是这样,我将使用state_id数据库中的 \xe2\x80\x9ccalculated\xe2\x80\x9d 字段,这将更改它的 \xe2\x80\x99s 值INSERT和UPDATE(这将带来更多的生产力优势)和此代码红宝石:
def state_if\n return @item.state_id if @item.state_id # persistent object\n\n case @item.value\n when 0 then 2\n when -Float::INFINITY...0 then 3\n else 1\n end\nend\nRun Code Online (Sandbox Code Playgroud)\n