How to fix Ruby 2.7 warning: Using the last argument as keyword parameters is deprecated

kinopyo avatar
kinopyo

After upgrading to Ruby 2.7, I started to see these warnings in my Rails server logs:

warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call

In Ruby 2.7, the way it handles the positional arguments and keyword arguments is changed, aiming to provide a smooth transition to Ruby 3.

Understand the change

If you were passing a Hash as a keyword argument, now you'd need to update your code to use the double splat operator:

def avatar(user, size:)
end

options = { size: "medium" }

avatar(user, options) # => 💥 warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
avatar(user, **options) # => 👍 use double splat to explicitly convert a Hash into keyword argument

Let's look at another example where the keyword argument is used to as the last argument with a default value.

def buy(stuff, need_receipt: false)
  puts "stuff: #{stuff}"
  puts "need_receipt: #{need_receipt}"
end

buy(item: "burger")
# 💥 warning: Passing the keyword argument as the last hash parameter is deprecated
# => stuff: { :item => "burger" }
# => need_receipt: false

Here you'll need to add braces {} to explicitly pass a Hash object:

buy({ item: "burger" })
# => stuff: { item: "burger }
# => need_receipt: false

(Now it makes the code review a bit troublesome as now we can't blindly suggest removing the { } from the single Hash parameter like before 😅)


The reason why the Ruby team made the change is because the automatic conversion "too complex and troublesome". It had caused confusions and many bug report tickets in the past. So now we as the developers need to code it explicitly.

Learn more from the official ruby doc: - Separation of positional and keyword arguments in Ruby 3.0

3 ways to suppress the warnings

Many gems have been updated to the newly recommended style. There is a PR in Rails as well, but as of now the change has not been released.

To temporarily suppress the warnings.

  1. Start the rails server with RUBYOPT='-W:no-deprecated' rails s
  2. Set export RUBYOPT='-W:no-deprecated' in your bash/zsh profile
  3. Set Warning[:deprecated] = false in your ruby code

If you were to use No.3 and put it in a Rails initializer, it'll affect all members so make sure that's your intention, and be sure to come back remove it when Rails and other gems have caught up with the warnings.

Read more