Rails truncating of parameters with '.' in urls - ruby-on-rails

I am trying to send an IP address as a parameter to a Rails method destroy in a url. There is a problem if the parameter includes .; I get not found errors, this is the log generated:
Started DELETE "/admin/user/stefan-admin/whitelist/4.3.2.1" for 127.0.0.1 at 2013-07-17 09:31:18 +0100
Processing by ErrorsController#error_404 as
Parameters: {"not_found"=>"admin/user/stefan-admin/whitelist/4.3.2"}
WARNING: Can't verify CSRF token authenticity
Session: {:user=>"admin", :role=>:admin, :user_id=>"stefan-admin"}
Completed 404 Not Found in 30ms (Views: 1.1ms | ActiveRecord: 0.0ms)
The not found message has a truncated ip address. If I use a parameter without ., e.g. abc, I don't get the not found error, and the destroy method is called.
Rails received the url, but then mangled it internally, possibly because it is processing . as an extension. Is there some way to turn off this behaviour or escape the url to avoid it?

You need to add a constraint to the routes to allow dots in params
resources :whitelists, :constraints => { :id => /[0-9.]+/ }
Or something of that kind in your routes.rb, it depends on how you write your routes but the constraints part stay the same

The reason for the "truncated" ip address is the (optional) (.:format) that resources, 'get', 'match' etc. generate on every route.
You can specify a dedicate route without the format like:
match '/admin/user/:id/whitelist/*ip', to: 'controller#action', format: false
pay attention to the * at the last parameter. It collects the whole rest of the url.

At first glance the problem could be resolved by manipulating the parameters or routing. By thinking a bit more, you will notice two more problems in your scheme:
You used GET request to process a delete action
The dots in url, if not for name extension, is very ugly.
So, instead of solving the problem directly, I suggest you to:
Review the view code containing the request link. It's better to be a button_to, or a link_to with delete method and UJS support.
By this you'll send a POST request to server without ip in URL. And you don't need any change in controller code.

Found a hacky way to do it. If your route looks like this
match 'controller/:some_param' => 'controller#action'
Then in the controller action, you can do something like this
actual_param = params[:some_param]
if params[:format]
actual_param << "." << params[:format]
end
Then use actual_param to identify the correct resource

Related

Rails Routing Error w/ key

So I made this custom Route
on my routes.rb
get'dashboard_report_m/:date/:branch_id'=>'reports#monthly_and_branch'
I'm Getting Routing Error, No route matches [GET] "/dashboard_report_m"
on my rake routes I have this
on rake routes
GET /dashboard(.:format) reports#today_admin
GET /dashboard_report/:date/:branch_id(.:format) reports#date_and_branch
GET /dashboard_report_m/:date/:branch_id(.:format) reports#monthly_and_branch
all the other routes I made are fine but this one just doesn't seem to work.
I tried removing the keys ':date/:branch_id'
and it would work just fine.
I have already made similar routes and they all work just fine except for this one.
Some things to check:
Is there a ReportsController with a ​monthly_and_branch action?
Does the error occur if you visit /dashboard_report_m/2016-09-20/1234 directly or are you using a path helper?
UPDATE
OK so you are accessing the path http://localhost:3000/dashboard_report_m/?date=2016-09&branch_id=1 - you are passing the parameters in as query params, this is not how your route is set up. The way you have it now it is expecting dashboard_report_m/2016-09/1. You need to either remove the date and branch_id params from your route or change the way you access the URL. I suggest reading the Rails Routing from the Outside In guide.
When you access the following route:
localhost:3000/dashboard_report_m/?date=2016-09&branch_id=1
This is a GET request to 'dashboard_report_m', with query parameters: params['date'] = '2016-09' and params['branch_id'] = '1'.
What you should instead be doing is accessing this route:
localhost:3000/dashboard_report_m/2016-09/1
This is a GET request to 'dashboard_report_m/:date/:branch_id' - i.e. using the bound parameters of date and branch_id.
Further reading: Understand the difference between bound parameters and the query string. This is by no means specific to Rails; it's at the core of how all web applications work.

Set params hash value using link_to without affecting url in Rails 4

