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:
class User < ActiveRecord::Base
validates_presence_of :login, :email
before_create do
self.name = login.capitalize if name.blank?
end
end
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, continue
in a block "returns" from the block.
The specific behavior of normal blocks is:
continue
, 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:
value = [1,2,3,4].each do |i|
continue if i == 2
puts i
end
In this case, value
will be [1,2,3,4]
, the normal return value of the each
method, and the output will be:
1
3
4
In the case of break:
value = [1,2,3,4].each do |i|
break if i == 2
puts i
end
In this case, the value
will be nil
, since the break
also immediately returned from the each
method. You can force a return with a specific value by using break n
, which will make value
the same as n
. The output in the above case will be:
1
The important thing is that continue
and break
do not just apply to iterators, although their semantics are designed to behave like their equivalents in C in the case of iterators.
The operation of return
within Ruby blocks depends whether the block was constructed with Proc.new
or lambda
.
I recommend you read the highest rated answer on this other Stack Overflow question: When to use lambda, when to use Proc.new?
In this case, the block has the properties of one created with Proc.new
.
Calling return
in the context of that kind of callback would only make sense if this also made sense (which it obviously doesn't):
class Foo
return "bar"
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With