Измените имя параметра: id в ресурсах маршрутизации для Rails

108

Я посмотрел, как изменить слот динамических параметров, и нашел этот пост, который делает именно то, что нужно. Сообщение: https://oughttbot.com/blog/rails-patch-change-the-name-of-the-id-parameter-in.

В основном, что он делает, если следующие маршруты:

map.resources :clients, :key => :client_name do |client|
  client.resources :sites, :key => :name do |site|
    site.resources :articles, :key => :title
  end
end

Эти маршруты создают следующие пути:

/clients/:client_name
/clients/:client_name/sites/:name
/clients/:client_name/sites/:site_name/articles/:title

Одно из решений - переопределить def to_paramметод в модели, но я хочу, чтобы это не касалось самой модели.

Но поскольку это для Rails 2.x, как я могу добиться того же для Rails 3?

Обновить

Это приложение использует Mongoid. Не AR. Таким образом, дружественный драгоценный камень не может быть использован afaik.

Самоучка
источник

Ответы:

192

Рельсы 4 и 5

В Rails 4 :paramбыла добавлена ​​опция, которая, кажется, делает именно то, что вы ищете. Вы можете сравнить код Rails 3 с кодом Rails 4 .

подробности

Вы можете легко реализовать это в своем routes.rbфайле:

# config/routes.rb

resources :posts, param: :slug

# app/controllers/posts_controller.rb

# ...
@post = Post.find_by(slug: params[:slug])
# ...

Начиная с выпуска Rails 4, эта функциональность задокументирована в руководствах по Rails .

Рельсы 3

К сожалению, в Rails 3 :keyопция for resourcesбыла удалена, поэтому вы больше не можете легко изменить имя для маршрутов, созданных таким образом, просто передав дополнительную опцию.

подробности

Я предполагаю, что вы уже каким-то образом добились того, чтобы приложение работало так, как вы хотите, в прошлом году, но я постараюсь получить эффект, который вы описали в Rails 3, в routes.rb. Это просто потребует немного больше работы, чем to_paramметод. Вы все еще можете определить пользовательские параметры маршрутов определяются с использованием scopeи match(или его кузенов get, put, post, и delete). Вы просто пишете имя параметра, которое хотите в сопоставлении:

get 'clients/:client_name', :to => 'clients#show', :as => client

scope 'clients/:client_name' do
  get 'sites/:name', :to => 'sites#show', :as => site
end

Вам придется вручную добавить все маршруты, которые resourcesавтоматически создаются для вас, но это даст вам то, что вы ищете. Вы также можете эффективно использовать :controllerопцию scopeи дополнительные scopeблоки, чтобы убрать часть повторения.


РЕДАКТИРОВАТЬ (8 мая 2014 г.): сделайте более очевидным ответ, содержащий информацию как для Rails 3, так и для Rails 4. Обновите ссылки на код, чтобы перейти к точным номерам строк и фиксации, чтобы они работали в течение более длительного периода времени.

РЕДАКТИРОВАТЬ (16 ноября 2014 г.): Rails 4 теперь должен быть наверху и включать соответствующую информацию, поскольку это была текущая версия Rails в течение некоторого времени.

РЕДАКТИРОВАТЬ (9 августа 2016 г.): подумайте о том, что решение все еще работает в Rails 5, и обновите устаревшие ссылки.

Джошепворт
источник
1
В общем, Rails3 создал параметр ресурсов в маршрутизаторе, чтобы он был полностью заполнен, но его нужно переопределить, чтобы иметь собственные имена переменных ... Кажется, что это неуместно!
Августин Ридингер
1
Вот бэкпортparam варианта для рельсов 3: gist.github.com/sj26/44ef47fe8b98b46ee32d
sj26
Это приводит к поломке помощников URL. Они заканчивают генерацию обычного маршрута на основе идентификатора, если я передаю объект или жалуюсь на отсутствующий ключ [: slug], если я передаю слаг. Есть идеи, как исправить?
RonLugge
9
К вашему сведению, если вы используете вложенные ресурсы, параметр для родительского ресурса будет иметь значение post_slug, что может сбивать с толку.
ghayes
4
Это действительно хорошо, но что я могу сделать, если мне не нужно имя параметра родительского идентификатора, например post_post_id для вложенного ресурса?
Asnad Atta 05
45

в Rails 4 передайте параметр param, чтобы изменить параметры: id. Например resources :photos, param: :photo_name, сгенерирует / photos /: имя_фото

bobzsj87
источник
1

Если я правильно вас понял, вы хотите, client_nameчтобы idв вашем URL-адресе был вместо , верно?

Вы можете сделать это, переопределив to_paramметод в своей модели. Вы можете получить больше информации здесь .

Мохит Джайн
источник
1
Как я уже упоминал, у меня есть ограничение - не менять модель. Вышеупомянутый пример не поддерживается или не рекомендуется в Rails 3?
Autodidact
1

Для этого есть драгоценный камень, как и драгоценный камень для всего;)

Я использовал FriendlyId для такого поведения в rails 3.

Однако вам потребуется добавить код в вашу модель, например:

class Client < ActiveRecord::Base
  has_friendly_id :name
end

... и если у ваших клиентов нет имен, совместимых с URI, вы можете использовать для этого slug, с которым вы можете справиться has_friendly_id :name, :use_slug => true. Однако при использовании ярлыков вам, очевидно, также необходимо сохранить их в базе данных.

И, как уже упоминалось, вы все еще можете использовать to_paramтрюк с rails 3, как описано здесь . Я считаю FriendlyId более универсальным.

Мороз
источник
Мне нравится дружелюбный идентификатор, и я использовал его во многих проектах. На самом деле мое приложение использует Mongoid. Friendly_id не поддерживает это afaik. И, как я уже упоминал, мое ограничение - не менять модель.
Autodidact
1
Если вы используете mongoid, для достижения этой функции есть mongoid-slug . Он действительно использует to_param, но в фоновом режиме делает и другие умные вещи. Я нашел ссылку здесь: stackoverflow.com/questions/4744446/…
Frost
Мне понравилась эта жемчужина. Есть еще один похожий слугоид . Но, как я уже говорил, у меня есть ограничение не изменять модель. Это to_paramломает мою интерфейсную часть приложения. На самом деле я отчаянно ищу подход к маршрутизации - мне нужно изменить свой API, но не нарушая часть модели и внешнего интерфейса приложения. Почему я не могу просто изменить маршруты только так, как я сказал, и пример сообщения для более старой версии рельсов выше ???
Autodidact
Вы пытались переписать свои контроллеры, чтобы они использовали ваши собственные ключи маршрута? Например @client = Client.find(:name => param[:client_name]в ClientsController#show? Это может сработать.
Frost
Client.where(:name => param[:client_name]).first, то есть.
Frost
0

В Rails 3 вы можете переименовать ключи id, используя такую ​​комбинацию пространств имен и областей видимости (хотя и не очень хорошо):

namespace :clients do
  scope "/:client_name" do
    namespace :sites do
      scope "/:name" do
         post "/:title" => "articles#create"
         ...
      end
    end
  end
end
Доминик Гольтерманн
источник