Custom Rails 4 Routes containing "/" - ruby-on-rails

I have a method that generates a random url ending and a get path that looks like
/path/var1/var2
The only problem is that some of those generated values for var2 have a "/" in them. So if var 2 is "h4rd/erw" rails reads it as
/path/var1/h4rd/erw
or
/path/var1/var2/var3
rails thinks that this is another parameter of the route and i keep get the error
No route matches.
I have thought of setting up the generated value for var2 to not include "/"s or possibly putting a wildcard in the route if that's possible like /path/var1/*. What would be the best solution for this?

You can use route globbing:
get '/path/var1/*var2', to: 'controller#action'
Let's say the request went to /path/var1/h4rd/erw. Then in the controller action, the value of params[:var2] would be h4rd/erw.

I would make sure that the values are always escaped.
string = "my/string"
=> "my/string"
CGI.escape(string)
=> "my%2Fstring"
So your url will be like
/path/var1/h4rd%2Ferw
and it will go to the right controller with the right variables set.
Rails will automatically unescape the values of parameters in the controller "params" variable, so by the time you're dealing with the value in the controller the slash will be back in the string.
The only remaining question is when to do the escaping. If you pass the value as an argument to a path helper then rails should escape it automatically for you, like so:
link_to "Here", my_route_path(:foo => "bar")

Related

Rails routing forcing param to be present

I'm fairly new to ruby api development and have created the below endpoint in my routes.rb
get "/users/active_users/:since"
However, when the param is not given, I want the param to default to a certain value. How do I enforce this? Also, I want to enforce that param be an integer and not alpha/alpha-numeric. Help is appreciated!
get "/users/active_users/:since"
By making this routes its compulsory to give the params[:since] , other wise it will throw back a error not routes matches
So here by i would suggest you to make routes
get "/users/active_users"
Since it's get type request so its won't affect more, you can append params[:since] in query with routes like this:-
/users/active_users?since=1999
And at your controller you will get params[:since] = 1999
So far as i know it can't be enforce routes to accept only integer params but it can be handle at controller side
params[:since].is_a? Integer
=> true
Or
params[:since].to_i

Path helper changing "/search?option=..." to "/search.option=..." when anchor is specified

I have a seemingly simple case with Rails' path helpers. My route is straightforward:
get 'search', to: 'search#search_results'
$ rails routes
...
search GET /search(.:format) search#search_results
I need to inject an option=graph parameter into the query string on the current page. This works as expected:
<%= link_to "Graphs", search_path(request.query_parameters.merge({:option => "graphs"})) %>
Giving a link like this:
http://localhost:3000/search?body=&commit=Search&feedback=&option=graphs&reason=&site=&title=&user_rep_direction=%3E%3D&user_reputation=0&username=&utf8=%E2%9C%93&why=foo
However, when I specify the anchor parameter, something weird happens:
search_path(request.query_parameters.merge({:option => "graphs"}), anchor: "graph-1")
http://localhost:3000/search.body=&commit=Search&feedback=&option=graphs&reason=&site=&title=&user_rep_direction=%253E%253D&user_reputation=0&username=&utf8=%25E2%259C%2593&why=foo#graph-1
The anchor is added as expected, but the ? to start the query string turns into a . - which irritates the controller because it's an unrecognized format.
Why is this happening, and how can I fix it?
Running Rails 5 beta 4 on Ruby 2.2.2
After some testing it turns out that you should include the anchor when merging the params:
search_path(request.query_parameters.to_h.merge({option: "graphs", anchor: "graph-1")})
Explanation: your approach, i.e.:
search_path(request.query_parameters.merge({:option => "graphs"}), anchor: "graph-1")
actually passes two separate hashes as arguments to the search_path helper instead of just one. However, in the helper definition code, only the last hash argument is taken as the real options parameter to the helper. Other arguments are processed differently.
In the end, the anchor argument gets understood by the helper as the format specifier (I found this out by debugging the path construction in the helper but am unable to point to a precise place in the source code) and that is why the resulting path contains a dot . after the resource name.
Update: Note, that the query_parameters must also be converted to a hash, as normally they are of the ActionController::Parameters and are also processed differently in the path helper. After unifying all params and the anchor to a Hash class, the path should be correct.

Rails routing sometimes replaces the id in url with id-name. How do I avoid problems?

Generally the url from my report page looks like this:
http://test-account.peter:3000/offices/7/reports/index
However, sometimes it looks like this:
http://test-account.peter:3000/offices/7-peters-office/reports/index
Why does this happen?
It was not really a problem until we changed the controller action from a GET to a POST and renamed it. We had to do this so we could pack more parameters in to the ajax request. Users still have this section of the site bookmarked and it throws errors all day long.
I have tried to redirect the route:
get '/offices/*all/reports/index' => 'offices#show'
get '/offices/:office_id/reports/index' => 'offices#show'
get '/offices/:office_name/reports/index' => 'offices#show'
Is there a way to catch the name? Or do I have to prevent the name from being added to the url in the first place?
In the controller, you would be able to parse the parameter to get just the first character and check if its an integer. However, it would be much better to debug how the parameter is getting assigned to different values and ensure only the id is used. If you're linking to that route in a view, check what is being passed in the link and confirm the value is what you expect it to be.
Rails does routing it does not look in your database for matched data. So without looking at data, your three routes are exactly the same, the variable (office_id & office_name) is just named different. If you get a request on example /offices/:office_name/reports/index, rails will just match the first one since both routes match the request.
You need something in the path that indicates its a name or id. If you will really never have a name and id with the same search, then you could just have one route and try to match a id or name from the DB in the controller.

Rails: The easiest way to differ path parameter from query string parameter?

Rails router gives us an easy way to define optional path parameters, like this:
# config/routes.rb
scope "(:locale)", locale: /ru|de|fr/ do
resources :books
end
Thus we can access /users path and get the default locale, or /ru/books and get the locale in params[:locale].
But with the same setup we can also call the page /books?locale=ru and get the same effect (both path parameters and query string parameters are treated equally and put in the params hash). If locale is processed in a global before_action as Rails i18n guide suggests we can even set locale for the pages that are not supposed to be localized.
So my question is what is the simplest and cleanest way differ path parameters from query string parameters (with the goal to ignore certain query string parameters)?
Answering my own question:
There is a method ActionDispatch::Request#query_parameters. It returns only the parameters set via query string.
There are also method path_parameters and symbolized_path_parameters. It is obvious they return parameters derived from path (including controller and action). They can be called on request inside a controller action. (They are not documented under ActionDispatch::Request, this is why I missed them initially.)
Rails 5 (edit Jan 9, 2017): As of Rails 5 method symbolized_path_parameters was removed. Method path_parameters is now documented.

rails passing parameter from view to a different controller as a string

Im trying to pass a parameter (a file path : eg. user/lauren/tools/) from a view in RAILS to another different controller using RUBY. I want to use the file path (as a string) to be matched with a regular expression. To do that, right now Im using the params [:parameter] method as follows in the controller action where Im setting the variable instance:
#variable = /^.+\/[^\/]+$/.match(params[:name]).to_s ---where :name is the parameter passed from view
Right now, I dont get any output when I try to display that in the corresponding view of that controller....im guessing its the params [:name] method I need to replace or modify?
Id really appreciate views on this...thanks!
While your server is running open a new terminal window and type rails console. This will let you see what your variables actually contain. You can type params and see what the hash has in it and see why your regex is failing. It sounds to me like you are trying to match your path, not your params.

Resources