Set And Restore Public Attributes Around a Block Using Object#with

Object#with(**args) method is not part of the Ruby standard library. Thanks to Rails, it’s a convenience method added to the Object class to manage object states.

def test_posts_when_user_is_verified
  user.with(verified: true) do
    # Perform posts testing
  end
end

Before

Saving the value of an attribute, setting a new value, and then restoring the previous value in an ensure clause is a fairly popular pattern in Ruby, particularly in testing or in api calls

def test_posts_when_user_is_verified
  old_value = user.verified
    user.verified = true
    # Perform posts testing
  ensure
    user.verified = old_value
end

This is a common and popular pattern as everything works fine in this pattern but sometimes when we have a code block before the # perform posts testing which raises an exception then user.verified is set to old_value due to the ensure block and # perform posts testing will have user.verified with old value instead of true

After

Object#with helps to streamline and elegantly improve this technique. It is an addition to the Ruby Object class that offers a simpler method of managing object states.

With the upcoming version of Rails, we can temporarily change one or more attributes of an Object with Object#with and guarantee that they automatically revert to their initial values even if an error arises while the block is being executed.

def test_posts_when_user_is_verified
  user.with(verified: true) do
    # Perform posts testing
  end
end
def test_users_with_different_credentials
  user = User.new(name: "John", email: "[email protected]")
  user.with(name: "Bob", email: "[email protected]") do
    puts user.name # Bob
    puts user.email # [email protected]
  end
  puts user.name # John
  puts user.email # [email protected]
end

#with method isn’t available on Nil class and other common immediate types because immediate values are immutable and do not support method additions or removals, applying the with method to them doesn’t work as expected. It may lead to errors or unexpected behaviour.

For example, we have Integer 32 and if we try to use with method on top of the Integer like 32.with(args) to change its state temporarily, it won’t work because we cannot modify an immediate value in this way.

Due to this reason, #with is not available on

NilClass, TrueClass, FalseClass, Integer, Float, Symbol

Object#with simplifies state management of Ruby object, making our code cleaner, more readable, and less error-prone. Whether we’re writing tests, working with APIs, or configuring our application.

Need help on your Ruby on Rails or React project?

Join Our Newsletter