错误:nil的未定义方法`contact':NilClass

时间:2012-12-10 15:55:37

标签: ruby-on-rails ruby hobo

我有一个有人在几年前写过的ruby / rails / hobo系统,我需要移植到最新版本的ruby / rails / hobo。似乎ruby并不关心向后兼容性,因此以前在旧应用程序中工作的代码不再起作用了:

在observation.rb模型文件中,旧应用程序具有:

belongs_to :survey
has_one :site, :through => :survey

def create_permitted?
  acting_user == self.survey.contact or acting_user.administrator?
end

survey.rb模型文件有:

belongs_to :contact, :class_name => 'User', :creator => true

不幸的是,observe.rb中的代码在新的ruby / rails / hobo下无效,它给了我错误:

NoMethodError in Observations#index

Showing controller: observations; dryml-tag: index-page where line #1 raised:

undefined method `contact' for nil:NilClass
Extracted source (around line #1):

0
Rails.root: /home/simon/ruby/frogwatch2

Application Trace | Framework Trace | Full Trace
app/models/observation.rb:48:in `create_permitted?'

如何更改“create_permitted”方法?我发现ruby / rails / hobo的文档非常糟糕(这很公平,因为它是免费软件)。此外,我甚至不知道如何开始在谷歌搜索这个(我已经尝试了几天)。

请帮忙! :)

3 个答案:

答案 0 :(得分:2)

除了对Rails文档的不同观点之外,您在调查中调用contact,在这种情况下不存在,导致调用nil.contact

另一种方法是在调用contact之前检查是否存在调查,例如以这种方式。

def create_permitted?
  acting_user == (survey && survey.contact) or acting_user.administrator?
end

答案 1 :(得分:1)

您收到错误,因为参考列(survey_id)可能包含null或无效的参考ID。

如果允许null或无效引用,则更改代码以处理它

( self.survey and acting_user == self.survey.contact ) or acting_user.administrator?

答案 2 :(得分:1)

我要回应其他两位所说的话。您尝试引用的调查是nil,而nil没有名为contact的方法。我将提供一个稍微不同的解决方案:

def create_permitted?
  acting_user == survey.try(:contact) or acting_user.administrator?
end

#try方法存在于nilsurvey上。它基本上将方法调用包装在rescue中。从概念上讲,它看起来像:

def try(method_name, *args)
  self.send(method_name, args) rescue nil
end

这可能会减少您必须编写的代码量以捕获可能不存在关系的条件,从而阻止NoMethodError异常。

#tryObject的Rails核心扩展的一部分。实际上,它不像我上面那样工作,因为调用Object#try引起的异常仍然会像通常那样发生。相反,它通过调用Object来扩展send。它通过返回NilClass来扩展nil,因此它不会尝试将任何方法发送到NilClass,从而阻止NoMethodError。正如tadman在评论中指出的那样,一个包罗万象的异常处理程序通常不是一个好主意。

https://github.com/rails/rails/blob/6ef9fda1a39f45e2d18aba4881f60a19589a2c77/activesupport/lib/active_support/core_ext/object/try.rb

<强>更新

更好的解决方案,也就是我忘记的解决方案,是使用delegate

例如:

class User < ActiveRecord::Base
  delegate :contact, to: :survey, prefix: true, allow_nil: true
end

然后你会打电话给user.survey_contact,如果调查是nil,则会优雅地失败。