2012-03-21 17 views
10

Tôi đang làm việc để triển khai chế độ SEO, điều đó có nghĩa là tôi cần phải thêm thông số cho một hành động hiển thị.Thông số tùy chỉnh trong URL cho hành động hiển thị

Việc sử dụng hợp cụ thể là một trang web tìm kiếm nơi URL cấu trúc là:
/cars/(:brand)/ => một danh sách trang
/cars/(:brand)/(:model_name)?s=query_params => tìm kiếm hành động
/cars/:brand/:model_name/:variant/:id => một chương trình xe hoạt động

My vấn đề là làm cho URL hoạt động của chương trình hoạt động mà không cần phải cung cấp:brand, :model_name:variantlàm đối số riêng lẻ . Chúng luôn có sẵn từ các giá trị trên tài nguyên.

Những gì tôi có: /cars/19330-Audi-A4-3.0-TDI

Những gì tôi muốn /cars/Audi/A4/3.0-TDI/19330

Trước đây, đây là như thế nào routes.rb trông giống như:

# Before 
resources :cars. only: [:show] do 
    member do 
    get 'favourize' 
    get 'unfavourize' 
end 

Sau đây là nỗ lực đầu tiên của tôi:

# First attempt 
scope '/cars/:brand/:model_name/:variant' do 
    match ":id" => 'cars_controller#show' 
    match ":car_id/favourize" => 'cars_controller#favourize', as: :favourize_car 
    match ":car_id/unfavourize" => 'cars_controller#unfavourize', as: :unfavourize_car 
end 

Điều này giúp bạn có thể thực hiện:
cars_path(car, brand: car.brand, model_name: car.model_name, variant: car.variant)
Nhưng điều đó rõ ràng không thực sự lý tưởng.

Làm cách nào để thiết lập các tuyến đường (và có lẽ là phương pháp .to_param?) Theo cách không khiến nhiệm vụ tẻ nhạt thay đổi tất cả các cuộc gọi link_to?

Cảm ơn trước!

- CẬP NHẬT -

Với gợi ý @ tharrisson, đây là những gì tôi đã cố gắng:

# routes.rb 
match '/:brand/:model_name/:variant/:id' => 'cars#show', as: :car 

# car.rb 
def to_param 
    # Replace all non-alphanumeric chars with - , then merge adjacent dashes into one 
    "#{brand}/#{model_name}/#{variant.downcase.gsub(/[^[:alnum:]]/,'-').gsub(/-{2,}/,'-')}/#{id}" 
end 

Tuyến hoạt động tốt, ví dụ /cars/Audi/A4/3.0-TDI/19930 hiển thị đúng trang. Tuy nhiên, việc tạo liên kết với to_param không hoạt động. Ví dụ:

link_to "car link", car_path(@car) 
#=> ActionView::Template::Error (No route matches {:controller=>"cars", :action=>"show", :locale=>"da", :brand=>#<Car id: 487143, (...)>}) 
link_to "car link 2", car_path(@car, brand: "Audi") 
#=> ActionView::Template::Error (No route matches {:controller=>"cars", :action=>"show", :locale=>"da", :brand=>"Audi", :model_name=>#<Car id: 487143, (...)>}) 

Đường ray dường như không biết cách dịch to_param thành liên kết hợp lệ.

+0

Đây là một câu hỏi thực sự tốt và tốt bằng văn bản. Tôi nghĩ rằng tôi có một ý tưởng và muốn chắc chắn rằng tôi đang đi đúng hướng (không có ý định chơi chữ). Có phải trường hợp bạn muốn có thể sử dụng 'cars_path (@car)' trong link_to của bạn và có nó tạo ra URL phân cấp tốt đẹp từ các khung nhìn của bạn, nhưng cũng có router nhận ra các URL "một phần" (ví dụ '/ cars/Audi') như một yêu cầu để liệt kê Audis? Hoặc là yêu cầu bổ sung cho liên kết_để nhận biết theo ngữ cảnh (ví dụ như vậy nó tạo liên kết đến biến thể/xe /: thương hiệu từ một số hành động của bộ điều khiển, nhưng URL đầy đủ của xe từ các hành động điều khiển khác? –

+0

Cảm ơn, @tharrison. bạn đã có nó đúng, tôi muốn có thể sử dụng 'cars_path (@car)' trong 'link_to' của tôi. Hành động nào đang được kích hoạt có thể được kiểm soát bởi các ràng buộc trong' routes.rb'. Điều này có nghĩa là các url cho 'cars/Audi' không sử dụng 'cars_path' nhưng một cái gì đó như' brand_path (thương hiệu: "Audi") '. –

+0

OK, đến đó, nhưng tôi không hoàn toàn có nó sau đó :-). Nếu bạn muốn sử dụng các tuyến đường được đặt tên như brand_path, đối số sẽ là một ví dụ của mô hình thương hiệu ... mặc dù điều đó có thể giống như 'brand_path (@ car.brand)'. Bạn có một mô hình thương hiệu và nguồn lực trong các tuyến đường cho điều đó không? –

