开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