In Rails, blocks can be used as callbacks, e.g.:
class User < ActiveRecord::Base
validates_presence_of :login, :email
before_create {|user| user.name = user.login.capitalize
if user.name.blank?}
end
When a block is used like this, is there any use for break and return? I’m asking because normally in a block, break will break out of the loop, and return will return from the enclosing method. But in a callback context, I can’t get my head round what that means.
The Ruby Programming Language suggests that return could cause a LocalJumpError but I haven’t been able to reproduce this in a Rails callback.
Edit: with the following code I’d expect a LocalJumpError, but all the return does is stop the rest of the callback executing.
class User < ActiveRecord::Base
validates_presence_of :login, :email
before_create do |user|
return
user.name = user.login.capitalize
end
Actually it’s kind of interesting…
When you use before_create in Rails 3, we take the block or lambda that you give us and convert it into a method. We then invoke the method with the current ActiveRecord object, for backwards compatibility with the old Rails approach.
As a result, the following is equivalent to your snippet:
Because of this behavior, you can call return from the block, and it will behave the same as a return in a normal method (because it is a normal method).
In general,
nextin a block "returns" from the block.The specific behavior of normal blocks is:
next, you are skipping the rest of the block, and returning control to the method that invoked the block.break, you are skipping the rest of the block, and also immediately returning from the method that invoked the block.You can see that behavior in normal iterators:
In this case,
valuewill be[1,2,3,4], the normal return value of theeachmethod, and the output will be:In the case of break:
In this case, the
valuewill benil, since thebreakalso immediately returned from theeachmethod. You can force a return with a specific value by usingbreak n, which will makevaluethe same asn. The output in the above case will be:The important thing is that
nextandbreakdo not just apply to iterators, although their semantics are designed to behave like their equivalents in C in the case of iterators.