web-dev-qa-db-fra.com

Rails routes avec: nom au lieu de: id paramètres url

J'ai un contrôleur nommé 'companies' et plutôt que les URL de chaque entreprise étant désignées par un: id, j'aimerais que l'url utilise leur: name comme: url/company/Microsoft au lieu de url/company/3.

Dans mon contrôleur, je supposais que j'aurais

 def show
   @company = Company.find(params[:name])
 end

Puisqu'il n'y aura aucun autre paramètre dans l'url, j'espérais Rails comprendrait que: nom a référencé la colonne: nom dans mon modèle d'entreprise. Je suppose que la magie ici serait dans la route mais je suis coincé à ce stade.

27
dscher

params

En fin de compte, vous cherchez la mauvaise solution - les clés de hachage params sont plutôt hors de propos, vous devez être en mesure d'utiliser plus efficacement les données qu'elles contiennent.

Vos itinéraires seront construits comme:

#config/routes.rb
resources :controller #-> domain.com/controller/:id

Cela signifie que si vous demandez cet itinéraire: domain.com/controller/your_resource, les params[:id] la valeur de hachage sera your_resource (peu importe si ça s'appelle params[:name] ou params[:id])

-

friendly_id

La raison pour laquelle vous avez plusieurs réponses recommandant friendly_id est parce que cela remplace la méthode find de ActiveRecord, vous permettant d'utiliser un slug dans votre requête:

#app/models/model.rb
Class Model < ActiveRecord::Base
  extend FriendlyId
  friendly_id :name, use: [:slugged, :finders]
end

Cela vous permet de faire ceci:

#app/controllers/your_controller.rb
def show
    @model = Model.find params[:id] #-> this can be the "name" of your record, or "id"
end
12
Richard Peck

Bonne réponse avec Rails 4.0+:

resources :companies, param: :name

vous pouvez éventuellement utiliser only: ou except: liste pour spécifier les itinéraires

et si vous voulez construire une URL, vous pouvez remplacer ActiveRecord :: Base # to_param d'un modèle associé:

class Video < ApplicationRecord
  def to_param
    identifier
  end

  # or
  alias_method :to_param, :identifier
end

video = Video.find_by(identifier: "Roman-Holiday")
edit_videos_path(video) # => "/videos/Roman-Holiday"
69
Matrix

Honnêtement, je voudrais juste écraser le to_param dans le Modèle. Cela permettra à company_path les aides pour fonctionner correctement.

Remarque: je créerais une colonne de slug distincte pour le nom complexe, mais ce n'est que moi. C'est le cas simple.

class Company < ActiveRecord::Base
  def to_param
    name
  end
end

Modifiez ensuite mes itinéraires param pour plus de lisibilité.

# The param option may only be in Rails 4+,
# if so just use params[:id] in the controller
resources :companies, param: :name

Enfin dans mon Controller je dois le chercher dans le bon sens.

class CompaniesController < ApplicationController
  def show
    # Rails 4.0+
    @company = Company.find_by(name: params[:name])
    # Rails < 4.0
    @company = Company.find_by_name(params[:name])
  end
end
11
Azolo

Je recommande d'utiliser le friendly_id à cet effet. Veuillez noter qu'il existe des différences entre friendly_id 4 et 5. Dans friendly_id 4, vous pouvez utiliser comme ceci

 @company = Company.find(params[:id])

Cependant, vous ne pourrez pas faire cela dans friendly_id 5, vous devez utiliser:

 @company = Company.friendly.find(params[:id])

Dans le cas où vous ne souhaitez pas utiliser les paramètres [: id] mais les paramètres [: nom], vous devez remplacer l'itinéraire dans routes.rb. Par exemple

 get '/companies/:name', to: "companies#show"

J'espère que ces informations vous seront utiles

6
The Lazy Log

Il n'y a en fait pas de magie pour l'implémenter, vous devez soit le construire vous-même en implémentant correctement to_param sur votre modèle (non recommandé) ou en utilisant l'un des joyaux disponibles pour cela comme:

J'utilise friendly_id et il fait bien le travail.

5
Maurício Linhares

Model.find (primary_key)
Le paramètre par défaut ici est l'identifiant de la clé primaire. Si vous souhaitez utiliser d'autres colonnes, vous devez utiliser Model.find_by_xxx donc ici cela pourrait être

def show
  @company = Company.find_by_name(params[:name])
end
2
brick