How do I Rails…? Handle nil values in objects that are a result of 3rd party APIs

3 possible implementations

Loi V Tran
4 min readDec 30, 2017

The nil object sometimes isn’t fun in Rails. Nil ends up in the front end due to many reasons. One reason is an incomplete API response object received from a 3rd party API like Facebook.

{"provider"=>"facebook",
"uid"=>"420471495034828",
"info"=>
{"name"=>"Loi Tran", "image"=>"http://graph.facebook.com/v2.6/420471495034828/picture"},
"credentials"=> {"token"=>
"EAAPE0SbxwqoBAMcq0SlJgZAjJEigeZBhZCZB1wYPOXZCxiPiyEMlAHGp6dP16fKnZCN7AeyTX1n0smE6DvdqZA8iTmFs8cP4KN256b0r2QCH2xzAcUaKcZCuUFNdP1C03XKWf4kJgKnEepjE1KovRlc71YSJ3kZB3ZATZCefOmY2TrqowZDZD", "expires_at"=>1519802715, "expires"=>true},
"extra"=>{"raw_info"=>{"name"=>"Loi Tran", "id"=>"420471495034828"}}}

The Facebook Omni-Auth2 json return object provides only a snippet of data we need to work with in our web application.

Name, Image URL of Facebook main profile pic, etc…,

This results in nil values in our Ruby objects, and eventually views.

Setup

Rails 5.1.3 & Ruby 2.4.0

➜  railsbuuk git:(master) ✗ rails -v
Rails 5.1.3
➜ railsbuuk git:(master) ✗ ruby -v
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin15]
➜ railsbuuk git:(master) ✗

We want our Rails application to parse Facebook’s json response into a ruby object, User, so that the partials/templates we write using html & erb can render in the browser for clients. Specifically, browsers.

Consequently, we need to turn ruby User objects into production client side html.

Here’s the ruby User object our Rails application initializes.

Our applications User object will have among many fields, city, position, & school.

These nil values end up in our partials. How do we deal I with them?

=> # <User id: nil, name: nil, city: nil, school: nil, position: nil, ..>
2.4.0 :011 >

We get a NoMethodError when we refresh our browser because the nil class does not understand/respond to the .city method. Try it out!

We need to take into account nil objects in ours views because of insufficient/inadequate json responses from third party APIs such as Facebook.

</ul>
<li>Work: <%= other_user.position %></li>
<li>Education: <%= other_user.school %></li>
<li>Location: <%= other_user.city + ', ' + other_user.state %></li>
</ul>

Complains

undefined method `+' for nil:NilClass

We’ve got 3 options, disregarding for now higher level abstractions…

1. Add logic to view

<ul>
<li>
Work: <%= other_user.position %>
</li>
<li>
Education: <%= other_user.school %>
</li>
<% if other_user.city && other_user.state %>
<li>
Location: <%= other_user.city + ', ' + other_user.state %>
</li >
<% else %>
<li>
Location: Unlisted
</li>
<% end %>
</ul>

This works, but it doesn’t adhere to separation of concerns. Also we’d have to implement this if else anywhere else we want to show our users location.

2. Define 2 new ActiveRecord User model methods and call them from the view.

Model:

# ./app/models/user.rbdef current_city
self.city || ''
end
def current_state
self.state || ''
end

View:

# ./app/views/users/index.html.erb</ul>
<li>
Work: <%= other_user.position %>
</li>
<li>
Education: <%= other_user.school %>
</li>
<li>
Location: <%= other_user.current_city + ', ' + other_user.current_state %>
</li>
</ul>

Better, but now we run into cases where the user has filled out their city but not their state. Resulting in bugs in the front end, for example, an unnecessary comma.

3. Create a custom Rails helper method, so that we can extract code from both our view & our model.

Helper:

# => ./app/helpers/users_helper.rbmodule UsersHelperdef user_location(user)
return "#{user.city}, #{user.state}" if user.city &&
user.state
return "#{user.city}" if user.city
"Unlisted"
end
end

View:

# ./app/views/users/index.html.erb<ul>
<li>Work: <%= other_user.position %></li>
<li>Education: <%= other_user.school %></li>
<li>Location: <%= user_location(other_user) %></li>
</ul>

Which results in returning “Unlisted”, because neither conditional returns true.

And that’s it, my 3 lower levels techniques of handling nil values in the front end of a Rails 5.1.3 & Ruby 2.4.0 application

1. Adding logic to the Rails view to correct bug. Resulting in polluted view.

2. Implementing new methods in ActiveRecord model to keep logic outside of the view, but resulting in new errors.

3. Use Rails helper methods to keep logic out of the view & model; helping keep our ActiveRecord model class User far from God mode. This also allows us to isolate & unit test much easier!

Thanks for reading! Stay tuned in for more.

In part 2 we’ll solve this problem with design patterns. We’ll be using the Draper gem for implementing decorators to solve these problems at a higher level of abstraction.

Questions? Concerns? Better implementations?

I’d love to hear your thoughts or answer any questions! Don’t hesitate to comment or reach out to me at loi@coderschool.vn.

--

--