Ändern Sie den Namen des Parameters: id in Routing-Ressourcen für Rails

106

Ich habe mich umgesehen, wie man den dynamischen Parameter-Slot ändert, und diesen Beitrag gefunden, der genau das tut. Der Beitrag lautet https://thoughtbot.com/blog/rails-patch-change-the-name-of-the-id-parameter-in

Grundsätzlich funktioniert es, wenn folgende Routen verwendet werden:

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

Diese Routen erstellen die folgenden Pfade:

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

Eine Lösung besteht darin, die def to_paramMethode im Modell zu überschreiben , aber ich möchte dies, ohne das Modell selbst zu berühren.

Aber wie kann ich dasselbe für Rails 3 erreichen, da es für Rails 2.x ist?

Aktualisieren

Diese App verwendet Mongoid. Nicht AR. Daher kann der Edelstein freundlich nicht afaik verwendet werden.

Autodidakt
quelle

Antworten:

191

Schienen 4 & 5

In Rails 4 wurde die :paramOption hinzugefügt, die genau das zu tun scheint, wonach Sie suchen. Sie können sich den Rails 3-Code im Vergleich zum Rails 4-Code ansehen .

Einzelheiten

Sie können dies einfach in Ihre routes.rbDatei implementieren :

# config/routes.rb

resources :posts, param: :slug

# app/controllers/posts_controller.rb

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

Ab der Veröffentlichung von Rails 4 ist diese Funktionalität in den Rails-Handbüchern dokumentiert .

Schienen 3

Leider ist in Rails 3 die :keyOption fürresources entfernt, sodass Sie den Namen für auf diese Weise erstellte Routen nicht mehr einfach ändern können, indem Sie einfach eine zusätzliche Option übergeben.

Einzelheiten

Ich gehe davon aus, dass Sie die Anwendung im letzten Jahr bereits irgendwie so zum Laufen gebracht haben, wie Sie es möchten, aber ich werde einen Weg gehen, um den in Rails 3 beschriebenen Effekt zu erzielen routes.rb. Es wird nur ein bisschen mehr Arbeit als die to_paramMethode erfordern. Sie können immer noch benutzerdefinierte Parameter in Routen definieren definiert mit scopeund match(oder Vettern get, put, post, unddelete ). Sie schreiben einfach den gewünschten Parameternamen in den Matcher:

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

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

Sie müssten alle Routen, die resourcesautomatisch für Sie erstellt werden, manuell hinzufügen , aber es würde das erreichen, wonach Sie suchen. Sie können die :controllerOption mit scopeund zusätzliche scopeBlöcke auch effektiv verwenden , um einen Teil der Wiederholung zu entfernen.


BEARBEITEN (8. Mai 2014): Machen Sie deutlicher, dass die Antwort Informationen für Rails 3 und 4 enthält. Aktualisieren Sie die Links zum Code, um genaue Zeilennummern und Commits zu erhalten, damit sie über einen längeren Zeitraum funktionieren.

BEARBEITEN (16. November 2014): Rails 4 sollte jetzt ganz oben stehen und relevante Informationen enthalten, da es sich seit einiger Zeit um die aktuelle Version von Rails handelt.

BEARBEITEN (9. August 2016): Beachten Sie, dass die Lösung in Rails 5 noch funktioniert, und aktualisieren Sie veraltete Links.

Joshpworth
quelle
1
Im Grunde genommen hat Rails3 die Ressourcenoption im Router so erstellt, dass sie vollständig ist, muss jedoch überschrieben werden, um benutzerdefinierte Variablennamen zu erhalten ... Fühlt sich lahm an!
Augustin Riedinger
1
Hier ist ein Backport der paramOption für Schienen 3: gist.github.com/sj26/44ef47fe8b98b46ee32d
sj26
Dies führt dazu, dass die URL-Helfer kaputt gehen. Sie generieren eine normale ID-basierte Route, wenn ich ein Objekt übergebe oder mich über einen fehlenden [: slug] -Schlüssel beschwere, wenn ich den Slug übergebe. Irgendwelche Ideen zur Behebung?
RonLugge
9
Zu Ihrer Information: Wenn Sie verschachtelte Ressourcen verwenden, lautet der Parameter für die übergeordnete Ressource post_slug, was verwirrend sein kann.
Ghayes
4
Das ist wirklich gut, aber was kann ich tun, wenn ich keinen Parameternamen der übergeordneten ID wie post_post_id für verschachtelte Ressourcen haben möchte?
Asnad Atta
45

