Zmień nazwę parametru: id w Zasoby routingu dla Railsów

107

Rozejrzałem się, jak zmienić miejsce na dynamiczne parametry i znalazłem ten post, który robi dokładnie to. Post jest https://thoughtbot.com/blog/rails-patch-change-the-name-of-the-id-parameter-in

Zasadniczo to, co robi, jeśli następujące są trasy:

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

Te trasy tworzą następujące ścieżki:

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

Jednym z rozwiązań jest zastąpienie def to_parammetody w modelu, ale chcę tego bez dotykania samego modelu.

Ale skoro jest to dla Rails 2.x, jak mogę osiągnąć to samo dla Rails 3?

Aktualizacja

Ta aplikacja korzysta z Mongoid. Nie AR. Tak więc, przyjazny dla klejnotów nie może być używany afaik.

Samouk
źródło

Odpowiedzi:

192

Szyny 4 i 5

W Rails 4 :paramdodano opcję, która wydaje się robić dokładnie to, czego szukasz. Możesz spojrzeć na kod Rails 3 w porównaniu z kodem Rails 4 .

Detale

Możesz to łatwo zaimplementować w swoim routes.rbpliku:

# config/routes.rb

resources :posts, param: :slug

# app/controllers/posts_controller.rb

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

Od wydania Rails 4 ta funkcjonalność jest udokumentowana w Rails Guides .

Szyny 3

Niestety w Railsach 3 usunięto :keyopcję dla resources, więc nie można już łatwo zmienić nazwy tras utworzonych w ten sposób, po prostu podając dodatkową opcję.

Detale

Zakładam, że w minionym roku aplikacja działała tak, jak chcesz, ale spróbuję uzyskać efekt, który opisujesz w Railsach 3 routes.rb. Będzie to wymagało trochę więcej pracy niż to_parammetoda. Nadal można zdefiniować parametry niestandardowe w trasach zdefiniowana scopei match(lub jego kuzyni get, put, post, i delete). Po prostu wpisz nazwę parametru, który chcesz dopasować:

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

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

Musiałbyś ręcznie dodać wszystkie trasy, które są resourcesautomatycznie tworzone dla Ciebie, ale pozwoliłoby to osiągnąć to, czego szukasz. Możesz także efektywnie skorzystać z :controlleropcji scopei dodatkowych scopebloków, aby usunąć część powtórzeń.


EDYCJA (8 maja 2014): Uczyń to bardziej oczywistym, że odpowiedź zawiera informacje dla obu Rails 3 i 4. Zaktualizuj linki do kodu, aby przejść do dokładnych numerów linii i zatwierdzeń, aby działały przez dłuższy czas.

EDYCJA (16 listopada 2014): Rails 4 powinny być teraz na szczycie i zawierać istotne informacje, ponieważ jest to aktualna wersja Railsów już od dłuższego czasu.

EDYCJA (9 sierpnia 2016 r.): Zastanów się, że rozwiązanie nadal działa w Railsach 5 i zaktualizuj nieaktualne łącza.

joshhepworth
źródło
1
Zasadniczo Rails3 stworzył opcję zasobów w routerze, aby była pełna, ale musi zostać zastąpiona ze względu na niestandardowe nazwy zmiennych ... Czuje się kiepsko!
Augustin Riedinger,
1
Oto backport paramopcji dla szyn 3: gist.github.com/sj26/44ef47fe8b98b46ee32d
sj26
To kończy się zerwaniem pomocników URL. Generują normalną trasę opartą na identyfikatorze, jeśli przekażę obiekt lub narzekają na brakujący klucz [: slug], jeśli przekażę ślimak. Jakieś pomysły, jak to naprawić?
RonLugge
9
FYI, jeśli używasz zagnieżdżonych zasobów, parametr zasobu nadrzędnego będzie miał wartość post_slug, co może być mylące.
Ghayes
4
To jest naprawdę dobre, ale co mogę zrobić, jeśli nie chcę, aby nazwa parametru identyfikatora nadrzędnego, na przykład post_post_id, dotyczyła zagnieżdżonego zasobu?
Asnad Atta
45

w Railsach 4, podaj opcję param, aby zmienić parametry: id. Na przykład resources :photos, param: :photo_namewygeneruje / photos /: photo_name

bobzsj87
źródło
1

Jeśli dobrze cię rozumiem, to co chcesz to mieć client_namezamiast idw swoim adresie URL, prawda?

Możesz to zrobić, nadpisując to_parammetodę w swoim modelu. Więcej informacji znajdziesz tutaj .

Mohit Jain
źródło
1
Jak już wspomniałem, mam obowiązek nie zmieniać modelu. Czy powyższy przykład nie jest obsługiwany lub przestarzały w Railsach 3?
Autodidact
1

Jest za to klejnot, tak jak klejnot do wszystkiego;)

Używam FriendlyId do tego rodzaju zachowania w szynach 3.

Będzie to jednak wymagało dodania kodu do modelu, na przykład:

class Client < ActiveRecord::Base
  has_friendly_id :name
end

... a jeśli twoi klienci nie mają nazw zgodnych z URI, możesz użyć do tego slug, co możesz zrobić za pomocą has_friendly_id :name, :use_slug => true . Jeśli używasz ślimaków, oczywiście musisz je również utrwalić w bazie danych.

I jak już wspomniano, nadal możesz użyć to_paramsztuczki z szynami 3, jak opisano tutaj . Uważam jednak, że FriendlyId jest nieco bardziej wszechstronny.

Mróz
źródło
Lubię przyjazny identyfikator i używałem go w wielu projektach. W rzeczywistości moja aplikacja korzysta z Mongoid. Friendly_id nie obsługuje tego afaik. I jak już wspomniałem, moim ograniczeniem jest niezmienianie modelu.
Autodidact
1
Jeśli używasz mangusty, istnieje mangusta-ślimak do osiągnięcia tej funkcji. W rzeczywistości używa to_param, ale robi też inne sprytne rzeczy w tle. Link znalazłem tutaj: stackoverflow.com/questions/4744446/…
Frost
Podobał mi się ten klejnot. Jest jeszcze jeden podobny slugoid . Ale jak już mówiłem, mam obowiązek nie modyfikować modelu. To to_parampsuje moją część aplikacji. Właściwie desperacko szukam podejścia do routingu, aby zmienić moje API, ale bez zrywania części Model i Frontend z aplikacji. Dlaczego nie mogę po prostu zmodyfikować tras tylko tak, jak powiedziałem i przykładowy post dla starszych wersji szyn powyżej?
Samouk
Czy próbowałeś przepisać kontrolery, aby używały niestandardowych kluczy tras? Na przykład @client = Client.find(:name => param[:client_name]w ClientsController#show? To może zadziałać.
Frost
Client.where(:name => param[:client_name]).first, to jest.
Frost
0

W Railsach 3 możesz zmienić nazwy kluczy id używając kombinacji przestrzeni nazw i zakresów w ten sposób (choć niezbyt ładne):

namespace :clients do
  scope "/:client_name" do
    namespace :sites do
      scope "/:name" do
         post "/:title" => "articles#create"
         ...
      end
    end
  end
end
Dominik Goltermann
źródło