我的Composition
模型有has_and_belongs_to_many :authors
。
我需要在作品更改其作者后触发一个方法,但是,因为它涉及创建一个PDF文件(带有作者的名字),我想只调用一次这个方法,无论其数量是多少作者添加/删除。
当然我可以从合成中添加/删除现有作者,因此before_save
/ after_save
在这里不起作用(不知何故,它会识别添加到合成中的新作者,但不是现有作者)
所以我尝试使用after_add
/ after_remove
,但是会为在合成中添加/删除的每个作者项调用此处指定的回调。
对于从这种关系中添加/删除项目的每个“批处理操作”,是否有办法只调用一次方法?
答案 0 :(得分:0)
以下是可能的服务:
class UpdateCompositionAuthorsService
attr_accessor *%w(
args
).freeze
class << self
def call(args={})
new(args).call
end
end # Class Methods
#======================================================================================
# Instance Methods
#======================================================================================
def initialize(args={})
@args = args
assign_args
end
def call
do_stuff_to_update_authors
generate_the_pdf
end
private
def do_stuff_to_update_authors
# do your 'batch' stuff here
end
def generate_the_pdf
# do your one-time logic here
end
def assign_args
args.each do |k,v|
class_eval do
attr_accessor k
end
send("#{k}=",v)
end
end
end
你会称之为:
UpdateCompositionAuthorsService.call(composition: @composition, authors: @authors)
我厌倦了记住要发送到我的服务类的args,所以我创建了一个名为ActsAs::CallingServices
的模块。当包含在想要调用服务的class
中时,该模块提供了一个名为call_service
的方法,可以让我执行以下操作:
class FooClass
include ActsAs::CallingServices
def bar
call_service UpdateCompositionAuthorsService
end
end
然后,在服务类中,我包含一些额外的类级数据,如下所示:
class UpdateCompositionAuthorsService
SERVICE_DETAILS = [
:composition,
:authors
].freeze
...
def call
do_stuff_to_update_authors
generate_the_pdf
end
...
end
调用类(在本例中为FooClass
)使用UpdateCompositionAuthorsService::SERVICE_DETAILS
构建适当的参数hash(详细信息省略)。
我还有一个名为good_to_go?
(详细省略)的方法,它包含在我的服务类中,因此我的调用方法通常如下所示:
class UpdateCompositionAuthorsService
...
def call
raise unless good_to_go?
do_stuff_to_update_authors
generate_the_pdf
end
...
end
所以,如果参数集不好,我马上知道,而不是在服务中间的某个地方碰到nil
错误。