Rails NoMethodError nil的未定义方法`data':NilClass(Controller#update)

时间:2014-08-28 04:03:44

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

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

我的rails应用程序中有一个模板模型。它有一个方法"数据"在其中定义。

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

我在最初保存新模板时存储了关联local_template的id,但是如何确保在更新操作中再次引用该id,这样我就不会出现no方法错误?

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

型号:

    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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

你应该确认@template不是nil,如果@template为nil,你就不能使用数据方法。

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