How to have a gem controller handle multiple arbitrary models?
I have four models that I allow commenting on by four separate comment controllers. Those four comment controllers do essentially the same thing and vary only slightly.
In an attempt to remove duplication of the four commenting controllers which are essentially all the same, I've created a Rails Engine as a gem to arbitrarily handle commenting on any arbitrary model that I specify in the routes.rb.
So in my routes.rb file I can now use:
comments_on :articles, :by => :users
with comments_on implemented as follows in my gem:
def comments_on(*resources)
options = resources.extract_options!
[snip of some validation code]
topic_model = resources.first.to_s
user_model = options[:by].to_s
# Insert a nested route
Rails.application.routes.draw do
resources topic_model do
resources "comments"
end
end
end
The routes show up in 'rake routes' and requests correctly get routed to my gem's 'CommentsController' but that's where my gem's functionality ends.
What is the best way detect the context in my gem CommentsController so I can process requests specific to how comments_on was called?
More specifically, how would I implement an index action like the following, having it context aware?
def index
@article = Article.find(params[:article_id])
@comments = ArticleComment.find(:all, :conditio开发者_开发问答ns => { :article_id => @article.id })
end
Thanks for the help!
You could specify the topic as an extra parameter in your routes:
Rails.application.routes.draw do
resources topic_model do
resources "comments", :topic_model => topic_model.to_s
end
end
Then your controller could be written like this:
def index
@topic = topic
@comments = topic.comments
end
protected
def topic
m = params[:topic_model]
Kernel.const_get(m).find(params["#{m.underscore}_id"])
end
You could move a lot of the logic out of the controller and into the model as well. topic.comments
could be a named scope that all of these models should implement.
I've done similar patterns in the past and there's usually an edge-case that breaks this idea down and you end up doing more 'meta' programming than is wise.
I'd recommend making a base controller, then making simplistic controllers that inherit from that, or try to split these common behaviors into modules.
精彩评论