Find_by_id vs. find in postback action

I’m playing around with the Postback action recipe listed in the recipes
book.
Here is the default code given:

def edit
@recipe = Recipe.find_by_id(params[:id]) || Recipe.new
if request.post?
@recipe.attributes = params[:recipe]
redirect_to :main_url and return if @recipe.save
end
end

Here is what my code sort of ended up looking like, altho i’ve ripped it
apart so many times now trying to figure it out:

def edit
begin
@entry = Entry.find(params[:id])
rescue
@entry = Entry.new
end

causes a weird error where on the second time in, with no params

passed in it still loads the previous entry object saved.

@entry = Entry.find_by_id(params[:id]) || Entry.new

logger.debug “!!! edit: #{@entry.inspect}”

if request.post?
  @entry.attributes = params[:entry]
  # pulled this out so i can inspect it
  entrysaved = @entry.save
  logger.debug "on save: #{@entry.inspect}"
  redirect_to :action => "index" and return if entrysaved
end

end

I get some interesting results tho.

So, the first time i click the href (simple href to :action => “edit”)
the edit form pops up (blank), i type in the values and submit.

My page redirects and then loads the index page which shows me my entry
that i just saved.

All good so far.

Now i click the same href (no params attached or anything) and the form
pops back up, but this time its prefilled.
When i look at my inspect above, it looks like it loaded the last entry
saved. However if i inspect the params[:id] that shows nil.

The weirdest thing is that if i do
Entry.find_by_id(nil) in place of Entry.find_by_id(params[:id]) it still
loads the last entry saved. They have different addresses, so its not
the same object that was created and then passed around a session or
something.

So to top it off I tried using just what you see above, a
Entry.find(params[:id]) and did my error trapping around it.

That works. The old saved entry is never pulled back up.

So what in the world am I missing. Is there some ‘magic’ in rails that
is supposed to be a shortcut or am I just missing something in the code?
I can’t believe that it would be a bug, that would be caught immediately
by the team I’m sure.

Some System details:
Mac OSX 10.4.6
Ruby 1.8.4
Rails 1.1.2
Mysql 4.1.18

thx,
k

no ideas? :frowning:

ken brooks wrote:

causes a weird error where on the second time in, with no params

passed in it still loads the previous entry object saved.

@entry = Entry.find_by_id(params[:id]) || Entry.new

logger.debug “!!! edit: #{@entry.inspect}”

if request.post?
  @entry.attributes = params[:entry]
  # pulled this out so i can inspect it
  entrysaved = @entry.save
  logger.debug "on save: #{@entry.inspect}"
  redirect_to :action => "index" and return if entrysaved
end

end

…snip

So what in the world am I missing. Is there some ‘magic’ in rails that
is supposed to be a shortcut or am I just missing something in the code?
I can’t believe that it would be a bug, that would be caught immediately
by the team I’m sure.

Ken Brooks wrote:

@recipe = Recipe.find_by_id(params[:id]) || Recipe.new

causes a weird error where on the second time in, with no params

passed in it still loads the previous entry object saved.

Unfortunately, the “magic” is in MySQL. Although I wouldn’t exactly call
it magic. The explanation may be found here:
http://dev.mysql.com/doc/refman/5.0/en/myodbc-usagenotes-functionality.html.
In a nutshell, MySQL is “helping” you by replacing NULL with last
generated ID. And as I found out, it does that even if last ID was
generated for some other table.

My workaround for this situation was to prepend "params[:id] && " as
follows:

@recipe = params[:id] && Recipe.find_by_id(params[:id]) || Recipe.new

Or, if you do not want to treat invalid ID’s as “new”, you may do this:

@recipe = params[:id] ? Recipe.find(params[:id]) : Recipe.new

Regards,
Fyodor Golos

Ahhhh, I got bitten by this last week and couldn’t for the life of me
figure
out what was going on!! I fixed it in the same way you described, but
didn’t
know why it worked :).

If you ask me, that’s really weird default behaviour on the part of
mysql.

-Jonathan.