病灶
假设你有一个 Rake Task,需要记录一些用户信息,并且为了防止重复记录,你加了一段保护代码:
Task :record_information do
return if already_check?
record_information
end
看上去挺不错,但是一运行。Booom!!! 报错了 LocalJumpError: unexpected return
开刀
初看很迷茫,细看悔断肠: Rake task is a block not a method.
明确了原因,解决方案就显而易见了。
-
next
当你不想继续执行后面的的代码时,经常会使用 next 来结束一个循环或者 block 。那我们这里可不可以使用呢?行不行,试试就知道:
Task :record_information do next if already_check? record_information end bin/rake record_information # Bingo
-
break
在 each…do… 的循环类 block 中,我们经常使用 break 来结束,很自然地,那这里能不能用 break 来结束呢?让我们来看看,修改代码如下:
Task :record_information do next if already_check? record_information end bin/rake record_information # rake aborted! # LocalJumpError: break from proc-closure
看来不对。
-
使用 abort/fail/raise
另外,如果你认为这是异常情况,或许使用 abort/fail/raise 更符合语义。
Task :record_information do abort if already_check? record_information end bin/rake record_information # abort 不返回任何信息 # fail/raise 返回 rake aborted!
-
将 Task 的封装成方法,直接调用方法
在网上搜索 Rake 的最佳实践,许多人推荐,将 Task 的内容封装成方法,然后直接调用方法,这样就可以在方法体里面直接使用 return 来返回了,并且还附带了便于测试等一系列附属好处,噢耶!
Task :record_information do dosomething end def dosomthing return if already_check? record_information end bin/rake record_information # Bingo
下药
- Rake 是一个 block, 并不是一个方法,所以不能直接使用 return 来返回
- 根据实际情况来使用 next/abort/fail/raise 提早结束 Task
- 最理想的情况下,保持每一个 Rake Task 都仅仅是调用另一个业务方法,把所有处理逻辑放在那个业务方法里面完成