Reputation: 7719
can anybody explain the following strange behaviour of update form ?
the model post.rb contains following definition
class Post < ActiveRecord::Base
attr_accessible :id, :name, :content
validates :id, :presence => true, :numericality => { :greater_than_or_equal_to => 100}, :uniqueness => true
end
the controller posts_controller.rb defines the update method this way
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
the partial view _form.rb also contains standard expressions generated with 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 %>
Issue description:
instead of form reception and updating the database, Rails throw an exception ActiveRecord::RecordNotFound in PostsController#show
Couldn't find Post with id=42
What's going on here ? Why the expception and why the old value is passed again ?
Upvotes: 0
Views: 528
Reputation: 6213
update_attributes
method doesn't update primary keys nor read-only attributes. Even more, update_attributes
uses id
attribute in the WHERE
condition in the update SQL statement, so if you changed the id
attribute you'll end up updating a record which has this ID already (or no update at all if the id doesn't exist in the db).
As a workaround, you'll either have to write your update SQL statement yourself, or hit the database twice by creating a new record with the desired id (copying the old attributes and setting a new id) and deleting the old one.
That said, I agree with @MrDanA that updating primary keys is not a very good idea and I think you should think about another approach to your issue.
Upvotes: 0
Reputation: 11647
Well the problem is that in your controller you are doing this:
@post = Post.find(params[:id])
And you are passing in an ID of 42. So the controller goes and tries to find a Post object with an ID of 42. However, there is no Post with an ID of 42, so it throws an error. It never even gets to your update_attributes
call, and never even goes to your validation.
You must either rescue from this error, or use the find_by_id
method which will return nil
if no record is found.
In addition though, I'm wondering, why are you letting your users enter in an ID by hand? They shouldn't know about that. Is this ID supposed to be different than a primary key? Consider adding a different column then, like identifier
or key
or something to make it less ambiguous if that's the case. Could run in to a lot of issues if you're trying to manipulate ID (which actually come to think of it may be allowed by Rails).
Upvotes: 1