以编程方式定义around_回调时的"no block given"



我正在尝试编写一个库,该库将以编程方式向ActiveRecord模型添加around_update/around_destroy回调。

因此,一个常规模型会是这样的,并且它可以按预期工作:

class User < ActiveRecord::Base
  around_update :test_update
  def test_update
    Rails.logger.debug "test_update"
    yield
    Rails.logger.debug "Finished test_update"
  end
end
u=User.last
u.name = 'something'
u.save
######### output (as expected):
# test_update
# Finished test_update

我的小图书馆(显然只是骨架)看起来是这样的:

# A module for creating around callbacks in a model
module Piddle
  module TimelineFor
    def self.included(klass)
      klass.send(:extend, ClassMethods)
    end
    module ClassMethods
      def timeline_for(event, opts={})
        method_name = :"timeline_for_#{event.to_s}"
        define_method(method_name) do |&block|
          Rails.logger.debug method_name.to_s
          yield block
          Rails.logger.debug "After yield in #{method_name.to_s}"
        end
        send(:around_update, method_name)
      end
    end
  end
end

它定义了一个timeline_for方法,该方法应添加timeline_for_update方法,并使其成为around_update事件的回调。我想使用的用户模型是:

# second version of the User model using Piddle to create the callback
require 'piddle/piddle'
class User < ActiveRecord::Base
  include Piddle::TimelineFor
  timeline_for :update
end
u=User.last
u.name = 'gfgfhfhfgh'
u.save

在输出中,我看到

timeline_for_update
LocalJumpError: no block given (yield)
from /vagrant/lib/piddle/piddle.rb:13:in `block in timeline_for'

第一个输出行表示正在调用该方法,但没有传入块

有什么想法或替代实施方案吗?

问题是,如果从define_method调用yield,ruby会将其解释为试图屈服于传递给timeline_for的(不存在的)块,而不是块轨道通过timeline_for_foo

你有block被传递给你,所以你可以称之为:

def timeline_for event
  method_name = "timeline_for_#{event}"
  define_method method_name do |&block|
    ActiveRecord::Base.logger.debug "before #{method_name} yield" 
    block.call
    ActiveRecord::Base.logger.debug "after #{method_name} yield" 
  end
  send :around_update, method_name.to_sym #must use a symbol here
end

如果你想定义这样的东西。看看积极支持关注的问题。

我认为您需要在类上调用around过滤器,而不是在定义本身中使用send:

http://apidock.com/rails/ActiveSupport/Concern

相关内容

最新更新