Trả lời

1

OK, vậy đây là những gì tôi có. Điều này làm việc trong trường hợp thử nghiệm nhỏ của tôi.Rõ ràng một số fixups cần thiết, và tôi chắc chắn có thể là ngắn gọn hơn và thanh lịch, nhưng phương châm của tôi là: "làm cho nó hoạt động, làm cho nó đẹp, làm cho nó nhanh" :-)

Trong routes.rb

controller :cars do 
    match 'cars', :to => "cars#index" 
    match 'cars/:brand', :to => "cars#list_brand", :as => :brand 
    match 'cars/:brand/:model', :to => "cars#list_model_name", :as => :model_name 
    match 'cars/:brand/:model/:variant', :to => "cars#list_variant", :as => :variant 
    end 

trong mô hình xe

def to_param 
    "#{brand}/#{model_name}/#{variant}" 
    end 

và rõ ràng là mong manh và không khô, trong cars_controller.rb

def index 
    @cars = Car.all 

    respond_to do |format| 
     format.html # index.html.erb 
     format.json { render json: @cars } 
    end 
    end 

    def list_brand 
    @cars = Car.where("brand = ?", params[:brand]) 

    respond_to do |format| 
     format.html { render :index } 
    end 
    end 

    def list_model_name 
    @cars = Car.where("brand = ? and model_name = ?", params[:brand], params[:model]) 

    respond_to do |format| 
     format.html { render :index } 
    end 
    end 

    def list_variant 
    @cars = Car.where("brand = ? and model_name = ? and variant = ?", params[:brand], params[:model], params[:variant]) 

    respond_to do |format| 
     format.html { render :index } 
    end 
    end 
+0

Tôi xin lỗi @tharrison, nhưng tôi nghĩ bạn đã hiểu sai. Vấn đề không hiển thị các trang thương hiệu, model_name hoặc trang biến thể. Công cụ đó đã hoạt động. Vấn đề là liên kết trực tiếp tới bản ghi _one single_. Để làm việc này, tôi phải sử dụng ID xe hơi và thêm vào đó, tôi muốn thêm thương hiệu, model_name và biến thể vào URL (cho mục đích SEO). Vì vậy, những gì tôi muốn là: link_to cars_path (@car) để trỏ đến/cars /: brand /: model_name /: variant /: id. Điều đó có ý nghĩa? –

+0

Jonas, tôi nghĩ rằng mã tôi cung cấp là một milimét cách xa những gì bạn muốn. Thêm hoặc sửa đổi các mệnh đề 'match' khi cần bằng cách thêm': id'. Đối số ': as =>: foo' là thứ cho phép bạn tham chiếu URL là 'foo_path' và ghi đè' to_param' là thứ tạo ra đường dẫn đẹp - định dạng theo mặc định bạn thích và thêm id hoặc bất kỳ thuộc tính nào khác của xe bạn thích để có được URL đẹp. Đúng? –

+0

Có lẽ tôi chưa đủ rõ ràng.Định tuyến hoạt động hoàn hảo theo cách bạn đề xuất. Vấn đề là Rails không thể dịch thực hiện 'to_param' thành một liên kết. Tôi đã cập nhật câu hỏi của mình với một ví dụ đơn giản. –

3

Tôi không thấy bất kỳ cách nào để làm điều này với Rails mà không cần tinh chỉnh hoặc nhận dạng URL hoặc tạo URL.

