Я закодировал себя в угол с этим нестандартным маршрутом? - PullRequest
0 голосов
/ 29 июня 2011

Я даже не знаю, как написать правильное название для этого. Я как бы собрал воедино некоторый код маршрутизации, основанный на куче разных статей, и теперь мне интересно, нарисовал ли я себя в углу.

У меня есть модель 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 голосов
/ 29 июня 2011

Вероятно, не стоит генерировать пути путем объединения строк в помощниках путей.Вместо этого просто используйте метод 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

Для ваших тестов либо включите вспомогательные методы через что-либовдоль этих строк: Мои вспомогательные методы в контроллере - или используйте метод url_for снова.

... Тем не менее - как вы и предлагали, тестирование просмотров в контроллер тесты не идеальны.:)

0 голосов
/ 29 июня 2011

Чтобы сделать news_article_path доступным, вам нужно сделать:

class MyClass
  include Rails.application.routes.url_helpers
end

Теперь будет определен MyClass # news_article_path.Вы можете попытаться включить url_helpers в ваш тестовый пример.Я недавно видел этот разрыв с ошибками «слишком большой уровень стека» (это создает бесконечную рекурсию «супер» вызовов при инициализации).Если это не работает, создайте свой собственный класс помощников вида и выполните «MyViewHelper.new.news_article_path» и т. Д.

...