Awhile ago, I implemented an "undo" and "redo" button like in this railscasts on the paper_trail gem. Everything worked great until today when the "redo" stopped working. I haven't been able to figure out why.
Here is the relevant controller action:
def revert
@version = PaperTrail::Version.find(params[:id])
if @version.reify
@version.reify.save!(:validate => false)
view_context.reify_associations(@version)
else
@version.item.destroy
end
link_name = params[:redo] == "true" ? "undo" : "redo"
link = view_context.link_to(link_name, revert_version_path(@version.next, :redo => !params[:redo]), :method => :post)
if @version.event == "create"
flash[:success] = "Undid #{@version.event}. #{link}"
redirect_to :controller => session[:controller], action: :index
else
flash[:success] = "Undid #{@version.event}. #{link}"
redirect_to :back
end
end
It fails on the line: link = view_context.link_to(link_name, revert_version_path(@version.next, :redo => !params[:redo]), :method => :post)
With an error: ActionController:UrlGenerationError
... No route matches {:action=>"revert", :controller=>"versions", :format=>nil, :id=>nil, :redo=>false} missing required keys: [:id]
.
So, obviously, I followed the error to see why the :id wasn't being passed in, but it is.
In the parameters:
{"_method"=>"post",
"authenticity_token"=>"6/B1YDXqZ62+DqMMdcYTfCTIJGaVvc1RjKmxWW2GkeQ=",
"redo"=>"true",
"id"=>"29"}
The id is clearly defined and the first line of this controller finds the corresponding version in the table based on that id.
I cannot figure out what is wrong here so any help would be greatly appreciated.
For anyone finding this later on, the issue I was having was the first statement of my conditional (@version.reify
) never returned nil. This is because I had overwritten the object attribute to add additional information to create events. To solve the problem, I simply changed the conditional to check the type of event, i.e.
if @version.event == "create"
...
end
PaperTrail's reify method looks at the object
attribute of @version
and recreates the object from the serialization. It returns nil whenever the object field is nil, otherwise it will return the object it unserialized.