Rubocop: Lint/EnsureReturn cop - why ensure must not return

Created on 5 Jun 2018  Â·  6Comments  Â·  Source: rubocop-hq/rubocop

In my code I have an ensure like that:

   return false unless successfully_updated(result)
end

And rubocop show me the following warning : Lint/EnsureReturn: Do not return from an ensure block.

But if I removed the return the result will not be the same.

Exemple:

def test_ensure_without_return
  true
ensure
  false  
end

test_ensure_without_return
=> true

def test_ensure_with_return
  true
ensure
  return false  
end

test_ensure_with_return
=> false

So is there a reason that ensure must not return a value ?

RuboCop version

0.54.0 (using Parser 2.5.0.5, running on ruby 2.3.1 x86_64-linux)

documentation good first issue hacktoberfest

Most helpful comment

Google lead me to this blog post. Apparently, ensure with explicit return also silently rescues.

All 6 comments

Google lead me to this blog post. Apparently, ensure with explicit return also silently rescues.

I see an opportunity to improve the documentation of this cop. 😉

On Wed, 6 Jun 2018 at 2:53, Michael Gee notifications@github.com wrote:

Google lead me to this blog post
http://blog.leshill.org/blog/2009/11/17/ensure-with-explicit-return.html.
Apparently, ensure with explicit return also silently rescues.

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/rubocop-hq/rubocop/issues/5949#issuecomment-394801703,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAGVyhQbOS0aCbJTRBlQNouNUIdsB08sks5t5sV_gaJpZM4Ua4Eq
.

Care to open a PR with documentation improvement @ckornaros? 🙂

Thanks for the link @mikegee ! I didn't know that ensure with return have this strange behavior.
And I didn't notice this behavior in my code because I try something like that (see example bellow) to check if ActiveRecord::Rollback is raised even if return is used on ensure:

  def test_ensure_without_return
    Order.transaction do
      order = Order.last
      order.user_id = 1000008
      order.save
      p 'raise now!'
      raise ActiveRecord::Rollback
    end
  ensure
    p 'ensure'
    false
  end

Result:

(0.4ms) BEGIN
Order Load (0.3ms) SELECT "orders".* FROM "orders" ORDER BY "orders"."id" DESC LIMIT $1 [["LIMIT", 1]]
SQL (0.9ms) UPDATE "orders" SET "user_id" = $1, "updated_at" = $2 WHERE "orders"."id" = $3
[["user_id", 1000008], ["updated_at", "2018-06-06 10:15:17.737387"], ["id", 100000036]]
"raise now!"
(0.3ms) ROLLBACK
"ensure"
=> nil

  def test_ensure_with_return
    Order.transaction do
      order = Order.last
      order.user_id = 1000008
      order.save
      p 'raise now!'
      raise ActiveRecord::Rollback
    end
  ensure
    p 'ensure'
    return false
  end

Result:

(0.3ms) BEGIN
Order Load (0.3ms) SELECT "orders".* FROM "orders" ORDER BY "orders"."id" DESC LIMIT $1 [["LIMIT", 1]]
SQL (0.8ms) UPDATE "orders" SET "user_id" = $1, "updated_at" = $2 WHERE "orders"."id" = $3
[["user_id", 1000008], ["updated_at", "2018-06-06 10:16:54.228939"], ["id", 100000036]]
"raise now!"
(0.4ms) ROLLBACK
"ensure"
=> false

But because of the transaction, ActiveRecord::Rollback will always be raised in my case but not in all other case without transactions.
So I definitely agree that it's a good practice to avoid return in ensure.
@bbatsov @Drenmi It'll be good to document that and I'll do it if I have the time.

Hey guys, I'd like to help with this issue. Is there anyone currently working on it?

Glad I found this thread; It's good to know more about how ensure works. We had an issue in production today because of a specific Rubocop fix that was made to our code.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Ana06 picture Ana06  Â·  3Comments

kirrmann picture kirrmann  Â·  3Comments

millisami picture millisami  Â·  3Comments

deivid-rodriguez picture deivid-rodriguez  Â·  3Comments

benoittgt picture benoittgt  Â·  3Comments