Почему я получаю «неопределенный метод для nil: NilClass» для объекта, который явно существует? - PullRequest
0 голосов
/ 31 октября 2018

контроллер

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

вид

<%= daily_data_for(params[:store], params[:month], date.day, params[:year], 'starting_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

Я получаю ошибку undefined method 'starting_safe' for nil:NilClass при попытке отобразить атрибут объекта ActiveRecord в представлении. Я в замешательстве, но это не должно быть равно нулю, потому что, если я удалю .send (поле) из помощника, я получу #<Daily:0x00007fea597aad50>. Так что это возвращает объект. Затем я проверяю объект Activerecord в представлении:

daily_data_for(params[:store], params[:month], date.day, params[:year], 'starting_safe').inspect

Который отображает #<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">

Он получает правильную запись и возвращает ее, но затем я получаю неопределенный метод класса nil, когда пытаюсь получить доступ к initial_safe.

Почему я не могу отобразить start_safe в представлении? Я хотел бы использовать переменную экземпляра @dailies в помощнике вместо повторного запроса к базе данных, но я получаю те же ошибки. Я пытался в консоли, и все работает отлично. Я немного растерялся относительно того, что здесь происходит.

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

Ошибка undefined method 'starting_safe' for nil:NilClass специально говорит вам, что вы не можете позвонить starting_safe на nil. Поскольку ваш вспомогательный метод вызывает метод области действия .where, вызов .first для этого не гарантирует, что он не будет пустым объектом отношения activerecord. Если он пуст, то вызов .first для него вернет nil. Так что вы можете просто использовать безопасную навигацию , чтобы быть в безопасности.

def daily_data_for(store, month, day, year, field)
  Daily.where(store_id: store, month: month, day: day, year: year).first&.send(field)
end

Или, если вы оказались на версии ruby ​​<2.3, просто используйте <code>.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
0 голосов
/ 31 октября 2018

Я почти уверен, что проверяемая вами запись (Daily с id = 1030) и ошибочная [несуществующая] запись - это две разные записи. Вот как вы можете узнать. Временно измените ваш метод следующим образом:

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

Теперь сообщение об ошибке должно быть гораздо более показательным.

...