Красивые Пути в Рельсах

У меня есть модель категории, и я маршрутизирую ее, используя стандартные леса 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.

Другие вопросы по тегам