启动方法只需添加/删除关联元素一次

时间:2018-04-18 23:18:55

标签: ruby-on-rails callback after-save after-create

我的Composition模型有has_and_belongs_to_many :authors

我需要在作品更改其作者后触发一个方法,但是,因为它涉及创建一个PDF文件(带有作者的名字),我想只调用一次这个方法,无论其数量是多少作者添加/删除。

当然我可以从合成中添加/删除现有作者,因此before_save / after_save在这里不起作用(不知何故,它会识别添加到合成中的新作者,但不是现有作者)

所以我尝试使用after_add / after_remove,但是会为在合成中添加/删除的每个作者项调用此处指定的回调。

对于从这种关系中添加/删除项目的每个“批处理操作”,是否有办法只调用一次方法?

1 个答案:

答案 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错误。