我是否已使用此自定义路线将自己编入角落?

时间:2011-06-28 20:38:22

标签: ruby-on-rails-3 unit-testing rspec2

我甚至不知道如何为此写一个合适的标题。我基于一堆不同的文章拼凑了一些路由代码,现在我想知道我是否已经把自己画成了一个角落。

我有一个NewsArticle模型,我希望链接看起来像这样:

/news                          # List of all articles
/news/2011                     # List of articles published this year
/news/2011/06                  # List of articles published this month
/news/2011/06/28               # List of articles published on this day
/news/2011/06/28/my-post-title # Actual article

好的,已经违背了Rails方式,但也是如此。

我的路线设置如下:

controller :news_articles, :via => [:get] do
  match '/news(/:year/(/:month(/:day)))' => :index, :constraints => { :year => /\d{4}/, :month => /\d{2}/, :day => /\d{2}/ }
  match '/news/:year/:month/:day/:id'    => :show
end

请注意,没有:as声明。那是因为当我添加:as => "news_archive"之类的东西时,我最终会得到news_archive_path,这会返回像“/ news?year = 2010& month = 4”这样的愚蠢内容。所以,我排除了那个位并在我的应用程序帮助文件中编写了自己的路径方法:

def news_archive_path(year = nil, month = nil, day = nil)
  return "/news" if year.nil?
  t = Time.zone.local(year.to_i, month.nil? ? nil : month.to_i, day.nil? ? nil : day.to_i)
  if month.nil?
    "/news/#{t.year}"
  elsif day.nil?
    "/news/#{t.year}/#{"%02d" % t.month}"
  else
    "/news/#{t.year}/#{"%02d" % t.month}/#{"%02d" % t.day}"
  end
end

def news_article_path(article)
  t = article.published_at.in_time_zone
  "#{news_archive_path(t.year, t.month, t.day)}/#{article.friendly_id}"
end

太好了,这一切都在实践中有效。但是现在我遇到了一个问题,我正在测试我的控制器,我想确保在渲染的模板上出现正确的链接。 (哦,是的,我没有保持单独的视图测试,而是在我的控制器测试中使用render_views。)但测试失败,错误undefined method news_article_path'为#`。

那么,我是否只是接近这一切并将自己画成一个角落?或者我可以通过某种方式在控制器测试中包含辅助方法来解决这个问题?或者,为了让测试通过并对链接进行硬编码,我是否只是将其吸收?我希望它们能够实现?

2 个答案:

答案 0 :(得分:0)

要使news_article_path可用,您需要执行以下操作:

class MyClass
  include Rails.application.routes.url_helpers
end

现在将定义MyClass#news_article_path。您可以尝试将url_helpers包含到测试用例中。我最近看到了“堆栈级太深”的错误(它在初始化时创建了“超级”调用的无限递归)。如果它不起作用,请创建自己的视图助手类并执行“MyViewHelper.new.news_article_path”等。

答案 1 :(得分:0)

通过在路径助手中连接字符串来生成路径可能不是一个好主意。相反,只需使用url_for()方法即可。例如:

def news_article_path(article, options = {})
   url_for(options.merge(:controller => :articles, 
     :action => :show, 
     :id => article.id, 
     :year => article.year, 
     :month => article.month, 
     :day => article.day))
end

(假设日,月,年作为模型的快速方法添加,例如:

def year
   self.published_at.in_time_zone.year
end

对于您的测试,可以通过以下方式包含帮助方法:My helper methods in controller - 或者再次使用url_for方法。

...那就是说 - 如你所说,在控制器测试中测试视图并不理想。 :)