无法在 Rails 中创建新模型
tl;dr:似乎params[:commit]
不包含创建新Commit的实际相关信息,而是仅包含提交按钮的值对于名称也是“commit”的表单。关于为什么会发生这种情况有什么想法吗?我没有改变任何东西。
我正在使用 webrick 服务器运行 Rails 3,因为它显示相关的调试信息。我创建了一个只有一个属性 description:text
的模型,一切似乎都工作正常。
然而,当我使用自动生成的脚手架表单创建一个新表单时,它似乎并不关心描述文本区域值。换句话说,创建后,created_at
列很好,除了 description
之外的所有列都根本不显示。这是服务器的输出:
Started POST "/commits" for 127.0.0.1 at 2010-11-03 17:24:20 -0700
Processing by CommitsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"F00A8Ttv7ceREegfZmP+T5kr+6u2YbRJrQzmfEOaT7o=", "commit"=>"Create Commit"}
SQL (0.5ms) INSERT INTO "commits" ("created_at", "description", "updated_at") VALUES ('2010-11-04 00:24:20.986571', NULL, '2010-11-04 00:24:20.986571')
Redirected to http://0.0.0.0:3000/commits/5
Completed 302 Found in 42ms
这是我的迁移的样子,由 railsgenerate
自动生成
def self.up
create_table :commits do |t|
t.text :description
t.timestamps
end
end
因此,如您所见,它将描述值视为 NULL
即使我确实在文本区域中输入了一些内容。以下是 Rails 在 _form.html.erb
部分中生成的内容:
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
有人知道为什么会发生这种情况吗?我很确定这也是显而易见的事情。
顺便说一句,当我创建一个并手动保存它时,rails console 工作正常,所以我有一种感觉,当控制器进行保存或其他操作时,控制器中会发生断开连接。
编辑:我注意到一些有趣的事情。在控制器中,对象是这样创建的:
@commit = Commit.new(params[:commit])
但是,正如上面的 webrick 输出中所指出的,服务器接收的参数只有:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"F00A8Ttv7ceREegfZmP+T5kr+6u2YbRJrQzmfEOaT7o=", "commit"=>"Create Commit"}
所以它似乎没有获取 description
参数,该参数我想应该已经包含在 commit
参数中,但是如果我查看 new
表单的源代码,它会显示描述的文本区域的名称为 commit[description]
,但提交按钮的名称为commit
。因此,不知何故,它只获取提交按钮的值,这确实具有“创建提交”的值,而不是它所需的其他信息。
不过我对 Rails 不太了解,所以我真的不知道是这种情况还是什么。
有人请帮帮我哈哈。
编辑:这是由rails生成的_form.html.erb
部分的其余部分。也许你能发现一个明显的问题:
<%= form_for(@commit) do |f| %>
<% if @commit.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@commit.errors.count, "error") %> prohibited this commit from being saved:</h2>
<ul>
<% @commit.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
答案:看来Rails 3现在自动为每个提交按钮提供一个名称“commit”,这与我的模型名称冲突。我也同样担心。我想知道使用这个名字是否有任何进一步的影响。通过将提交调用显式更改为以下内容解决了此问题:
f.submit "Button Text", :name => "something_else"
tl;dr: It seems like params[:commit]
does not contain the actual relevant information to create a new Commit, instead, it only contains the value of the submit button for the form whose name is also "commit". Any ideas as to why this is happening? I did not change anything.
I am running rails 3 with the webrick server since it displays relevant debugging information. I created a model with only one attribute, description:text
, and everything seems to be working fine.
However, when I go to create a new one using the auto-generated scaffolding form, it does not seem to care about the description text-area value. In other words, after having been created, the created_at
column is fine and all but the description
does not show up at all. Here is the output from the server:
Started POST "/commits" for 127.0.0.1 at 2010-11-03 17:24:20 -0700
Processing by CommitsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"F00A8Ttv7ceREegfZmP+T5kr+6u2YbRJrQzmfEOaT7o=", "commit"=>"Create Commit"}
SQL (0.5ms) INSERT INTO "commits" ("created_at", "description", "updated_at") VALUES ('2010-11-04 00:24:20.986571', NULL, '2010-11-04 00:24:20.986571')
Redirected to http://0.0.0.0:3000/commits/5
Completed 302 Found in 42ms
Here is what my migration looks like, auto-generated by rails generate
def self.up
create_table :commits do |t|
t.text :description
t.timestamps
end
end
So as you can see, it is seeing the description value as NULL
even though I did type something into the text area. Here is what rails generated in the _form.html.erb
partial:
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
Anyone have any ideas as to why this is happening? I'm pretty sure it's some obvious thing too.
By the way, rails console
works fine when I create one and save it manually, so I have a feeling there is a disconnect going on in the controller when it goes to save or something.
EDIT: I noticed something interesting. In the controller, the object is created as such:
@commit = Commit.new(params[:commit])
However, as noted in the webrick output above, the parameters the server receives are only:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"F00A8Ttv7ceREegfZmP+T5kr+6u2YbRJrQzmfEOaT7o=", "commit"=>"Create Commit"}
So it doesn't seem like it gets the description
parameter, which I imagine should have been wrapped in the commit
parameter, but then if I look at the source for the new
form, it shows that the description's text area is of name commit[description]
, but the submit button is of name commit
. So somehow it's getting only the value of the submit button, which is indeed of value "Create Commit", and not the other information it requires.
I don't know that much about rails though so I don't really know if this is the case or what.
Someone please help me out haha.
EDIT: Here is the rest of the _form.html.erb
partial generated by rails. Perhaps you can spot the glaring issue:
<%= form_for(@commit) do |f| %>
<% if @commit.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@commit.errors.count, "error") %> prohibited this commit from being saved:</h2>
<ul>
<% @commit.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Answer: It seems that Rails 3 now automatically gives every submit button a name of "commit", which conflicts with the name of my model. I feared as much. I'm wondering if there are any further implications on using this name. This problem was solved by explicitly changing the submit call to:
f.submit "Button Text", :name => "something_else"
默认情况下,rails 脚手架将创建一个如下所示的表单:
请注意,我已将部分内容折叠到表单本身中。重要的是要了解发生这种情况时会生成什么 HTML。它看起来像这样:
您遇到的问题是提交按钮的名称和对象的名称之间的名称冲突。通常,当rails遇到像“commit[description]”这样的表单名称时,它会将结果存储在@params中,因此值看起来像这样:
事实上,这就是rails所做的。问题是“submit_tag”表单助手生成的默认名称也被命名为“commit”。因此,当 Rails 遇到该表单参数时,它会覆盖表单的结果,如下所示:
要解决此名称冲突,您有几个选项。第一个选项是用普通的旧 HTML 手写提交按钮。当然,您会失去一些选项,但至少您可以将提交按钮的名称更改为其他名称:
另一个选项是使用“form_for”助手的变体。在这种情况下,表单的开头行将如下所示:
这会将生成的 HTML 更改为如下所示:
这会将表单数据绑定到 @params[:newcommit] 参数,并且您可以继续正常处理。
为了您的进一步阅读乐趣:
http://guides.rubyonrails.org/form_helpers.html
By default, the rails scaffolding will create a form that will look something like the following:
Please note that I have collapsed the content of the partial into the form itself. The important thing to understand is what HTML is generated when this happens. It will look like this:
The gotcha you've run into is a name collision between the submit button's name and the object's name. Normally, when rails encounters a form name like "commit[description]" it will store the results in @params so the value looks like this:
In fact, that is what rails did. The problem was that the default name generated by the "submit_tag" form helper is also named "commit". So when rails encountered that form parameter it overwrote the results of the form like this:
To get around this name collision you have a couple options. The first option is to hand write your submit button in plain old HTML. Sure you lose some of the options, but at least you can change the name of the submit button to something else:
The other option is to use a variation of the 'form_for' helper. In this case the form's opening line would look like this:
That will change the resulting HTML to look like this:
That will bind your form data to the @params[:newcommit] parameter, and you can continue processing as per normal.
For your further reading enjoyment:
http://guides.rubyonrails.org/form_helpers.html