Ruby on rails 我应该如何在服务对象中转换此关注点?
我担心让后端用户能够对元素进行排序。我将它用于几个不同的元素。rails社区似乎非常反对关注和回调,我想就如何更好地对以下代码建模提出几点建议:Ruby on rails 我应该如何在服务对象中转换此关注点?,ruby-on-rails,callback,refactoring,separation-of-concerns,service-object,Ruby On Rails,Callback,Refactoring,Separation Of Concerns,Service Object,我担心让后端用户能够对元素进行排序。我将它用于几个不同的元素。rails社区似乎非常反对关注和回调,我想就如何更好地对以下代码建模提出几点建议: require 'active_support/concern' module Rankable extend ActiveSupport::Concern included do validates :row_order, :presence => true scope :next_rank, lambda { |ra
require 'active_support/concern'
module Rankable
extend ActiveSupport::Concern
included do
validates :row_order, :presence => true
scope :next_rank, lambda { |rank| where('row_order > ?',rank).order("row_order asc").limit(1)}
scope :previous_rank, lambda { |rank| where('row_order < ?',rank).order("row_order desc").limit(1)}
scope :bigger_rank, order("row_order desc").limit('1')
before_validation :assign_rank
end
def invert(target)
a = self.row_order
b = target.row_order
self.row_order = target.row_order
target.row_order = a
if self.save
if target.save
true
else
self.row_order = a
self.save
false
end
else
false
end
end
def increase_rank
return false unless self.next_rank.first && self.invert(self.next_rank.first)
end
def decrease_rank
return false unless self.previous_rank.first && self.invert(self.previous_rank.first)
end
private
def assign_default_rank
if !self.row_order
if self.class.bigger_rank.first
self.row_order = self.class.bigger_rank.first.row_order + 1
else
self.row_order=0
end
end
end
end
需要“主动支持/关注”
模块可分级
扩展ActiveSupport::关注点
包括做
验证:行顺序,:presence=>true
范围:下一级,lambda{124; rank | where('row_order>?',rank).order(“row_order asc”).limit(1)}
范围:前一级,lambda{124; rank | where('row_order<?',rank.).order(“row_order desc”).limit(1)}
范围:更大的等级、顺序(“行顺序描述”)。限制(“1”)
在\u验证之前:分配\u排名
结束
def反转(目标)
a=自行\顺序
b=目标行\顺序
self.row\u顺序=target.row\u顺序
target.row_order=a
自救
如果target.save
真的
其他的
self.row\u order=a
自救
假的
结束
其他的
假的
结束
结束
def增加_等级
返回false,除非self.next\u rank.first和self.invert(self.next\u rank.first)
结束
降阶
返回false,除非self.previous\u rank.first和self.invert(self.previous\u rank.first)
结束
私有的
def分配默认等级
如果!自排顺序
如果self.class.biger\u排名第一
self.row\u order=self.class.biger\u rank.first.row\u order+1
其他的
self.row\u order=0
结束
结束
结束
结束
我认为关注点是您试图完成的目标的一个不错的选择(特别是在验证和作用域方面,因为ActiveRecord在这两方面做得非常好)。然而,若您确实想将问题从关注点转移出去,除了验证和范围之外,这里有一种可能性。只要看一下代码,就好像你有一个等级的概念,它由一个整数表示,但可以成为它自己的对象:
class Rank
def initialize(rankable)
@rankable = rankable
@klass = rankable.class
end
def number
@rankable.row_order
end
def increase
next_rank ? RankableInversionService.call(@rankable, next_rank) : false
end
def decrease
previous_rank ? RankableInversionService.call(@rankable, previous_rank) : false
end
private
def next_rank
@next_rank ||= @klass.next_rank.first
end
def previous_rank
@previous_rank ||= @klass.previous_rank.first
end
end
要提取#invert方法,我们可以创建一个RankableInversionService(如上所述):
要提取回调,您可以使用RankableUpdateService,它将在保存对象之前分配默认秩:
class RankableUpdateService
def self.call(rankable)
new(rankable).call
end
def initialize(rankable)
@rankable = rankable
@klass = rankable.class
end
def call
@rankable.rank = bigger_rank unless @rankable.ranked?
@rankable.save
end
private
def bigger_rank
@bigger_rank ||= @klass.bigger_rank.first.try(:rank)
end
end
现在你关心的是:
module Rankable
extend ActiveSupport::Concern
included do
# validations
# scopes
end
def rank
@rank ||= Rank.new(self)
end
def rank=(rank)
self.row_order = rank.number; @rank = rank
end
def ranked?
rank.number.present?
end
end
我敢肯定,如果您按原样使用,这段代码会有问题,但您得到了这个概念。总的来说,我认为这里唯一好做的事情就是提取一个Rank对象,除了它可能太复杂了,所以关注点可以很好地封装
module Rankable
extend ActiveSupport::Concern
included do
# validations
# scopes
end
def rank
@rank ||= Rank.new(self)
end
def rank=(rank)
self.row_order = rank.number; @rank = rank
end
def ranked?
rank.number.present?
end
end