可以访问ActiveRecord对象,但不能访问其属性

时间:2016-04-23 23:16:49

标签: ruby-on-rails ruby ruby-on-rails-4 activerecord

我正在使用form_fornested_form_fields在Rails中呈现视图。在此处,@procedure_stephas_many :procedure_step_actions的记录,其中每个belongs_to :error都是ProcedureError,其中(与某些其他模型的关系中)有一个整数:code我正试图访问并打印到页面。这是我的模板:

<%= form_for @procedure_step do |f| %>
    <%= f.nested_fields_for :procedure_step_actions do |act| %>
        <%= act.object.error.code %>
    <% end %>
<% end %>

当我运行时,我得到undefined method 'code' for nil:NilClass。好吧,所以我的关系搞砸了,我无法访问act.object.error,对吧?更改我的模板以显示它而不是产生#<ProcedureError:0x0000000ece02a8>,这是人们对功能关系的期望。使用debug将其内容转储到屏幕上会显示记录的所有属性,包括code,但我仍然无法使用原始模板访问它!显然act.object.error不是nil,因此Rails告诉我act.object.errornil对我没有任何意义。

感到沮丧,我尝试使用act.object.error.to_json解决问题。这为记录打印了正确的JSON及其所有属性。在JSON.load()上使用Hash为我提供了所有属性的正确[:code],但使用undefined method '[]' for nil:NilClass尝试访问代码会给我nil。同样,我知道对象不是/"code":([0-9]+)/.match(act.object.error.to_json),但Rails仍然拒绝允许我访问它。

缺少想法,我尝试使用正则表达式从原始JSON字符串中提取代码。 #<MatchData "\"code\":69" 1:"69">返回[1],这是对的。我使用undefined method '[]' for nil:NilClass尝试访问匹配的代码,但我又获得了act.object.error_id

ActiveRecord足够了,我心想。我决定转向原始SQL查询。我使用"... WHERE id = #{act.object.error_id}"获取了有问题的错误ID,然后首先将其打印到屏幕上以确保我可以访问它。幸运的是,我可以。然后我用WHERE id =将其插入到我的SQL查询中。我再次刷新页面,并遇到SQL错误。它显示了我生成的最终SQL查询字符串,但它以ProcedureError.find(action.object.error_id)结束。错误的ID未添加到字符串中。 ActionBuilder也犯了类似的错误。

我完全没有想法。什么可能阻止我以这么多不同的方式访问一个简单的整数?

2 个答案:

答案 0 :(得分:2)

这里至少有几个问题。首先,如果您使用的是4.x,则可能希望使用fields_for而不是nested_fields_for

第二个与第一个答案所表明的相似。你有一个嵌套的字段表单,它允许你嵌套一个级别,但你试图嵌套两个级别。通过解决你的demeter违规法则,你应该能够取得更多的进展。

调试这样的事情,你可以在你的erb中放入binding.prybyebug权利来获取更多信息。

<%- binding.pry %>

然后重新加载页面。您的服务器将在代码中停止,您可以使用变量值来了解有关正在发生的事情的更多信息。

答案 1 :(得分:1)

我可以立即看到的一件事是你违反了德米特法则

act.object.error.code

表单对象显然必须保留,但您可以通过在procedure_step上创建一个方法来委托对子对象的访问,这可以帮助处理空值和其他错误情况。

首先尝试委托,因为我不确定nested_forms_for创建的作用域是否允许ActiveRecord :: Relation对象正常执行。我会在当地仔细检查。

代表团可能如下所示

class ProcedureStepActions
   belongs_to :error
   def error_code
       @error.code
   end
end

编辑:

其他可能有用的东西是您正在使用的Ruby和Rails的版本以及任何其他额外的宝石或库。