我有一个表单,我想出现在每个页面的顶部,所以我把它包含在/app/views/layouts/application.html.erb 文件中,我在尝试加载页面时收到错误 undefined method
model_name' for NilClass:Class'。
这是应用程序中的表单片段.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 的建议,在我的应用程序/视图/布局/应用程序.html.erb 文件中,我有这样的东西:
<div>
<%= yield :add_user %>
</div>
在我的应用程序/视图/用户/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 http://localhost:3000/admin/index
,所以它在 app/views/admin/index.html.erb 中查找add_user
content_for
如果表单包含多个操作(页面),则需要将@user
设置为某些内容,否则 form_for
指令将失败(它不会有任何要为其创建表单的内容)。
更好的方法(和 Rails 默认值)是为每个操作提供单独的视图,每个视图仅包含该操作所需的元素,并使用 <%= yield %>
加载到您的application.html.erb
布局中。因此,您将有一个包含表单的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" })
您可以在 Ruby On Rails API 文档中阅读有关资源驱动form_for
的更多信息。
您是否先尝试调试?我问是因为你说你是Rails的新手。如果没有,这是我的方法。我想分享它,因为我很惊讶有多少人(无论出于何种原因)不仔细调试。
(我创建了一个测试应用程序,以便我可以解决您的问题。首先,我访问了http://localhost:3000/users
。
首先,查看堆栈跟踪。
用户中的无方法错误#索引
显示/Users/david/dev/testapp/app/app/views/layouts/application.html.erb 其中行 #11 提出:
未定义的方法"model_name"用于 NilClass:Class 提取的源(围绕第 #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/nameing.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:in 'form_for'
你可能不明白这一切——很少有人理解——但你会看到错误来自model_name_from_record_or_class
来自param_key
来自form_for
。这是一个很大的线索!
我建议使用 open_gem
gem 来轻松挖掘源代码:
gem install open_gem
现在,看一下 activemodel,因为它是堆栈跟踪中最顶层的 gem:
gem open activemodel
现在,在启用正则表达式搜索的情况下搜索它:
定义 .*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,因此在您尝试对其进行处理之前,它不会抱怨。
我希望这对这个问题和未来的问题有所帮助。
这个答案实际上只是Someth的答案得到纠正,但解决方案是为每个控制器操作设置@user
,而不仅仅是与特定控制器相关的操作。这可以通过使用应用程序控制器中的before_filter
来完成,即
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 %>
您的问题是您正在尝试向页面上的每个操作添加表单,但没有在所有操作中初始化用户。 尝试在所有操作中初始化用户:
class UserController < ApplicationController
before_filter :initialize_user
def index
end
def initialize_user
@user = User.new
end
end
用户控制器中的
def index
@user = User.new
end