Rails 4.1.2 - to_param speeds up the slash (and breaks the application)

I use to_param in my application to create a custom URL (this custom path contains slashes):

 class Machine < ActiveRecord::Base def to_param MachinePrettyPath.show_path(self, cut_model_text: true) end end 

The thing is, since the behavior of Rails 4.1.2 has changed, and Rails does not allow slashes in the URL (when using a custom URL), so it skips slashes.

I had the following routes:

 Rails.application.routes.draw do scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do resources :machines, except: :destroy do collection do get :search get 'search/:ad_type(/:machine_type(/:machine_subtype(/:brand)))', action: 'search', as: :pretty_search get ':subcategory/:brand(/:model)/:id', action: 'show', as: :pretty patch ':subcategory/:brand(/:model)/:id', action: 'update' # To be able to update machines with new rich paths. end end end end 

I tried using the recommendation in the stream to use the glob parameter only for the show method, to make sure that it works:

 resources :machines, except: :destroy do #... end scope format: false do get '/machines/*id', to: "machines#show" end 

But this is absolutely not working. I still have such broken links:

 http://localhost:3000/machines/tractor%2Fminitractor%2Fmodel1%2F405 

Of course, if I would replace the hidden slashes with myself:

 http://localhost:3000/machines/tractor/minitractor/model1/405 

And try visiting the path, then the page will open.

Any ideas how I can fix this?

+6
source share
3 answers

I had the same issue when using auto-generated url helpers. I used the debugger to track new behavior in its source (somewhere around ActionDispatch :: Journey :: Visitors :: Formatter), but I did not find promising solutions. It seems that the parameterized model is now strictly interpreted as a single path segment with a slash separator and is accordingly shielded, without any options, in other words, the formatting device.

As far as I can tell, the only way to get the URL helper to get the old result is to use the source routes file and pass each segment separately, something like:

 pretty_machine_path(machine.subcategory, machine.brand, machine.model, machine.id) 

This is ugly, hell, and obviously not what you want to do over and over again. You can add the MachinePrettyPath method to generate segments as an array and explode the result for the helper (e.g. pretty_machine_path(*MachinePrettyPath.show_path_segments(machine)) ), but it's still pretty verbose.

Between the aforementioned headaches and the โ€œYou're doing it wrongโ€ attitude from the developers on this Rails ticket you contacted, the easiest option for me was to bite a bullet and write my own URL helper instead of using to_param. I have yet to find a good example of the โ€œrightโ€ way to do this, but something like this blue-bone example should serve the purpose:

 #app/helpers/urls_helper.rb module UrlsHelper def machine_path(machine, options = {}) pretty_machine_path(*MachinePrettyPath.show_path_segments(machine), options) end end #app/controllers/application_controller.rb class ApplicationController < ActionController::Base helper :urls #for the views include UrlsHelper #for controllers #... end 
+1
source

If you are sure that the correct URL is safe, you should add .html_safe to the returned string:

 MachinePrettyPath.show_path(self, cut_model_text: true).html_safe 

(I have not seen anywhere where it can be escaped, but check the entire stream in your application, perhaps the method of manual testing using the method)

0
source

How about determining the URL itself?

 def to_param "#{ subcategory.title.parameterize }/#{ brand.name.parameterize }/#{ model.name.parameterize) }/#{ id }" end 

And then in your routes something like this:

 get 'machines/*id', to: "machines#show" 

You also need to separate your [: id] parameters when you find on your model.

 Machine.find( params[:id].split("/").last ) 
0
source

Source: https://habr.com/ru/post/973086/


All Articles