任何人都可以解释更新表格的以下奇怪行为吗?
模型post.rb包含以下定义
class Post < ActiveRecord::Base
attr_accessible :id, :name, :content
validates :id, :presence => true, :numericality => { :greater_than_or_equal_to => 100}, :uniqueness => true
end
控制器posts_controller.rb以这种方式定义更新方法
class PostsController < ApplicationController
def update
@post = Post.find(params[:id])
respond_to do |format|
if @post.update_attributes(params[:post])
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
部分视图_form.rb还包含使用scaffold
生成的标准表达式<%= form_for(@post) do |f| %>
...
<div class="field">
<%= f.label :id %><br />
<%= f.number_field :id %>
</div>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
问题描述:
而不是表单接收和更新数据库,Rails抛出异常 PostsController#show
无法找到ID为42的帖子
这里发生了什么?为什么说明以及为什么再次传递旧值?
答案 0 :(得分:1)
问题是你的控制器中你正在这样做:
@post = Post.find(params[:id])
你传入的ID是42.所以控制器去试图找到ID为42的Post对象。但是,没有ID为42的Post,所以它会抛出一个错误。它甚至从未进入update_attributes
电话,甚至从未进行验证。
您必须解决此错误,或使用find_by_id
方法,如果找不到记录,将返回nil
。
另外,我想知道,为什么让你的用户手动输入ID?他们不应该知道这一点。这个ID应该与主键不同吗?考虑添加一个不同的列,如identifier
或key
或其他类似的东西,如果是这样的话,可以减少歧义。如果你试图操纵ID(实际上可以认为它可能被Rails允许),可能会遇到很多问题。
答案 1 :(得分:0)
update_attributes
方法不更新主键也不更新只读属性。更重要的是,update_attributes
在更新SQL语句中的id
条件中使用WHERE
属性,因此如果您更改了id
属性,您最终将更新已更新的记录这个ID已经存在(或者如果数据库中不存在id,则根本没有更新)。
作为一种解决方法,您要么自己编写更新SQL语句,要么通过创建具有所需id的新记录(复制旧属性并设置新ID)并删除旧记录来两次命中数据库。
那就是说,我同意@MrDanA认为更新主键不是一个好主意,我认为你应该考虑另一种解决问题的方法。