JimBob
JimBob

Reputation: 175

Array#zip not working (undefined method for nil:NilClass)

I'm trying to make a table from 2 different sets of data

My Controller

@data = CompanyBorrower.find(params[:id])
@data1= @data.childs.all
@data2= @data.parents.all

The Table (a snippet)

            <% @data1.zip(@data2) do |f1,f2| %>
              <tr>
                <td><%= f1.company_borrower1.name %></td>
                <td><%= f2.company_borrower2.name %></td>
              </tr>
            <% end %>

But I get "undefined method `company_borrower2' for nil:NilClass". If I remove one or the other set of data it works fine.

I think I know the issue; I think it is because the "data1" returns 5 rows, whilst "data2" would have 1 row. If I switch, it works, but I only get one row!

So I (think) I know the issue, but have no idea how to resolve?

Edit - Updated

Note that company_borrower1 & company_borrower2 use the same model -

CompanyBorrower Model

has_many :childs, :class_name => 'Parent', :foreign_key => 'company_borrower_id'
has_many :parents, :class_name => 'Parent', :foreign_key => 'company_borrower_id1'

Parent Model

belongs_to :company_borrower1, :class_name => 'CompanyBorrower', :foreign_key => :company_borrower_id
belongs_to :company_borrower2, :class_name => 'CompanyBorrower', :foreign_key => :company_borrower_id1

UPDATE 2

If I do the following it works great, but it places what would be columns across rows. I can work with that, but would still prefer to know how to achieve my original question for future reference

              <tr>
                <% @data1.each do |f1| %><td><%= f1.company_borrower1.name %></td><% end %>
              </tr>
              <tr>
                <% @data2.each do |f1| %><td><%= f1.company_borrower2.name %></td><% end %>
              </tr>

Upvotes: 0

Views: 345

Answers (2)

Jegan
Jegan

Reputation: 194

if you are using ruby 2.3 or greater version you can make use of Safe navigation operator (&.) instead of try method

        <% @data1.zip(@data2) do |f1,f2| %>
          <tr>
            <td><%= f1&.company_borrower1&.name %></td>
            <td><%= f2&.company_borrower2&.name %></td>
          </tr>
        <% end %>

The safe navigation operator (&.) will return nil if the object equals nil, otherwise it calls the method on the object..So, if you use the safe navigation operator, you need to make sure it will be called on the all methods.For example, I have used safe navigation operator on f2 object , f2&.company_borrower2 will return nil,but here we are calling agin name method on the return value of f2&.company_borrower2.So in oreder to avoid the error, we need to call agian safe navigation operator.

Same thing applies on the usage of try method

       <% @data1.zip(@data2) do |f1,f2| %>
          <tr>
            <td><%= f1.try(:company_borrower1).try(:name) %></td>
            <td><%= f2.try(:company_borrower2).try(:name) %></td>
          </tr>
        <% end %>

Upvotes: 2

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

My wild guess would be to use try on what’s returned. So instead of this:

<td><%= data1.name %></td>
<td><%= data2.name %></td>

You should do something like:

<td><%= data1.try(:name) %></td>
<td><%= data2.try(:name) %></td>

Upvotes: 0

Related Questions