Thay đổi tên của tham số: id trong Tài nguyên định tuyến cho Rails


107

Tôi đã xem xét xung quanh cách thay đổi vị trí thông số động và thấy bài đăng này thực hiện điều chính xác. Bài đăng là https://thoughtbot.com/blog/rails-patch-change-the-name-of-the-id-parameter-in

Về cơ bản nó là gì, nếu sau đây là các tuyến đường:

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

Các tuyến đường này tạo ra các đường dẫn sau:

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

Một giải pháp là ghi đè def to_paramphương thức trong mô hình, nhưng tôi muốn điều này mà không cần chạm vào chính mô hình.

Nhưng vì nó dành cho Rails 2.x, làm thế nào tôi có thể đạt được điều tương tự cho Rails 3?

Cập nhật

Ứng dụng này đang sử dụng Mongoid. Không phải AR. Vì vậy, không thể sử dụng gem thân thiện với afaik.

Câu trả lời:


192

Đường ray 4 & 5

Trong Rails 4, :paramtùy chọn đã được thêm vào, có vẻ như sẽ làm chính xác những gì bạn đang tìm kiếm. Bạn có thể xem qua mã Rails 3 so với Rails 4 .

Chi tiết

Bạn có thể dễ dàng triển khai điều này trong routes.rbtệp của mình :

# config/routes.rb

resources :posts, param: :slug

# app/controllers/posts_controller.rb

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

Kể từ khi phát hành Rails 4, chức năng này được ghi lại trong Hướng dẫn về Rails .

Đường ray 3

Thật không may, trong Rails 3, :keytùy chọn cho resourcesđã bị xóa, vì vậy bạn không còn có thể dễ dàng thay đổi tên cho các tuyến đường được tạo theo cách này bằng cách chỉ cần chuyển qua một tùy chọn bổ sung.

Chi tiết

Tôi cho rằng bằng cách nào đó bạn đã làm cho ứng dụng hoạt động theo cách bạn muốn trong năm qua, nhưng tôi sẽ đi sâu vào một cách để có được hiệu ứng như bạn mô tả trong Rails 3 routes.rb. Nó sẽ chỉ liên quan đến công việc nhiều hơn một chút so với to_paramphương pháp. Bạn vẫn có thể xác định các thông số tùy chỉnh trong các tuyến đường được xác định sử dụng scopematch(hoặc nó anh em họ get, put, post, và delete). Bạn chỉ cần viết tên tham số bạn muốn trong trình kết hợp:

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

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

Bạn sẽ phải thêm thủ công tất cả các tuyến đường resourcestự động tạo cho bạn, nhưng nó sẽ đạt được những gì bạn đang tìm kiếm. Bạn cũng có thể sử dụng hiệu quả :controllertùy chọn với scopevà các scopekhối bổ sung để loại bỏ một số lặp lại.


CHỈNH SỬA (ngày 8 tháng 5 năm 2014): Làm rõ ràng hơn câu trả lời chứa thông tin cho cả Rails 3 & 4. Cập nhật các liên kết đến mã để chuyển đến số dòng chính xác và cam kết để chúng hoạt động trong một khoảng thời gian dài hơn.

CHỈNH SỬA (ngày 16 tháng 11 năm 2014): Rails 4 phải ở trên cùng ngay bây giờ và bao gồm các thông tin liên quan vì nó là phiên bản hiện tại của Rails được một thời gian.

CHỈNH SỬA (ngày 9 tháng 8 năm 2016): Phản ánh rằng giải pháp vẫn hoạt động trong Rails 5 và cập nhật các liên kết đã lỗi thời.


1
Vì vậy, về cơ bản, Rails3 đã tạo tùy chọn tài nguyên trong bộ định tuyến để được khôi phục lại, nhưng cần phải được ghi đè vì lợi ích của các tên biến tùy chỉnh ... Cảm thấy khập khiễng!
Augustin Riedinger

1
Đây là một backport của paramtùy chọn cho rails 3: gist.github.com/sj26/44ef47fe8b98b46ee32d
sj26