Übergeben Sie in Rails 4 die Option param, um die Parameter: id zu ändern. Zum Beispiel resources :photos, param: :photo_namewird / photos /: photo_name generiert

bobzsj87
quelle
1

Wenn ich dich richtig verstehe, willst du das client_namestatt idin deiner URL haben, oder?

Sie können dies tun, indem Sie die to_paramMethode in Ihrem Modell überschreiben . Weitere Informationen erhalten Sie hier .

Mohit Jain
quelle
1
Wie ich bereits erwähnt habe, habe ich die Einschränkung, das Modell nicht zu ändern. Wird das oben genannte Beispiel in Rails 3 nicht unterstützt oder veraltet?
Autodidakt
1

Dafür gibt es ein Juwel, genauso wie es für alles ein Juwel gibt;)

Ich habe FriendlyId für diese Art von Verhalten in Rails 3 verwendet.

Dazu müssen Sie Ihrem Modell jedoch Code hinzufügen:

class Client < ActiveRecord::Base
  has_friendly_id :name
end

... und wenn Ihre Clients keine URI-kompatiblen Namen haben, möchten Sie möglicherweise einen Slug dafür verwenden, mit dem Sie arbeiten können has_friendly_id :name, :use_slug => true. Wenn Sie Slugs verwenden, müssen Sie diese natürlich auch in der Datenbank speichern.

Und wie bereits erwähnt, können Sie den to_paramTrick mit Schienen 3 weiterhin verwenden, wie hier dokumentiert . Ich finde FriendlyId allerdings etwas vielseitiger.

Frost
quelle
Ich mag freundliche ID und habe in vielen Projekten verwendet. Eigentlich benutzt meine App Mongoid. Und friend_id unterstützt es afaik nicht. Und wie ich bereits erwähnt habe, besteht meine Einschränkung darin, das Modell nicht zu ändern.
Autodidakt
1
Wenn Sie Mongoid verwenden, gibt es Mongoid-Slug, um diese Funktionalität zu erreichen. Es verwendet tatsächlich to_param, aber es macht auch einige andere clevere Dinge im Hintergrund. Ich habe den Link hier gefunden: stackoverflow.com/questions/4744446/…
Frost
Ich mochte dieses Juwel. Es gibt noch einen ähnlichen Slugoid . Aber wie ich schon sagte, habe ich die Einschränkung, das Modell nicht zu modifizieren. Das to_parambricht meinen Front-End-Teil der App. Eigentlich suche ich verzweifelt nach dem Routing-Ansatz: Ich muss meine API ändern, ohne jedoch den Modell- und Frontend-Teil aus der App zu entfernen. Warum kann ich nicht einfach den Ansatz haben, nur die Routen zu ändern, wie ich angegeben hatte, und den Beispielbeitrag für eine ältere Version der Schienen oben?
Autodidact
Haben Sie versucht, Ihre Controller so umzuschreiben, dass sie Ihre benutzerdefinierten Routentasten verwenden? Zum Beispiel @client = Client.find(:name => param[:client_name]in ClientsController#show? Das könnte funktionieren.
Frost
Client.where(:name => param[:client_name]).first, das ist.
Frost
0

In Rails 3 können Sie die ID-Schlüssel mithilfe einer Kombination aus Namespaces und Bereichen wie folgt umbenennen (allerdings nicht sehr schön):

namespace :clients do
  scope "/:client_name" do
    namespace :sites do
      scope "/:name" do
         post "/:title" => "articles#create"
         ...
      end
    end
  end
end
Dominik Goltermann
quelle