0

我有一个几年前有人写的 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

不幸的是,observation.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 的文档非常糟糕(这很公平,因为它是免费软件)。另外我什至不知道如何开始在谷歌上搜索这个(我已经尝试了好几天)。

请帮忙!:)

4

3 回答 3

2

除了对 Rails 文档的不同看法外,您还调用contact了一个在这种情况下不存在的调查,导致调用nil.contact.

一种替代方法是在呼叫之前检查调查是否存在contact,例如以这种方式。

def create_permitted?
  acting_user == (survey && survey.contact) or acting_user.administrator?
end
于 2012-12-10T16:10:54.417 回答
1

您收到错误是因为引用 column( survey_id) 可能包含一个null或无效的引用 ID。

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

( self.survey and acting_user == self.survey.contact ) or acting_user.administrator?
于 2012-12-10T16:09:34.540 回答
1

我将附和其他两位所说的话。您尝试引用的调查是nil,并且nil没有调用方法contact。我将提供一个稍微不同的解决方案:

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

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

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

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

#try是 Rails 核心扩展的一部分Object。实际上,它不像我上面所说的那样工作,因为调用 to 引起的异常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

于 2012-12-10T16:20:44.657 回答