Reputation: 17
I'm pretty new in Rails and I need your help. I have Job model, Invoice model and Item model.
job.rb model have - has_one :invoice, dependent: :destroy
accepts_nested_attributes_for :invoice
invoice.rb have - belongs_to :job, optional: true, :foreign_key => 'job_id'
has_many :items, dependent: :destroy
accepts_nested_attributes_for :items
item.rb have - belongs_to :invoice, optional: true, :foreign_key => 'invoice_id'
Everything is ok, it creating the job and invoice with items inside and on invoice show it generate the invoice but in invoices/index I want to list all invoices in a table but I can't get = @invoice.job.customer_name.capitalize
it give me a error - NoMethodError in Invoices#index undefined method `customer_name' for nil:NilClass.
It is like job is nil. My question is why in invoices/show.html.erb I can access
= @invoice.job.customer_name.capitalize
and in index it give me error ?
As you can see in invoices/show.html.haml I have = @invoice.job.customer_name.capitalize
and it give me correct data:
.container.invoice
.row
.col-sm-6
- if current_user.logo.present?
= image_tag current_user.logo.url(:thumb)
- else
= image_tag 'blank.jpg'
.col-sm-3
.col-sm-3
%h3
= current_user.full_name.titleize
%p
= current_user.email
%p
= current_user.phone
%hr
.row
.col-sm-6
%h4
Customer :
= @invoice.job.customer_name.capitalize.html_safe
%p
%b
Phone:
= @invoice.job.customer_tel
%p
%b
Email:
= @invoice.job.customer_email
.col-sm-3
.col-sm-3
%p
%b
Invoice: #
= @invoice.id
%p
%b
Date:
= @invoice.created_at.strftime("%B %d, %Y")
%hr
.row
.col-sm-12
%table.table.table-striped.table-hover
%thead
%tr.sortable-table
%th.col-sm-1
Item Id
%th.col-sm-3
Item/Operation
%th.col-sm-3
Unit cost/Hr rate
%th.col-sm-3
Qty
%th.col-sm-2
%th.col-sm-3
Amount
%tbody
- @invoice.items.each do |item|
%tr.sortable-table
%th
= item.id
%th
= item.name
%th
= number_to_currency item.unit_cost
%th
= item.qty
%th
%th
- amount = number_to_currency(item.unit_cost * item.qty)
= amount
%hr
.row
.col-sm-6
.col-sm-3
.col-sm-3
%b
Subtotal
- sum = 0
- @invoice.items.each do |item|
- if item.qty?
- subtotal = (item.unit_cost * item.qty)
- sum += subtotal
= number_to_currency(sum)
%p
%b
Tax
= number_to_currency(sum * (@invoice.tax/100))
%p
%h4
%b
Total
= number_to_currency((sum * (@invoice.tax/100)) + sum)
%hr
= link_to 'Edit', edit_invoice_path(@invoice)
\|
= link_to 'Back', invoices_path
But in invoices/_invoice.html.erb I have the error :
%h1 Listing invoices
%table.table.table-striped.table-hover
%thead
%tr.sortable-table
%th
Id
%th
Job Id
%th
Item
%th
Unit cost
%th
Qty
%th
Amount
%tbody
= render @invoices
%br
= link_to 'New Invoice', new_invoice_path
<tr>
<td>
<%= invoice.id %>
</td>
<td>
<%= invoice.job_id %>
</td>
<td>
</td>
<td>
<%= invoice.unit_cost %>
</td>
<td>
<%= invoice.qty %>
</td>
<td>
<%= invoice.job.customer_name %>
</td>
<td>
<%= link_to 'Details', invoice, class: 'btn btn-primary btn-xs' %>
</td>
<td>
<%= link_to "", edit_invoice_path(invoice), id: "edit_#{invoice.id}", class: 'glyphicon glyphicon-pencil index-icons' %>
</td>
<td>
<%= link_to "", invoice_path(invoice), method: :delete, id: "delete_invoice_#{invoice.id}_from_index", class: 'glyphicon glyphicon-trash index-icons', data: {confirm: 'Are you sure ?'} %>
</td>
</tr>
Thank you, and if you need more code let me know.
Update:
[you see invoice Id 47 have job id 67][1]
[the job id 67 is exist][2]
[on the invoice show I have name of customer][3]
[1]: https://i.sstatic.net/ODAkb.png
[2]: https://i.sstatic.net/uGK21.png
[3]: https://i.sstatic.net/sRTWS.png
Upvotes: 0
Views: 106
Reputation: 6455
NoMethodError in Invoices#index undefined method `customer_name' for nil:NilClass.
This means where you are calling customer_name:
@invoice.job.customer_name.capitalize.html_safe
You are calling it on nil, or in other words:
@invoice.job
returns nil. If the invoice does not have a job associated with it, any methods involving the invoice's job will fail (apart from just @invoice.job, which will return nil).
Your two options are to either make sure every invoice has a job associated with it before rendering, or to rewrite your view template as:
.container.invoice
.row
.col-sm-6
- if current_user.logo.present?
= image_tag current_user.logo.url(:thumb)
- else
= image_tag 'blank.jpg'
.col-sm-3
.col-sm-3
%h3
= current_user.full_name.titleize
%p
= current_user.email
%p
= current_user.phone
%hr
.row
.col-sm-6
- if @invoice.job
%h4
Customer :
= @invoice.job.customer_name.capitalize.html_safe
%p
%b
Phone:
= @invoice.job.customer_tel
%p
%b
Email:
= @invoice.job.customer_email
.col-sm-3
.col-sm-3
%p
%b
Invoice: #
= @invoice.id
%p
%b
This will only display the bottom section of the view if a job is associated with the @invoice
Upvotes: 1