When I submit a form, a number of parameters are set without showing up in the url.
I would like to do the same thing with link_to:
<%= link_to((purchase.paid ? 'yes' : 'no'), {action: :index, hidden_id: purchase.id}) %>
produces the url 'http://localhost:3000/purchases?hidden_id=1'. I would like to link to the url 'http://localhost:3000/purchases' while still setting params[:hidden_id] so I can access it in the controller, as if I had submitted a form.
My routes.rb file is as follows:
root to: 'products#index'
resources :products
resources :purchases
match ':controller/(:action/(:id))', controller: :shop, via: [:get,:post]
In answering this, is there anything I should know here about the difference in the way these two things are handled? Is it something about get vs post requests or is there some other principle involved which I'm not grasping?
Yes, it's to do with Get vs Post requests.
A Get request can only send parameters in the URL itself. A post request can also be sent to a URL that includes parameters in the URL itself, but it can also send parameters 'under the hood' so to speak.
So if your routes were set up to allow it, you could send either a get or a post request to http://localhost:3000/purchases?hidden_id=1, but only the post request could include additional parameters under the hood.
Anything else you should know about the difference in the way these two are handled? Yes. In most web frameworks, when you see the parameters server-side, they will be split up into GET params and POST params. Rails doesn't make this distinction, and puts them both in the same params hash. (I think this is silly, but whatever).
Also, a get request can be sent simply by entering the URL in your browser and hitting enter. A post request will generally only be executed by a user submitting a form on a web page. For this reason, get requests are not meant to change any content in your database. They should be for viewing information only. So, eg, if you have a button to delete a resource (eg. a blog post or something) it should be submitted via post. (more info on that at Why shouldn't data be modified on an HTTP GET request?)
Lastly, Rails provides an option in it's link_to helper to allow you to easily make the 'link' use a post request. See the method option at http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to. This basically uses javascript to prevent the normal action of clicking the link (which would be a get request), and submit a post request instead.

Custom route mistaken for object id in Rails

I have the following route:
view_all_styles /styles/view_all(.:format) styles#view_all
When I point my broswer at xyz.com/styles/view_all I receive the error:
ActiveRecord::RecordNotFound at /styles/view_all
Couldn't find Style with id=view_all
I'm also routed to the show action??
Request parameters
{"action"=>"show", "controller"=>"styles", "id"=>"view_all"}
It sounds like you've got your routes defined in the wrong order - you'll want to define your custom route before the resource routes of styles. Otherwise, you'll run into exactly this problem.
Since your route, /styles/view_all also fits into the route for #show, /styles/:id ('view_all' being the :id), it will match and pass along the request to #show before it even tries to match your custom route.

Rails 3 routing. How to create /controller/id/action routing format for specific action taking place?

Ok so this is a basic routing question for a rails 3 application. I have a controller called contact_infos. For the edit action I want to match the route like the following /contact_infos/id/action. The reason I'm doing this is specifically for ajax functionality. Here's what I've done so far. This route worked fine.
match ':controller(/:id(/:action))(.:format)'
But this route breaks my catch-all route of.
match ':controller(/:action(/:id))(.:format)'
so it is not acceptable for my application.
I know I could target my specific route in the following way
controller :contact_infos do
end
But I'm unsure how to match the url as /contact_infos/id/action only for the edit action without breaking any other contact_infos actions.
Any ideas?
If you give the right answer I will definitely rate you up.
Thanks!
Alex
Try using through the following sytax...
match "contact_infos/:id/edit" , :to => "contact_infos#edit", :as => 'contact_infos_edit'
Please note that whilst not part of your question, that a catch all route is a very bad idea.
This has been considered dangerous for some time, and is not recommended. It will allow the app to respond to actions for all HTTP methods (e.g. GET for things which should really be PUT). This exposes you to CSRF attacks, as the CSRF token is only required for PUT, POST and DELETE requests..
You should always explicitly route using the routing helpers for all resources you're making available, to ensure the app will only respond to correct requests (e.g. DELETE request for a destroy acttion)

What's the difference between example.com/controller and example.com/controller/ in Rails?

I have a PostsController, not essential to the example but will help when I paste snippets, and I'm using current_page? to, as the name implies, figure out what page is being displayed. I'm getting what seem like weird results.
current_page? will return different answers if I go to /posts vs. /posts/.
As a test, on the index view for my controller I am simply calling
current_page?(:action => 'index')
If I go to /controller (with no trailing slash), current_page? will return true. However, if I go to /controller/, it will return false.
Tailing the log shows that both do in fact hit the same action
Processing PostsController#index (for 127.0.0.1 at 2009-08-11 18:28:12) [GET]
Parameters: {"action"=>"index", "method"=>:get, "controller"=>"posts"}
The action produces the same results for both, as to be expected.
I'm using Rails 2.3.2 and this ticket is the only thing that seems close. The only commenter thinks that current_page should "consider two URLs to be the same page if they both refer to the same RESTful object".
Thanks for any insight into this.
rails routing will tolerate the trailing slash but it will not be generated when you pass :action => 'index', :controller => 'posts' to url_for (with standard routes).
according to current_page? documentation it just generates a url from the passed arguments and then compares to the current request url string. since this generated url will not have the trailing slash it will return true when current url is /controller and false when /controller/
There are several ways you can solve your problem:
compare the params, not generated url
redirect from /controller/ to /controller. This is actually a good idea if you do page caching etc. also for SEO
I'm sure there are other ways as always :)

Resources