Strange Rails resource routes behavior - ruby-on-rails

I've met strange error. Im not sure this is bug. However i never met this strange behavior before.
resource :watches
Makes such strange routing table:
watches POST /watches(.:format) watches#create
new_watches GET /watches/new(.:format) watches#new
edit_watches GET /watches/edit(.:format) watches#edit
GET /watches(.:format) watches#show
PUT /watches(.:format) watches#update
DELETE /watches(.:format) watches#destroy
As you see no ID param and messed actions
On same time:
resources :mibs
Make proper routes
mibs GET /mibs(.:format) mibs#index
POST /mibs(.:format) mibs#create
new_mib GET /mibs/new(.:format) mibs#new
edit_mib GET /mibs/:id/edit(.:format) mibs#edit
mib GET /mibs/:id(.:format) mibs#show
PUT /mibs/:id(.:format) mibs#update
DELETE /mibs/:id(.:format) mibs#destroy
I thought that is could be somehow inflector problem, but trying using "rockets" instead of "watches" give same result:
rockets POST /rockets(.:format) rockets#create
new_rockets GET /rockets/new(.:format) rockets#new
edit_rockets GET /rockets/edit(.:format) rockets#edit
GET /rockets(.:format) rockets#show
PUT /rockets(.:format) rockets#update
DELETE /rockets(.:format) rockets#destroy
Anything except my first two resources (servers and mibs) make such result.
Probably corrupted routing cache somewhere?

resource indicates a singleton resource: in other words, you're telling Rails that there's only ever one watch for each user, so passing IDs would be useless.
resources is the standard invocation for getting routes with IDs attached.
So, essentially, the problem is an inflector one, but for resource or resources, not for the name of your routes. For more information, check out the Ruby on Rails routing guide. It does a good job explaining the difference between singleton resources and the more usual kind.

Related

Routes causing legacy issues rails 5, cannot destroy etc

This is a continuation of my previous question: Put or patch for new update action Rails
The solution to this question worked, however, the solution is causing other issues within the legacy system, I'll show the main two issues but I'm not sure how to go about making the system work peacefully until I can go about refactoring the system.
With post :update in place the following actions break, destroying anything, importing records, if I uncomment post :update then importing works, edit does not.
None of the forms are setup to use REST, which I can't change currently as I'm trying to handle the routes for now and then move onto the system itself.
Here is the example of a routes
resources :stock_groups, except: %i[destroy] do
member do
get :copy
post :copy
post :update # temp PATCH, PUT routes
end
collection do
get :list
get :import_stock_groups
get :download_stock_groups_template
post :preview_import_stock_groups
post :process_import_stock_groups
end
end
# remap wrong implmentation of paths
get '/stock_groups/edit/:id', to: redirect('/stock_groups/%{id}/edit')
get '/stock_groups/copy/:id', to: redirect('/stock_groups/%{id}/copy')
get '/stock_groups/show/:id', to: redirect('/stock_groups/%{id}')
Here is what I get when I go to import records
it's targeting the wrong method in the controller.
As for destroying this fails either, I did try adding something like post :destroy but this didn't work.
Any help would be great.
Well let us discuss error it is telling your exactly what is happening here. You are trying to searching StockGroup.find(params[:id]) which should be integer. As find will search your record by id value.
StockGroup.find(params[:id]) # only integer allowed
But in your request you are sending id = process_import_stock_groups which is not possible as rails convention you will have id integer unless you change it in model level by changing rails conventions.
So to test run rails c
StockGroup.find('process_import_stock_groups') # should not work but just try to know your error
Now which column you save this value in process_import_stock_groups so you method whould be
StockGroup.where(name_of_column: 'process_import_stock_groups').first
what you get? I hope it solve your issue.

Are the order of routes in a Rails app significant

So, I work with a bit of a behemoth. A 15-year-old rails app which has a few... hundred... controllers, all with their own routes.
Perhaps unsurprisingly, the page loads aren't the snappiest (although not so slow it poses a problem), and this got me thinking.
Is the order in which the routes are defined significant?
Will routes defined later on in the list take longer to match, or are they indexed to speed up the searching process?
RailsGuides mentions this
Rails routes are matched in the order they are specified, so if you
have a resources :photos above a get 'photos/poll' the show action’s
route for the resources line will be matched before the get line. To
fix this, move the get line above the resources line so that it is
matched first.
Having a lot of RESTful routes actually can affect the speed of the process , Documentation actually hints at this
If your application has many RESTful routes, using :only and :except to generate only the routes that you actually need can cut down on memory use and speed up the routing process.
Current Router in rails creates a graph to optimize routes lookup.
Order matters because two routes that matches the same url will trigger the first one defined, but the router does not try each route on a sequential order.
This RailsConf talk explains how the Router works https://www.youtube.com/watch?v=lEC-QoZeBkM
If you find your page not responding fast enough I really doubt the router is the problem, you should profile the request (use something like mini-profiler).

Rails routing sometimes confuses method for object ID

