I’m trying to write a library that will programmatically add around_update/around_destroy callbacks to a ActiveRecord model.
So, a regular model would look like this and it works as expected:
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
My little library (obviously just the skeleton) looks like this:
# 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
It defined a timeline_for method which should add the timeline_for_update method and make that a callback for the around_update event. And the User model I want to use is this:
# 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
In the output I see
timeline_for_update
LocalJumpError: no block given (yield)
from /vagrant/lib/piddle/piddle.rb:13:in `block in timeline_for'
The first output line indicates that the method is being called but the block isn’t being passed in.
Any ideas or alternative implementations?
The problem is that if you call
yieldfrom yourdefine_method, ruby interprets that as trying to yield to the (nonexistant) block that was passed totimeline_for, not the blockthat rails passed to
timeline_for_fooYou’ve got
blockbeing passed to you so you can just call it: