Rails undefined方法`model_name'用于NilClass:Class

时间:2012-06-19 03:03:43

标签: ruby-on-rails ruby ruby-on-rails-3

我有一个表单,我想要显示在每个页面的顶部,所以我将它包含在/app/views/layouts/application.html.erb文件中,我收到错误undefined method model_name 'for NilClass:Class`在尝试加载页面时。

这是application.html.erb

中的表单摘要
 <%= form_for @user do |f| %>
    <h3>Add new contact</h3>
    <%= f.text_field :first_name %><br />
    <%= f.text_field :last_name %>
    <%= f.text_field :email %>
    <hr />
    <%= f.submit "Add Contact" %>
<% end %>

这是我的/app/controllers/user_controller.rb

class UserController < ApplicationController

    def index

    end

    def new
        @user = User.new
    end

end

我在想我正在遇到这个错误,因为表单在application.html.erb文件中,我需要以某种方式指定路径,但是我再次对rails很新。

如果您需要发布任何其他内容,请与我们联系。

修改 按照Ola的建议,在我的app / views / layouts / application.html.erb文件中,我有类似的东西:

<div>
<%= yield :add_user %>
</div>

在我的app / views / users / new.html.erb文件中我有这个

<% content_for :add_user do %>
    <%= form_for @user do |f| %>
        <h3>Add new contact</h3>
        First Name<br />
        <%= f.text_field :first_name %><br />
        Last Name<br />
        <%= f.text_field :last_name %><br />
        Email<br />
        <%= f.text_field :email %>
        <hr />
        <%= f.submit "Add Contact" %>
    <% end %>
<% end %>

表单未呈现,因为我的网址为http://localhost:3000/admin/index,因此它正在app / views / admin / index.html.erb中查找add_user content_for

5 个答案:

答案 0 :(得分:12)

如果表单包含在多个操作(页面)中,您需要将@user设置为某个内容,否则form_for指令将失败(它将无法创建表单 for )。

更好的方法(以及Rails默认设置)是为每个操作设置单独的视图,每个视图仅包含该操作所需的元素,并使用application.html.erb加载到<%= yield %>布局中。因此,您将拥有一个app/views/users/new.html.erb视图,其中包含表单。你从不很少需要在Rails中定义任何加载路径,它们都来自模型,控制器和动作名称 - 或者来自你的routes.rb。这是 convention over configuration 范例的核心部分,它在Rails中运行得非常深入。

编辑如果您 需要在每个页面上创建一个新表单(例如通常用于UserSessions),您可以重写{{ 1}}这样它就不依赖于存在的对象:

form_for

或者如果您需要强制它发布到form_for(User.new) 方法

create

您可以在Ruby On Rails API docs.

中详细了解资源驱动的form_for(User.new, :url => { :action => "create" })

答案 1 :(得分:11)

你先尝试过调试吗?我问,因为你说你是Rails的新手。如果没有,这是我的方法。我想分享它,因为我很惊讶有多少人(不管出于何种原因)仔细调试。

(我创建了一个测试应用,以便我可以解决您的问题。首先,我访问了http://localhost:3000/users。)

首先,查看堆栈跟踪。

  

用户#index

中的NoMethodError      

显示/Users/david/dev/testapp/app/views/layouts/application.html.erb第11行   提出:

     

NilClass:Class的未定义方法`model_name'   提取的来源(第11行):

8: </head>
9: <body>
10: 
11: <%= form_for @user do |f| %>
12:     <h3>Add new contact</h3>
13:     <%= f.text_field :first_name %><br />
14:     <%= f.text_field :last_name %>

这告诉您代码中的第11行是问题所在。想想 - 可能是什么问题?路由不太可能,因为您只是呈现页面。不是语法错误,会触发另一个错误。好的,请继续阅读:

  

Rails.root:/ Users / david / dev / testapp

     

应用程序跟踪|框架跟踪|完整跟踪

现在点击“框架跟踪”,您将看到:

  

activemodel(3.2.6)lib / active_model / naming.rb:163:in model_name_from_record_or_class' activemodel (3.2.6) lib/active_model/naming.rb:158:in param_key'   actionpack(3.2.6)lib / action_view / helpers / form_helper.rb:369:在`form_for'

您可能无法理解所有这一切 - 很少有人这样做 - 但您会发现model_name_from_record_or_class来自param_key的错误来自form_for。这是一个很大的线索!

我建议使用open_gem gem来轻松挖掘源代码:

gem install open_gem

现在,看看activemodel,因为它是堆栈跟踪中最顶层的gem:

gem open activemodel

现在,通过启用正则表达式搜索来搜索它:

  

def。* model_name_from_record_or_class

(为什么?你想找到类方法 - 例如以self开头的定义。)

这将带您进入naming.rb中的第162行。

def self.model_name_from_record_or_class(record_or_class)
  (record_or_class.is_a?(Class) ? record_or_class : convert_to_model(record_or_class).class).model_name
end

即使不了解所有这些,它确实提供了一个很大的提示......该方法尝试从记录或类中返回模型名称。为什么不能呢?因为您传递的参数@user尚未设置。未设置的实例变量的值为nil,因此在您尝试使用它之前不会抱怨。

我希望这有助于解决这个问题以及未来的问题。

答案 2 :(得分:6)

这个答案实际上只是修正了Someth的答案,但解决方法是为每个控制器操作设置@user,而不仅仅是与特定控制器有关的操作。这可以通过在ApplicationController中使用before_filter来完成,即

class ApplicationController < ActionController::Base
  before_filter :initialize_user

  def initialize_user
    @user = User.new
  end
end

通过在f​​orm_for帮助器本身中创建一个新模型(注意:这在关注点分离方面很难看,但它有效......)

 <%= form_for User.new do |f| %>
   <h3>Add new contact</h3>
   <%= f.text_field :first_name %><br />
   <%= f.text_field :last_name %>
   <%= f.text_field :email %>
   <hr />
   <%= f.submit "Add Contact" %>
 <% end %>

答案 3 :(得分:0)

您的问题是您尝试将表单添加到页面上的每个操作,但未在所有操作中初始化用户。尝试在所有操作中初始化用户:

class UserController < ApplicationController
    before_filter :initialize_user

    def index

    end

    def initialize_user
        @user = User.new
    end

end

答案 4 :(得分:0)

用户控制器中的

def index
   @user = User.new
end