I wanted to do this with the popular gem:
class User < ActiveRecord::Base
popular
after_befriend :notify_friend
def notify_friend(friend)
puts "#{self.username} followed #{friend.username}"
end
end
but after_befriend
doesn't send notify_friend
any arguments. This is because it's using ActiveSupport callbacks and they don't send arguments. Or do they...
I started investigating how popular and ActiveSupport callbacks worked. When befriending a user, popular creates a friendship in an ActiveSupport::Callbacks
run_callbacks
block (See). The return value of the friendship gets passed to run_callbacks
then some funky ActiveSupport::Callbacks stuff happens and then my notify_friend
method gets called... without the friendship value being passed.
I looked through run_callbacks
and it looked to be doing some complicated stuff as soon as it hit the compile
method. But essentially it calls apply
which calls make_lambda
which creates a lambda
which send
s on my method notify_friend
. The lambda
is called eventually from simple
where it is passed the return value of the block provided by popular.
Unfortunately, make_lambda
discards the return value when using a symbol or proc (note the _
on line 424). BUT for some reason, not when you provide a string to after_befriend
.
So the simple answer to my long winded adventures:
class User < ActiveRecord::Base
popular
after_befriend 'notify_friend value'
def notify_friend(friendship)
puts "#{self.username} followed #{friendship.friend.username}"
end
end
My suggestions to the rails core would be to pass value to the method if the method accepts arguments:
def make_lambda
# ...
when Symbol
lambda { |target, value, &blk|
if target.method(filter).arity == 0
target.send filter, &blk
else
target.send filter, value, &blk
end
}
# ...