【问题标题】:Rails NoMethodError undefined method `data' for nil:NilClass (Controller#update)Rails NoMethodError 未定义方法“数据”为 nil:NilClass (Controller#update)
【发布时间】:2014-08-28 04:03:43
【问题描述】:

编辑:事实证明我犯了一个非常简单的错误,并且有一个与不再存在的 LocalTemplate id 关联的模板。如果有人遇到此问题并认为他们无法在更新操作中关联另一个模型的 id,请确保您没有意外删除导致该 id 不再存在的父对象! 下面的代码虽然大大简化,但确实对我有用。

我的 rails 应用中有一个模板模型。它定义了一个方法“数据”。

我可以使用@template.data 在创建和显示操作中访问此方法,但是在我的控制器的更新操作中使用相同的@template.data 时,我得到一个无方法错误,因为我没有显示正确的本地模板ID。这一行可以在模型中找到base_data = YAML.load(local_template.data)

我在最初保存新模板时存储了关联的 local_template 的 id,但是如何确保在更新操作中再次引用该 id,以免出现 no method 错误?

这里是模板模型和控制器的简化版本

型号:

    class Template < ActiveRecord::Base
      def data
        base_data = YAML.load(local_template.data)
        # couldn't pass the correct LocalTemplate here because
        # the local_template_id I had in my Template model no
        # longer existed. Changing the id to a LocalTemplate
        # that did exist fixed the issue.
      end
    end

控制器:

    class TemplatesController < ApplicationController
      def index
        @business = Business.find(params[:business_id])
        @templates = @business.templates.all
      end

      def new
        @business = Business.find(params[:business_id])
        @local_templates = LocalTemplate.all
        @template = @business.templates.build
      end

      def create
        @business = Business.find(params[:business_id])
        @local_templates = LocalTemplate.all
        @template = @business.templates.build(template_params)

        if @template.save
          @template.data #works fine here

          redirect_to business_url(@template.business_id)
        else
          render 'new'
        end
      end

      def show
        @business = Business.find(params[:business_id])
        @template = @business.templates.find(params[:id])
        @template.data #works fine here too
      end

      def edit
        @business = Business.find(params[:business_id])
        @local_templates = LocalTemplate.all
        @template = @business.templates.find(params[:id])
      end

      def update
       @business = Business.find(params[:business_id])
       @template = @business.templates.find(params[:id])

        if @template.update_attributes!(pass_template_params)

          Api.new.update_template(@template.data.to_json) #this is where I had a problem

          redirect_to business_url(@template.business_id)
        else
          render 'edit'
        end
      end
    end

【问题讨论】:

  • 我在协调@template.update_attributes(template_params)@template.data #can't use it here or I get a no method error 时遇到了真正的麻烦,您是否在Template 中覆盖了update_attributes
  • 我删除了很多代码以试图让事情变得清晰,但在if @template.update_attributes(template_params) 之后我进行了一个需要使用@template.data 的API 调用。我没有显示呼叫,但它会去的地方,它不起作用。
  • 在那一行之后是这样的:Api.new.update_template(@template.data)
  • 对,但是如果满足if @template.update_attributes(template_params),就不能为nil。这使得错误(表明它为零)非常混乱。您是否删除了该方法中的其他代码?可能值得更换它,并且可能包括您的堆栈跟踪。它是指argument.data 而不是Api.new.update_template 中的argument
  • 布拉德你说得对,我看的不够近。问题其实出在 Template 模型的 data 方法里面。我将更新代码以反映这一点。

标签: ruby-on-rails ruby controller nomethoderror updatemodel


【解决方案1】:

你混合了很多。您的控制器中有很多需要重构的地方...
首先,你的 TemplatesController 应该是关于模板资源的,但是你的控制器看起来更像一个 BusinessesController。一般来说,例如,您的更新操作应该看起来更像:

def update
  @template = Template.find params[:id]
  @template.attributes = template_params # though this should raise a NoMethodError, because you dind't define it; I'd prefer params[:template] if possible
  if @template.save
    redirect_to business_url(@template.business_id)
  else
    @local_templates = LocalTemplate.all
    render 'edit'
  end
end

实例化@business 和@local_templates 毫无意义,因为您根本不使用它。如果可以,请加快您的回复速度! :)
修复了这个问题,更新中不需要嵌套资源的开销(就像您所做的那样)。
如果由于验证原因保存 @template 失败,您最好延迟加载业务对象:

@template.business

在您的 /templates/edit.html.erb 部分中。那么您也不需要到您的编辑操作的嵌套路由...您看,它清理了很多。
作为一般准则,您应该创建尽可能少的控制器实例变量。
如果您清理了控制器和视图,调试数据问题会更容易。
我假设:

local_template

在您的模板模型中成为关联的 LocalTemplate 模型对象。因此,如果您确保引用的对象存在,那么在任何地方调用它应该没有问题:

class Template < ActiveRecord::Base
  def data
    return if local_template.nil?
    YAML.load(local_template.data)
  end
end

或验证 local_template 对象的存在。甚至是 b

【讨论】:

  • 感谢@tobago,我的代码示例被大大简化,只显示了我认为与问题直接相关的内容。实际控制器中存在更多复杂性。模板属于企业并从特定的企业视图进行编辑。不过你是对的,我犯了一个简单的错误,即拥有一个属于不再存在的 LocalTemplate 的模板。我必须给它一个新的 LocalTemplate id,然后我的更新操作才起作用。谢谢!
【解决方案2】:

你要确认@template不为nil,如果@template为nil,你不能使用data方法。

1.9.3-p547 :024 > nil.data
NoMethodError: undefined method `data' for nil:NilClass
from (irb):24
from /Users/tap4fun/.rvm/rubies/ruby-1.9.3-p547/bin/irb:12:in `<main>'

你应该使用update_attributes!,如果记录无效,它会引发异常。

你可以这样做。

if @template
   @template.update_attributes!(template_params)
   @template.data 
end

【讨论】:

  • 谢谢,我发现问题实际上在模型base_data = YAML.load(local_template.data) 的这一行内,并更新了我的问题。我仍然不确定确切的解决方案。我将使用 update_attributes!相反;感谢您指出这一点。
猜你喜欢
  • 2015-06-30
  • 2015-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-14
  • 2013-01-14
  • 2017-10-02
  • 1970-01-01
相关资源
最近更新 更多