0

I'm still pretty new to rails and this seems pretty basic but I can't find a straight answer.

I have 4 models:

def Order
  has_many :payments

def Payment
  belongs_to :order
  has_one :collection
  has_one :dispute

def Collection
  belongs_to :payment

def Dispute
  belongs_to :payment

The "show" Order page has the order details and a loop for all payments:

<% @order.payments.each do |f| %>
<div class="well">
  <p> Payment Date: <%= f.date_created %> </p>
  <p> Amount: <%= f.amount %> </p>
    ....# some other fields
  <p> Collection Date: <%= f.collection.date_created %> </p>
  <p> Disputed Date: <%= f.dispute.date_created %> </p>
</div>

This all works perfect unless there is any value missing in this loop. Which is a lot since many payments don't have "collections" or "disputes". When any value is missing I get the following error:

NoMethodError in Orders#show
undefined method `whatever value is missing' for nil:NilClass  

Ideally the missing field would simply render blank, but I'm not sure why it breaks the whole view. Any help would be greatly appreciated!

0

3 Answers 3

2

Have a look at Object#try method, and here is how you'd use it:

<% @order.payments.each do |f| %>
<div class="well">
  <p> Payment Date: <%= f.try(:date_created) %> </p>
  <p> Amount: <%= f.try(:amount) %> </p>
    ....# some other fields
  <p> Collection Date: <%= f.try(:collection).try(:date_created) %> </p>
  <p> Disputed Date: <%= f.try(:dispute).try(:date_created) %> </p>
</div>

Using try like above will make sure that you are not thrown an error, instead it renders blank as you want.

Update:

As @muistooshort has commented, try should be used cautiously as potential bugs could get swallowed unknowingly. Use try only where it's required; in this case f.try(:dispute) and f.try(:collection).

Sign up to request clarification or add additional context in comments.

5 Comments

Putting try on them all looks like a good way to hide bugs, if f.nil? then @order.payments is buggy and should be fixed. Narrowly applying try just on the f.collection.date_created and f.dispute.date_created calls would make more sense, no?
I believe the .try should go on the object you suspect could be nil. So I'd write, e.g., f.collection.try(:date_created). If the object f itself might be nil, and thus we don't want to show anything, I'd use this at the top of the loop: next if f.nil?
@muistooshort, yes selectively applying try on attributes would be the way to go. @user2815613, please have a look at @muistooshort's comment.
This worked, thanks! I do agree with that something might be buggy, so I'll try to play around with "try" on the other fields and see if I can isolate the issue.
I was thinking more along the lines of f.collection.try(:date_created) and f.dispute.try(:date_created).
0

You can use the try method -http://api.rubyonrails.org/classes/Object.html#method-i-try

For example, replace

<%= f.date_created %>

with

<%= f.try(:date_created) %>

Comments

0

You can also use NullObject pattern. It's more complex but handling blank value in every possible case can leads you to a lot of spaghetti code. Moreover from my experience try method is often overused. Take a look: http://devblog.avdi.org/2011/05/30/null-objects-and-falsiness/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.