7

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

这是 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 %>

表单未呈现,因为我的 url 是,因此它正在app/views/admin/index.html.erb 中http://localhost:3000/admin/index寻找content_foradd_user

4

5 回答 5

13

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

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

首先,查看堆栈跟踪。

用户中的 NoMethodError#index

显示 /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:inparam_key' actionpack (3.2.6) lib/action_view/helpers/form_helper.rb:369:in `form_for'

你可能不明白这一切——很少有人明白——但是你会看到错误来自model_name_from_record_or_class哪个来自param_key哪个来自哪个form_for。这是一个很大的线索!

我推荐使用open_gemgem 来方便地挖掘源代码:

gem install open_gem

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

gem open activemodel

现在,在启用正则表达式搜索的情况下进行搜索:

def .*model_name_from_record_or_class

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

这将带您到第 162 行naming.rb

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,因此在您尝试使用它做某事之前它不会抱怨。

我希望这对这个问题和未来的问题有所帮助。

于 2012-06-19T03:33:01.767 回答
13

如果表单包含在多个操作(页面)中,您需要设置@user为某些内容,否则该form_for指令将失败(它没有任何内容可以为 创建表单

一种更好的方法(也是 Rails 的默认设置)是为每个操作设置单独的视图,每个视图只包含该操作所需的元素,并application.html.erb使用<%= yield %>. 所以你会有一个app/views/users/new.html.erb包含表单的视图。你从来不需要在 Rails 中定义任何加载路径,它们都来自模型、控制器和动作名称——或者来自你的routes.rb. 这是在 Rails 中运行得如此之深的约定优于配置范式的核心部分。

编辑:如果您确实需要在每个页面上创建一个新对象的表单(例如,通常用于 UserSessions),您可以重写您的表单form_for,使其不依赖于存在的对象:

form_for(User.new)

或者如果您需要强制它发布到create方法

form_for(User.new, :url => { :action => "create" }) 

form_for您可以在Ruby On Rails API 文档中阅读有关资源驱动的更多信息。

于 2012-06-19T03:07:57.117 回答
7

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

class ApplicationController < ActionController::Base
  before_filter :initialize_user

  def initialize_user
    @user = User.new
  end
end

或者通过在 form_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 %>
于 2012-06-19T03:33:07.867 回答
0

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

class UserController < ApplicationController
    before_filter :initialize_user

    def index

    end

    def initialize_user
        @user = User.new
    end

end
于 2012-06-19T03:17:57.993 回答
0

在用户控制器中:

def index
   @user = User.new
end
于 2014-01-11T04:43:57.543 回答