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: "john@example.com")
user.with(name: "Bob", email: "bob@example.com") do
puts user.name # Bob
puts user.email # bob@example.com
end
puts user.name # John
puts user.email # john@example.com
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.