So I have a rails app with a controller that has a bunch of methods. For some reason occasionally calls to this controller have not been interpreted correctly by the app. For example:
A 404 error occurred on the Production server at 2016-07-28 02:55:23 UTC:
Message:
Problem: Document(s) not found for class Section with id(s) publish_preview. Summary: When calling Section.find ... [etc.]
Requested Params
{"action"=>"update", "controller"=>"sections", "organization_id"=>"goannunciation", "bulletin_id"=>"20160731", "id"=>"publish_preview"}
Url:
bulletinbuilder.org/organizations/goannunciation/bulletins/20160731/sections/publish_preview
So the sections controller has a "publish_preview" method, which this URL is supposed to--and usually does--call appropriately. However, recently the app has not interpreted the URL correctly; from the stack:
"/var/www/bulletin_builder/releases/20160725175809/app/controllers/sections_controller.rb:34:in `update'"
which indicates that the app is calling the "update method," using the actual method call "publish_preview" as the id of the section. This must be some kind of routing error... possibly related to the header? Browser related?
resources :organizations do
...
resources :bulletins do
...
resources :sections do
collection do
get :manage
get :first_section
get :bulletin_creation
get :included_sections
get :custom_sections_max_message
get :search
get :publish_preview
get :admin_diagnostics
end
member do
post :remove
post :removed_blocked_section
get :delete_dynamic
get :update_included
get :update_added
get :share
get :unshare
get :refresh
end
end
As I mentioned in the comment below, the pertinent routes HAVE NOT been changed, and the issue only happens occasionally.
In addition, the server for some reason is sending a bunch (17) of error notification emails for the same error, all within a few seconds of each other.
This is most likely related to the HTTP method being used to access the resource. For example,
GET /organizations/../sections/publish_preview
Will hit the publish_preview action as expected; however
PUT/POST /organizations/../sections/publish_preview
Will hit the update action with :id as publish_preview
If you're actually using the update action, you can add a constraint to only route numeric ids
resources :sections, constraints: { id: /\d+/} do
...
end
If you're not using the update action, just remove the update route
resources :sections, except: [:update]
There are other ways to handle this too but the above two are probably the easiest to implement depending on your case.
So this was a very strange intermittent issue. It was kind of complex but it apparently boiled down to this:
There was a method that called a bunch of other methods. Some of those methods were put in a separate thread because they took a while to run. The enclosing method sometimes ended with a "return_to :back" before the thread calling the other methods was completed.
This apparently did some funky things to the app, including messing with the params used in the running thread, and causing some really strange errors. The issue was solved by replacing the return_to :back with a render json: statement.

Rails Routing from a plural to singular resource

I had built a feature in my app in which I had created some content settings that could be changed within my database. However I ran into an issue that required me to use a polymorphic route. This ended up causing me lots of issues because my routes had two ID's associated with them. I realized that the reason why this was the case was that my resource in my routes file was plural. So I made it singular, and now i'm having issues getting the simple routes to work out.
My routes file is like so
concern :content_settings do
resources :content_setting, only: [:index, :edit, :delete, :update]
end
When I run a rake routes I'm getting so
admin_customer_content_setting_index GET /admin/customers/:customer_id/content_setting(.:format) admin/content_setting#index
edit_admin_customer_content_setting GET /admin/customers/:customer_id/content_setting/:id/edit(.:format) admin/content_setting#edit
admin_customer_content_setting PATCH /admin/customers/:customer_id/content_setting/:id(.:format) admin/content_setting#update
PUT /admin/customers/:customer_id/content_setting/:id(.:format) admin/content_setting#update
Now basically I am at a point where I need to implement a route to the editing options of my new awesome feature. I keep trying something along the lines of..
=link_to edit_admin_customer_content_setting_path(#owner)
I continue getting a 'no route options' error. Would anybody know if there is something that I am missing? I'm happy to show more of my code if needed.
Much thanks!
Please try this
= link_to edit_admin_customer_content_setting_path(customer_id: #owner.id, id: #content.id)
When you take a look at the output of the rake routes, you can see that in the third column you are being told what parameters it expects:
edit_admin_customer_content_setting GET /admin/customers/:customer_id/content_setting/:id/edit(.:format) admin/content_setting#edit
In your case: customer_id and id
UPDATE
If you would like to avoid passing two ids to your helpers, you can use shallow routes. Please take a look at the documentation here (scroll little bit down to Shallow Nesting)

Forms for polymorphically associated resources where a basic resource path "/resource" does not exist

I have a polymorphic resource Location that can latch on to, let's say, instances of Store. The extent to which this "should" be a polymorphic resource is questionable, but that's besides the point at the moment.
A location accesses its polymorphic parent via location.locatable.
Since the location will always be the child of a resource like a store, I'd like to remove the route to POST /locations and instead have the application direct POST requests to /stores/1/locations.
Now, the default Rails method when it comes to dealing with polymorphic associations is to do it at the controller level with
def new
#location = Store.find(params[:store_id]).vendors.new
end
This, as expected, prepopulates location.locatable_id and location.locatable_type. Wonderful. But it still routes to locations_path by default, which I would like to get rid of.
And I try, it raises a route not found error.
So how can I prepare a general location form that is extensible to new parents?
I have come to the following:
form_for(#location, :url => [#location.locatable, #location]) do |l|
Which seems to work fine, but the passing of a path as an array irks me, and for some reason I can't find any documentation on the subject. Is there a better way to accomplish this? I'm new-ish to polymorphic resources, and it would be nice to do this right from the start.
Also, a (quite) minor peripheral issue is that this doesn't cooperate out of the box with the default RSpec-generated view spec since Rails actually tries to find #location.locatable. This is fairly easy to get around though. I was planning on rewriting the view spec from top to bottom anyway.

Resources