Проверка отсутствия перекрытия маршрутов при создании новых ресурсов в Ruby on Rails

StackOverflow https://stackoverflow.com/questions/1122759

Вопрос

У меня есть RESTful настройка маршрутов в приложении Rails с использованием текстовых постоянных ссылок в качестве идентификатора ресурсов.

Кроме того, существует также несколько специальных именованных маршрутов, которые перекрываются с именованным ресурсом, например:

# bunch of special URLs for one off views to be exposed, not RESTful
map.connect '/products/specials', :controller => 'products', :action => 'specials'
map.connect '/products/new-in-stock', :controller => 'products', :action => 'new_in_stock'

# the real resource where the products are exposed at
map.resources :products

В Product модель использует постоянная ссылка_fu чтобы сгенерировать постоянные ссылки на основе имени, и ProductsController выполняет поиск по полю постоянной ссылки при доступе.Все это прекрасно работает.

Однако при создании нового Product записи в базе данных, я хочу проверить, что сгенерированная постоянная ссылка выполняет не перекрывается специальным URL-адресом.

Если пользователь пытается создать продукт с именем specials или new-in-stock или даже обычный метод Rails RESTful resource, такой как new или edit, Я хочу, чтобы контроллер просматривал конфигурацию маршрутизации, устанавливал ошибки для объекта модели, не выполнял проверку для новой записи и не сохранял ее.

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

(названия контроллера и модели изменены, чтобы защитить невинных и упростить ответ, фактическая настройка сложнее, чем в этом примере)

Это было полезно?

Решение

Что ж, это работает, но я не уверен, насколько это красиво.Основная проблема заключается в смешивании логики контроллера / маршрутизации с моделью.В принципе, вы можете добавить пользовательскую проверку к модели, чтобы проверить ее.При этом используются недокументированные методы маршрутизации, поэтому я не уверен, насколько стабильно это будет происходить в дальнейшем.У кого-нибудь есть идеи получше?

class Product < ActiveRecord::Base
  #... other logic and stuff here...

  validate :generated_permalink_is_not_reserved

  def generated_permalink_is_not_reserved
    create_unique_permalink # permalink_fu method to set up permalink
    #TODO feels really ugly having controller/routing logic in the model. Maybe extract this out and inject it somehow so the model doesn't depend on routing
    unless ActionController::Routing::Routes.recognize_path("/products/#{permalink}", :method => :get) == {:controller => 'products', :id => permalink, :action => 'show'}
      errors.add(:name, "is reserved")
    end
  end
end

Другие советы

Вы можете использовать маршрут, который в противном случае не существовал бы.Таким образом, не будет иметь никакого значения, выберет кто-то зарезервированное слово для заголовка или нет.

map.product_view '/product_view/:permalink', :controller => 'products', :action => 'view'

И в ваших взглядах:

product_view_path(:permalink => @product.permalink)

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top