Ubah nama parameter: id di Sumber daya perutean untuk Rails


107

Saya melihat sekeliling tentang cara mengubah slot params dinamis dan menemukan posting ini yang melakukan hal yang tepat. Posnya adalah https://thoughtbot.com/blog/rails-patch-change-the-name-of-the-id-parameter-in

Pada dasarnya apa yang dilakukannya adalah, jika berikut ini adalah rutenya:

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

Rute ini membuat jalur berikut:

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

Salah satu solusinya adalah mengganti def to_parammetode dalam model, tetapi saya ingin ini tanpa menyentuh model itu sendiri.

Tetapi karena ini untuk Rails 2.x, bagaimana saya bisa mencapai hal yang sama untuk Rails 3?

Memperbarui

Aplikasi ini menggunakan Mongoid. Bukan AR. Jadi, gem friendly tidak bisa digunakan afaik.

Jawaban:


192

Rel 4 & 5

Di Rails 4, :paramopsi telah ditambahkan, yang tampaknya melakukan apa yang Anda cari. Anda dapat melihat kode Rails 3 dibandingkan dengan kode Rails 4 .

Detail

Anda dapat dengan mudah menerapkan ini di routes.rbfile Anda :

# config/routes.rb

resources :posts, param: :slug

# app/controllers/posts_controller.rb

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

Sejak rilis Rails 4, fungsionalitas ini didokumentasikan di Panduan Rails .

Rel 3

Sayangnya, di Rails 3, :keyopsi untuk resourcestelah dihapus, sehingga Anda tidak dapat lagi dengan mudah mengubah nama untuk rute yang dibuat dengan cara ini hanya dengan memasukkan opsi tambahan.

Detail

Saya berasumsi bahwa Anda entah bagaimana sudah mendapatkan aplikasi yang berfungsi seperti yang Anda inginkan pada tahun lalu, tetapi saya akan membahas cara untuk mendapatkan efek yang Anda gambarkan di Rails 3 in routes.rb. Ini hanya akan melibatkan sedikit lebih banyak pekerjaan daripada to_parammetode. Anda masih dapat menentukan parameter khusus dalam rute didefinisikan menggunakan scopedan match(atau sepupu itu get, put, post, dan delete). Anda cukup menulis nama parameter yang Anda inginkan di matcher:

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

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

Anda harus menambahkan semua rute yang dibuat resourcessecara otomatis untuk Anda secara manual , tetapi itu akan mencapai apa yang Anda cari. Anda juga dapat secara efektif menggunakan :controlleropsi dengan scopedan scopeblok tambahan untuk menghilangkan beberapa pengulangan.


EDIT (8 Mei 2014): Buat lebih jelas bahwa jawaban berisi informasi untuk Rails 3 & 4. Perbarui tautan ke kode untuk pergi ke nomor baris yang tepat dan komit sehingga mereka harus bekerja untuk jangka waktu yang lebih lama.

EDIT (Nov 16, 2014): Rails 4 harus berada di atas sekarang dan menyertakan informasi yang relevan karena ini adalah versi Rails saat ini untuk beberapa waktu sekarang.

EDIT (Agustus 9, 2016): Merefleksikan bahwa solusinya masih berfungsi di Rails 5, dan perbarui tautan lama.


1
Jadi pada dasarnya, Rails3 membuat opsi resource di router menjadi restfull, tetapi perlu diganti demi memiliki nama variabel kustom ... Terasa timpang!
Augustin Riedinger

1
Berikut adalah backport paramopsi untuk rel 3: gist.github.com/sj26/44ef47fe8b98b46ee32d
sj26

Ini akhirnya merusak pembantu url. Mereka akhirnya menghasilkan rute berbasis id normal jika saya melewati objek atau mengeluh tentang kunci [: slug] yang hilang jika saya meneruskan slug masuk Ada ide bagaimana memperbaikinya?
RonLugge

9
FYI, jika Anda menggunakan sumber daya bersarang, parameter untuk sumber daya induk akan post_slug, yang mungkin membingungkan.
ghayes

4
Ini benar-benar bagus tetapi apa yang dapat saya lakukan jika saya tidak ingin nama parameter id induk seperti post_post_id untuk sumber daya bersarang?
Asnad Atta

45

di Rails 4, berikan opsi param untuk mengubah: id params. Misalnya resources :photos, param: :photo_nameakan menghasilkan / photos /: photo_name


1

Jika saya memahami Anda dengan benar, yang Anda inginkan adalah memiliki client_namealih - alih iddi url Anda, bukan?

Anda dapat melakukannya dengan mengganti to_parammetode dalam model Anda. Anda dapat memperoleh informasi lebih lanjut di sini .


1
Seperti yang telah saya sebutkan, saya memiliki kendala untuk tidak mengubah model. Apakah contoh yang disebutkan di atas tidak didukung atau tidak digunakan lagi di Rails 3?
Autodidak

1

Ada permata untuk itu, sama seperti permata untuk segalanya;)

Saya telah menggunakan FriendlyId untuk perilaku semacam ini di rel 3.

Ini akan meminta Anda untuk menambahkan beberapa kode ke model Anda, seperti ini:

class Client < ActiveRecord::Base
  has_friendly_id :name
end

... dan jika klien Anda tidak memiliki nama yang kompatibel dengan URI, Anda mungkin ingin menggunakan slug untuk itu, yang dapat Anda lakukan dengan has_friendly_id :name, :use_slug => true. Saat menggunakan siput, Anda jelas harus menyimpannya ke database juga.

Dan seperti yang telah disebutkan, Anda masih bisa menggunakan to_paramtrik dengan rel 3, seperti yang didokumentasikan di sini . Saya menemukan FriendlyId sedikit lebih fleksibel.


Saya suka id yang ramah dan telah digunakan di banyak proyek. Sebenarnya aplikasi saya menggunakan Mongoid. Dan friendly_id tidak mendukungnya afaik. Dan seperti yang sudah saya sebutkan bahwa kendala saya adalah tidak mengubah model.
Autodidak

1
Jika Anda menggunakan mongoid, ada mongoid-siput untuk mencapai fungsi ini. Ini benar-benar menggunakan to_param, tetapi itu melakukan beberapa hal pintar lainnya di latar belakang juga. Saya menemukan tautannya di sini: stackoverflow.com/questions/4744446/…
Frost

Saya menyukai permata itu. Ada lagi yang serupa slugoid . Tetapi seperti yang telah saya katakan bahwa saya memiliki kendala untuk tidak memodifikasi model. Itu to_parammerusak bagian depan aplikasi saya. Sebenarnya saya sangat mencari pendekatan perutean adalah saya telah mengubah API saya tetapi tanpa memutus bagian Model dan Frontend dari aplikasi. Mengapa saya tidak bisa hanya memodifikasi rute saja seperti yang saya nyatakan dan contoh posting untuk versi rel yang lebih lama di atas ???
Autodidak

Sudahkah Anda mencoba menulis ulang pengontrol Anda sehingga menggunakan kunci rute kustom Anda? Misalnya @client = Client.find(:name => param[:client_name]di ClientsController#show? Itu mungkin berhasil.
Frost

Client.where(:name => param[:client_name]).first, itu adalah.
Frost

0

Di Rails 3 Anda dapat mengganti nama kunci id dengan menggunakan kombinasi namespace dan cakupan seperti ini (meskipun tidak terlalu bagus):

namespace :clients do
  scope "/:client_name" do
    namespace :sites do
      scope "/:name" do
         post "/:title" => "articles#create"
         ...
      end
    end
  end
end
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.