如何让gem控制器处理多个任意模型?

时间:2011-06-06 19:51:37

标签: ruby ruby-on-rails-3 metaprogramming gem

我有四个模型,我允许通过四个独立的评论控制器进行评论。这四个评论控制器基本上做同样的事情,并且只是略有不同。

为了删除基本上完全相同的四个注释控制器的重复,我创建了一个Rails引擎作为gem来随意处理对我在routes.rb中指定的任意模型的注释。

所以在我的routes.rb文件中我现在可以使用:

comments_on :articles, :by => :users

在我的gem中使用comments_on实现如下:

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

路线显示在'rake routes'中,请求被正确地路由到我的gem的'CommentsController',但这就是我的gem的功能结束。

检测我的gem CommentsController中的上下文的最佳方法是什么,以便我可以处理特定于comments_on被调用的请求?

更具体地说,我如何实现类似下面的索引操作,让它具有上下文感知功能?

def index
  @article = Article.find(params[:article_id])
  @comments = ArticleComment.find(:all, :conditions => { :article_id => @article.id })
end

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

您可以将主题指定为路线中的额外参数:

Rails.application.routes.draw do
  resources topic_model do
    resources "comments", :topic_model => topic_model.to_s
  end
end

然后您的控制器可以这样写:

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

您可以将许多逻辑移出控制器并进入模型。 topic.comments可以是所有这些模型都应该实现的命名范围。

我过去做过类似的模式,通常会有一个边缘情况会打破这个想法,你最终会做更多的“元”编程而不是明智的。

我建议制作一个基本控制器,然后制作从中继承的简单控制器,或尝试将这些常见行为拆分为模块。