2010-11-16 10 views
13

У меня есть задача разработать приложение для рельсов по модели маршрутизации.Динамические маршруты с Rails 3

Мне нужно иметь PageController и Page. URL страницы должны быть похожими на /contacts, /shipping, /some_page.

Также мне нужны модели CatalogController и Category. Категории URL-адреса должны быть похожими на /laptops, /smartphones/android.

И это будет ProductsController и Product модель, URLs продукции должна быть линия /laptops/toshiba_sattelite_l605, /smartphones/android/htc_magic

Я понимаю, что эта проблема может быть решена с помощью URL-адреса, как

  • /page/shipping
  • /catalog/smartphones/android

Но клиент не делает t хотите увидеть вставку «/page» или «/catalog» в URL.

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

+3

Как вы будете различать, является ли '/ something' страница или категория? – Matt

+0

Это может быть категория (/ ноутбуки), или это может быть страница (/ контакты). Из-за этого я понимаю, что для моделей категорий и страниц необходимо иметь какое-то поле, например «slug», и оно должно быть уникальным на сайте. –

+1

Это действительно плохая идея. Если они беспокоятся о том, что URL-адрес «уродливый», они могут делать что-то вроде '/ faq/contacts' или'/questions/shipping'. – jonnii

ответ

49

Вы должны написать правило "поймать всех":

На routes.rb:

get '*my_precioussss' => 'sauron#one_action_to_rule_them_all' 

Ваш драгоценный контроллер:

class SauronController < ApplicationController 
    def one_action_to_rule_them_all 
    @element = find_by_slug(params[:my_precioussss]) 
    render @element.kind # product, category, etc 
    end 
end 

Затем вы пишете один вид для каждого «вида» элемента: product.html.erb, category.html.erb и т. д.

Обязательно укажите свой find_by_slug осуществления.

Вы можете изменить one_action_to_rule_them_all на pikachu_i_choose_you и SauronController до PokemonController, также будет работать.

+13

upvoting исключительно на основе примера;) – defbyte

0

Маршруты Rails основаны исключительно на URL. Если у вас нет /pages или /categories или что-то еще до имени, то как Rails собирается определить, является ли URL-адрес http://example.com/smartphones URL-адрес страницы или категории? Если у вас нет предопределенного списка имен страниц в условиях маршрутов, он не может.

Единственный способ сделать это в этом примере - это фактически искать страницу по smartphones, и если ни один не найден, предположим, что это имя категории и поиск категории. Это невозможно сделать в маршрутах рельсов. Для этого вам понадобится один контроллер, который будет обрабатывать все эти URL-адреса и выполнять этот поиск, а затем отображать правильный шаблон (вы не можете перенаправить, так как это изменит URL-адрес). И это уродливый способ решить эту проблему.

Если бы я был вами, я бы попытался убедить клиента договориться о каком-то префиксе (например, /p_pagename) или предпочтительно о разных URL-адресах. Это может быть что-то вроде /p/shipping для страниц, и все остальные URL-адреса могут быть перенаправлены на CategoriesController или ProductsController.

+1

Я согласен с вашей позицией, но абсолютно невозможно убедить клиента согласовать какой-то префикс в URL-адресах. Его SEO нуждается в таких URL-адресах. мне нужно найти решение. –

4

Вы должны написать поймать всех

match '*page' => 'pages#show' 

затем обрабатывать путь к странице в вашей странице контроллера

def show 
    if params[:page] 
    @page = Page.find_by_page(params[:page]) 
    else 
    @page = Page.find(params[:id]) 
    end 
... 

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

match '*page' => 'pages#show', :constraints => lambda{|req| !req.env["REQUEST_URI"].include? "auth"} 

Если вы хотите имеют вложенные пути (например, «Смартфоны/андроид») вам нужно разделить: страницы параметров друг от друга и обрабатывать сегментов пути в контроллере

path = :page.split("/") // you now have an array of path segments you can use in your controller 
1

я сделал это в сочетании двух подходов

  1. использование friendly_id камень для работы с слизнями в запросах найти вместо числовых идентификаторов

  2. определяют маршруты с :constraints=>ConditionClass, который должен вернуть true или false (так маршрут будет определен или нет)

небольшой пример:

#routes.rb 
    class CategoryBrandGoodConstraint 
     def self.matches?(request) 
     path_parts = request.path.split('/') 
     Category.find(path_parts[1]).present?&&Brand.find(path_parts[2]).present?&&Good.find(path_parts[3]).present? rescue false 
     end 
    end 

    get ':category_friendly_id/:brand_friendly_id/:good_friendly_id' => 'goods#index', :constraints => CategoryBrandGoodConstraint 
    #another conditional routes with another :constraints=>ConditionClass2 definition 
    #... 
    #until you define all necessary conditional application routes 

#goods_controller.rb 

    def index 

     #operate with params[:category_friendly_id], params[:brand_friendly_id], params[:good_friendly_id] to collect all you need for view rendering 

    end 

конечно, вы можете маршрут к другому контроллер для визуализации другого вида get '/:whatever' => 'another_controller#another_action', :constraints=>ConditionClassN

надеюсь, что это поможет!

cheers

Смежные вопросы