Điều này kết thúc việc phá vỡ các trình trợ giúp url. Họ kết thúc việc tạo ra một tuyến dựa trên id bình thường nếu tôi chuyển một đối tượng vào hoặc phàn nàn về việc thiếu khóa [: slug] nếu tôi chuyển slug vào. Có ý kiến ​​nào về cách khắc phục không?
RonLugge

9
FYI, nếu bạn sử dụng tài nguyên lồng nhau, thông số cho tài nguyên mẹ sẽ là post_slug, điều này có thể gây nhầm lẫn.
ghayes

4
Điều này thực sự tốt nhưng tôi có thể làm gì nếu tôi không muốn tên tham số của id mẹ như post_post_id cho tài nguyên lồng nhau?
Asnad Atta

45

trong Rails 4, vượt qua tùy chọn param để thay đổi: id params. Ví dụ: resources :photos, param: :photo_namesẽ tạo / photos /: photo_name


1

Nếu tôi hiểu bạn một cách chính xác, những gì bạn muốn là có client_namethay vì idtrong url của bạn, phải không?

Bạn có thể làm điều đó bằng cách ghi đè to_paramphương thức trong mô hình của mình. Bạn có thể lấy thêm thông tin ở đây .


1
Như tôi đã đề cập rằng tôi có hạn chế là không thay đổi mô hình. Ví dụ nói trên không được hỗ trợ hoặc không được chấp nhận trong Rails 3?
Autodidact

1

Có một viên đá quý cho điều đó, giống như có một viên đá quý cho mọi thứ;)

Tôi đã sử dụng FriendlyId cho loại hành vi này trong rails 3.

Tuy nhiên, nó sẽ yêu cầu bạn thêm một số mã vào mô hình của mình, như sau:

class Client < ActiveRecord::Base
  has_friendly_id :name
end

... và nếu khách hàng của bạn không có tên tương thích với URI, bạn có thể muốn sử dụng một slug cho tên đó, điều này bạn có thể làm với has_friendly_id :name, :use_slug => true. Mặc dù vậy, khi sử dụng slugs, bạn cũng cần duy trì chúng vào cơ sở dữ liệu.

Và như đã đề cập, bạn vẫn có thể sử dụng to_paramthủ thuật với rails 3, như được ghi lại ở đây . Tôi thấy FriendlyId linh hoạt hơn một chút.


Tôi thích id thân thiện và đã sử dụng trong nhiều dự án. Thực ra ứng dụng của tôi đang sử dụng Mongoid. Và Friendly_id không hỗ trợ nó afaik. Và như tôi đã đề cập rằng hạn chế của tôi là không thay đổi mô hình.
Autodidact

1
Nếu bạn đang sử dụng mongoid, có mongoid-slug để đạt được chức năng này. Nó thực sự sử dụng to_param, nhưng nó cũng thực hiện một số công cụ thông minh khác trong nền. Tôi tìm thấy liên kết ở đây: stackoverflow.com/questions/4744446/...
Frost

Tôi thích viên đá quý đó. Có một slugoid tương tự khác . Nhưng như tôi đã nói rằng tôi có hạn chế là không được sửa đổi mô hình. Điều đó to_paramphá vỡ phần giao diện người dùng của tôi trong ứng dụng. Trên thực tế, tôi đang rất muốn tìm kiếm phương pháp định tuyến là tôi sẽ thay đổi API của mình nhưng không phá vỡ phần Model và Frontend khỏi ứng dụng. Tại sao tôi không thể có cách tiếp cận chỉ sửa đổi các tuyến đường như tôi đã nêu và bài đăng ví dụ cho phiên bản cũ hơn của đường ray ở trên ???
Autodidact

Bạn đã cố gắng viết lại bộ điều khiển của mình để nó sử dụng các khóa định tuyến tùy chỉnh của bạn chưa? Ví dụ @client = Client.find(:name => param[:client_name]trong ClientsController#show? Điều đó có thể hoạt động.
Frost

Client.where(:name => param[:client_name]).first, đó là.
Frost

0

Trong Rails 3, bạn có thể đổi tên các khóa id bằng cách sử dụng kết hợp không gian tên và phạm vi như thế này (mặc dù không đẹp lắm):

namespace :clients do
  scope "/:client_name" do
    namespace :sites do
      scope "/:name" do
         post "/:title" => "articles#create"
         ...
      end
    end
  end
end
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.