How to define a controller function that works for instances of any model
Implementing versioning for a Rails app I'd like to have a view that开发者_C百科 displays all versions of a model with some extra functionality like reverting etc.
I use the paper_trail
gem for the versioning.
I know that I could do that by writing a controller function like versions
and a view for every model but I'd like to do it for all models at once. This should be possible because the model.versions
attribute is always structured identically.
Ideally the URL should look like /pages/testpage/versions
while testpage
is the page id.
This seems similar to the concept of nested routes in rails.
resources :pages do
resources :versions
end
The problems with nested routes however are:
- Needs extra configuration per model
- I cannot access the
testpage
object without knowing of which model it is an instance. I also wasn't able to find a way to determine the model since the only thing that is provided to my versions controller is the params hash.
I'm completely open to alternative solutions that might not follow my initial ideas.
Write it in your ApplicationController
and define it as a helper_method.
For example
class ApplicationController < ActionController::Base
helper_method :current_time
def current_time
Time.now
end
end
Now you can cal current_time
everywhere in controllers or views.
Also you can write separate Module/Class and define there your helpers methods. Than you should include this file into your ApplicationController
as well
UPD after theme is changed
I didn't think about your actual question. But I can say that your approach is nod the best here.
You should create new resource instead of creating new functionality which will hard to be tested. So create new resource (controller): versions and play around this controller.
For example how it can work:
/versions/pages/132
/versions/comments/1003
How to realize it:
match "/versions/:model/:id", :to => "versions#index"
In your controller:
class VersionsController < ActionController::Base
def index
@object = my_type.find(params[:id])
@versions = @object.versions
end
private
def my_type
params[:model].constantize
end
end
Of course you can change routes the way you want:
match "/:model/:id/versions", :to => "versions#show"
So now your pretty /pages/testpage/versions
will work fine for you without any new strange logic.
UPD 2
Imagine you have got this route:
match "/:model/:id/versions", :to => "versions#index", :as => :versions
And this objects:
@page = Page.last
@hotel = Hotel.find(123)
@comment = @page.comments.first
How will we create links for versions:
<%= link_to "Versions of this page", versions_path(:model => @page.class.to_s, :id => @page.id) %>
<%= link_to "Versions of this hotel", versions_path(:model => @hotel.class.to_s, :id => @hotel.id) %>
<%= link_to "Versions of this comment", versions_path(:model => @comment.class.to_s, :id => @comment.id) %>
I would suggest passing a param such as 'type' and stuff the model name there. Then in your controller you can do:
class VersionsController < ApplicationController
def index
model = params[:type].classify.constantize
@obj = model.find(params[:id])
end
end
For your links, you can pass queries to the link_to helper
<%= link_to versions_path(@model, :type => @model.class) %>
Or something along those lines.
精彩评论