Rails 6 adds dig method to ActionDispatch::Request::Session


The Rails session object supports many hash methods. Ruby 2.3 introduced dig method to Hash, for safe hash traversal. Rails 6 brings dig method to ActionDispatch::Request::Session similar to Hash#dig.

This is useful if we have a want to access data or nested hashes in our session.

Before Rails 6

Lets take a look of this user attributes information, for current user stored as session information:

session[:user] = {id: 1, name: 'John Doe', gender: 'male',
                  notifications: [{kind: 'cancellation', email: true, text: false},
                                  {kind: 'reminder', email: true, text: true}]}

We can access this individual piece of information by hash access like so:

# Retrieving user's name from session
session[:user][:name]
#=> "John Doe"

# Retrieving kind from notifications at a particular index
session[:user][:notifications][1][:kind]
#=> "reminder"

While retrieving the value if any of the key is missing, it throws a NoMethodError:

# Retrieving user's phone number ext 
# Phone key does not exist in hash
session[:user][:phone][:ext]
*** NoMethodError Exception: undefined method '[]' for nil:NilClass

# Retrieving kind from notifications at index 2
# There are no notifications at index 2
session[:user][:notifications][2][:kind]
*** NoMethodError Exception: undefined method '[]' for nil:NilClass

To handle this error, we need to add individual key presence checks.

# Adding phone key presence check
session[:user][:phone] ? session[:user][:phone][:ext] : nil
#=> nil

This can get quite descriptive and repetitive.

With Rails 6

With Rails 6, we can now make use of dig method instead to access this information:

# Retrieving user's name from session
session.dig :user, :name
#=> "John Doe"

# Retrieving kind from notifications at a particular index
session.dig :user, :notifications, 1, :kind
#=> "reminder"

dig returns nil if any key is missing. This takes care of handling any nil values in nested hash accesses and returns nil.

# From out examples before
session.dig :user, :phone, :ext
#=> nil
session.dig :user, :notifications, 2, :kind
#=> nil

This allows us for simpler, safer access, of session objects.