Với nỗ lực đầu tiên của bạn, bạn đã nhận dạng URL hoạt động chứ không phải là thế hệ. Giải pháp tôi có thể thấy để làm cho thế hệ hoạt động sẽ là ghi đè phương thức trợ giúp car_path.

Một giải pháp khác có thể giống như bạn đã làm trong CẬP NHẬT, để ghi đè phương thức ô tô to_param. Lưu ý rằng sự cố của bạn không có trong phương thức to_param nhưng trong định nghĩa tuyến đường: bạn cần cung cấp thông số :brand, :model_name:variant khi bạn muốn tạo tuyến đường. Để giải quyết vấn đề đó, bạn có thể muốn sử dụng Wildcard segment trong tuyến đường của mình.

Cuối cùng, bạn cũng có thể sử dụng routing-filter gem làm cho bạn có thể thêm logic trước và sau khi nhận dạng/tạo url. Đối với tôi, có vẻ như tất cả các giải pháp này đều hơi nặng và không dễ như nó nên nhưng tôi tin rằng điều này xuất phát từ nhu cầu của bạn khi bạn muốn thêm một số cấp trong URL mà không tuân thủ nghiêm ngặt hành vi của đường ray sẽ cung cấp cho bạn URL giống như /brands/audi/models/A3/variants/19930

0

Bạn muốn thông số được giới hạn được chuyển đến url trong đó một số thông số là tùy chọn và một số thông số cần phải có mặt.

Hướng dẫn đường ray cho biết bạn có thể có thông số nghiêm ngặt cũng như tùy chọn và bạn cũng có thể đặt tên cho tuyến đường cụ thể theo thứ tự để đơn giản hóa việc sử dụng nó.

Hướng dẫn trên đường ray định tuyến bound parameters

sử dụng Ví dụ -

Trong lộ trình dưới đây,

  • brandoptional parameter như nó được bao quanh bởi circular bracket
  • Cũng xin lưu ý có thể có tùy chọn các thông số bên trong tuyến đường nhưng chúng cần được thêm vào cuối cùng /cars(/:brand)(/:make)(/:model)

    match '/cars/(:brand)', :to => 'cars#index', :as => cars

đây cars_url sẽ bản đồ để action index của xe điều khiển .. lại cars_url("Totoya") chí chỉ số tuyến đường hoạt động của những chiếc xe điều khiển cùng với các params[:brand] như Toyota

Hiện tuyến đường url có thể như sau nơi id là bắt buộc và những người khác có thể tùy chọn

match '/cars/:id(/:brand(/:model_name/)(/:variant)', :to => "cars#show", :as => car 

Trong trường hợp trên, id là bắt buộc cánh đồng. Các thông số khác là tùy chọn. để bạn có thể truy cập vào nó như car_url(car.id) hoặc car_url(12, 'toyota') hoặc car_url(12, 'toyota', 'fortuner') hoặc car_url(12, 'toyota', 'fortuner', 'something else)

1

Bạn chỉ cần tạo ra hai đường, một cho sự công nhận, một cho thế hệ.

Cập nhật: sử dụng các tuyến đường được đề cập.

# config/routes.rb 
# this one is used for path generation 
resources :cars, :only => [:index, :show] do 
    member do 
    get 'favourize' 
    get 'unfavourize' 
    end 
end 
# this one is used for path recognition 
scope '/cars/:brand/:model_name/:variant' do 
    match ':id(/:action)' => 'cars#show', :via => :get 
end 

Và tùy chỉnh to_param

# app/models/car.rb 
require 'cgi' 

class Car < ActiveRecord::Base 
    def to_param 
    parts = [brand, 
      model_name, 
      variant.downcase.gsub(/[^[:alnum:]]/,'-').gsub(/-{2,}/,'-'), 
      id] 

    parts.collect {|p| p.present? ? CGI.escape(p.to_s) : '-'}.join('/') 
    end 
end 

Mẫu người giúp đỡ đường dẫn:

link_to 'Show', car_path(@car) 
link_to 'Edit', edit_car_path(@car) 
link_to 'Favourize', favourize_car_path(@car) 
link_to 'Unfavourize', unfavourize_car_path(@car) 
link_to 'Cars', cars_path 
form_for(@car) # if resources :cars is not 
       # restricted to :index and :show 
Các vấn đề liên quan