marcamillion
marcamillion

Reputation: 33755

How do I elegantly check for presence of both the object and associated objects?

I have an instance variable @tally_property, and if there are photos on that object I would like to cycle through the photos and show them.

So my code snippet looks like this:

<% if @tally_property.photos.present? %>
   <% @tally_property.photos.each_with_index do |photo, index| %>

The issue is that based on the above, if @tally_property is nil, then the entire first line throws an error.

So is there a 'nil' check I can do that isn't bulky, i.e. I don't want to do if @tally_property.nil?, on both the primary object and the association, and is elegant and ruby & rails-esque?

Upvotes: 2

Views: 468

Answers (4)

NeverBe
NeverBe

Reputation: 5038

One more way, just select all photos connected to this tally_property:

example how it might be:

Photo.joins(:tally_property).each_with_index do |photo, index|

Upvotes: -1

max
max

Reputation: 102036

In Ruby 2.3.0+ you can use the safe navigation operator:

@tally_property&.photos

ActiveSupport has a .try method that can be used to the same end in older versions of ruby:

@tally_property.try(:photos)

You can add a simple conditional to be able to safely iterate through the collection:

<% (@tally_property.try(:photos)||[]).each_with_index do |photo, index| %>

<% end %>

Rails 4 adds ActiveRecord::Relation#none and a change in behaviour so that associations always return a ActiveRecord::Relation. So its perfectly acceptable to write:

<% @tally_property.try(:photos).try(:each_with_index) do |photo, index| %>

<% end %>

After upgrading your app. Or you can use a partial and render:

<%= render partial: 'photos', collection: @tally_property.photos if @tally_property %>

Which removes the need for writing the iteration.

Upvotes: 2

spickermann
spickermann

Reputation: 106882

I would use the safe navigation operator (&.) and write something like this:

<% @tally_property&.photos&.each_with_index do |photo, index| %>
  ... 
<% end %>

Upvotes: 3

ian
ian

Reputation: 12251

Use && (or and, they each have their sweetspot).

Taking it out of Erb for a moment, I would generally write something like this:

if @tally_property and @tally_property.photos.present?

Depending on photos I might use:

if @tally_property and @tally_property.photos

or perhaps:

if @tally_property and not @tally_property.photos.empty?

Sometimes I'll use a temporary variable:

if (photos = @tally_property && @tally_property.photos)
  photos.each #…

That kind of thing.

I would recommend this episode of Ruby Tapas, And/Or for a longer (but still quick) look at it.

Upvotes: 0

Related Questions