Красивые Пути в Рельсах
У меня есть модель категории, и я маршрутизирую ее, используя стандартные леса resources :categories
, Мне интересно, есть ли способ изменить пути от /category/:id
в /category/:name
, Я добавил:
match "/categories/:name" => "categories#show"
выше линии ресурсов в routes.rb
и изменил show
действие в контроллере:
@category = Category.find_by_name(params[:name])
это работает, но "магические пути", такие как link_to some_category
по-прежнему использовать :id
формат.
Есть ли способ сделать это? Если это плохая идея (из-за возможного способа внутренней работы рельсов), есть ли другой способ сделать это? Чтобы /categories/music
например, и /categories/3
оба работают?
3 ответа
В Rails есть отличный метод экземпляра модели, который называется to_param
и это то, что используют пути. По умолчанию id
, но вы можете переопределить его и создать что-то вроде:
class Category < ActiveRecord::Base
def to_param
name
end
end
cat = Category.find_by_name('music')
category_path(cat) # => "/categories/music"
Для получения дополнительной информации проверьте документацию Rails для to_param.
РЕДАКТИРОВАТЬ:
Когда дело доходит до названий категорий, которые не идеальны для URL, у вас есть несколько вариантов. Один, как вы говорите, gsub
пробелы с дефисами и наоборот при поиске записи. Однако более безопасным вариантом будет создание еще одного столбца в таблице категорий с именем name_param
(или похожие). Затем вы можете использовать его вместо имени для всего бизнеса, связанного с путями и URL. Использовать parameterize
Инфлектор для создания URL-безопасной строки. Вот как я это сделаю:
class Category < ActiveRecord::Base
after_save :create_name_param
def to_param
name_param
end
private
def create_name_param
self.name_param = name.parameterize
end
end
# Hypothetical
cat = Category.create(:name => 'My. Kewl. Category!!!')
category_path(cat) # => "/categories/my-kewl-category"
# Controller
@category = Category.find_by_name_param(param[:id]) # <Category id: 123, name: 'My. Kewl. Category!!!'>
Если вы не хотите нарушать существующий код, основанный на идентификаторе модели, вы можете определить ваш to_param следующим образом:
def to_param
"#{id}-#{name}"
end
поэтому ваш URL будет: http://path/1-some-model и вы все равно сможете загрузить свою модель с помощью Model.find(params[:id]), потому что:
"123-hello-world".to_i => 123
Хотя, возможно, больше, чем вам нужно, вы также можете обратиться к поддержке "удобочитаемых URL-адресов", например friendly_id или другим (например, если вам нужна поддержка юникода и т. Д.), Которые описаны здесь на Ruby Toolbox.