Reputation: 335
controller
def show
@dailies = Daily.where(store_id: params[:store]).order(created_at: :asc).by_month_year(params[:month],params[:year])
@services = Service.all.order(id: :asc)
end
view
<%= daily_data_for(params[:store], params[:month], date.day, params[:year], 'starting_safe') %>
helper
def daily_data_for(store, month, day, year, field)
Daily.where(store_id: store, month: month, day: day, year: year).first().send(field)
end
I'm getting the error undefined method 'starting_safe' for nil:NilClass
when trying to display ActiveRecord object attribute in the view. I'm a but confused as it shouldn't be nil, because if I remove .send(field) from the helper, I get #<Daily:0x00007fea597aad50>
. So it's returning an object. So then I inspect the Activerecord Object in the view:
daily_data_for(params[:store], params[:month], date.day, params[:year], 'starting_safe').inspect
Which displays #<Daily id: 1030, store_id: 1, created_at: "2018-10-01 18:20:07", updated_at: "2018-10-01 18:20:07", starting_safe: 0.1e1, ending_safe: 0.1e1, total_in: 0.1e1, total_out: 0.1e1, sum: 0.1e1, starting_drawer: 0.1e1, ending_drawer: 0.1e1, over_short: 0.1e1, year: "2018", month: "10", day: "1">
It's getting the right record and returning it, but then I get undefined method of nil class when I try to access starting_safe.
Why am I unable to display starting_safe in the view? I'd like to be using the instance variable @dailies in the helper instead of querying the database again, but I get the same errors. I've tried in the console and everything works fine. I'm a bit lost as to what's going on here.
Upvotes: 3
Views: 4118
Reputation: 11216
The error undefined method 'starting_safe' for nil:NilClass
is specifically telling you that you can't call starting_safe
on nil
. Since your helper method calls a scope .where
method, calling .first
on that doesn't insure that it won't be an empty activerecord relation object. If it is empty, then calling .first
on it will return nil
. So you might wanna just use safe navigation to be safe.
def daily_data_for(store, month, day, year, field)
Daily.where(store_id: store, month: month, day: day, year: year).first&.send(field)
end
Or if you happen to be on ruby version < 2.3 just use a .try
Daily.where(store_id: store, month: month, day: day, year: year).first.try(:send, field)
#try will only run if first is not nil
Upvotes: 0
Reputation: 230336
I'm pretty sure that the record you inspect (Daily with id=1030) and the failing [non-existing] record are two different records. Here's how you can find out. Amend your method like this, temporarily:
def daily_data_for(store, month, day, year, field)
daily = Daily.where(store_id: store, month: month, day: day, year: year).first
raise "Daily not found for #{store.inspect}, #{month.inspect}, #{day.inspect}, #{year.inspect}" unless daily
daily.send(field)
end
Now the error message should be much more revealing.
Upvotes: 2