Rails routing sometimes confuses method for object ID - ruby-on-rails

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.

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.

Rails routes and querystring

I am having troubles trying to define the correct route for a query coming from ember. The request appears like this:
GET "/users?id=1011
No matter what I try I always have the request forwarded to the index action, while it is intended for the show action.
I have tried many things, like
get "/users?id=", to: redirect('/users')
but nothing seems to work.
Can anyone explain to me what can I do and most important the reason behind it?
Thank you very much for your time!
GET /users?id=1011 always goes to index because Rails just sees the route as GET /users. The question mark denotes a parameter, which isn't part of any of your defined routes.
You can modify your index method to interpret the param, something like:
def index
if params[:id]
# call show, do something, whatever
else
# regular index action
end
end
In the case of retrieving just one user, it would be more common to route this to your show action as you originally intended. To accomplish this, do not pass the id as a query param, but instead as a slug segment /users/1011, which you can accomplish by declaring the following in your routes.rb:
get '/users/:id', to: 'users#show'
If you want to go full tilt then you might as well just declare users as a resource like so:
resources :users
Which will automatically wire up your index, show, update, destroy, etc. Throw Active Model Serializers in the mix and you can have Ember Data start talking to your API nearly "out of the box".

Strange Rails resource routes behavior

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.

rails, general understanding of URIs and controllers

i have a Message model and controller. and in it, i have the standard functions such as index, show etc.
when i go to "localhost:3000/messages", my index.html.erb gets displayed, which in turn renders my partial _messages.html.erb.
and in there, i have an anchor href
Received Messages
however, i encounter 2 issues.
received_messages isn't being appending the URL, which i thought it would normally do unless i added a / in the beginning. how do i make it append?
and also.. if i manually type in "localhost:3000/messages/received_messages", i keep getting redirected to the messages#show function. why is that in general?
i have a received_messages.html.erb and even in my routes, i have
match '/received_messages', to: 'messages#received_messages'
which i have the function #received_messages in my controller as well.
why does it keep getting redirected to messages#show
thanks a lot = )
You asked:
if i manually type in "localhost:3000/messages/received_messages", i
keep getting redirected to the messages#show function. why is that in
general?
In general, you have the idea of "messages"... and to
view the collection of messages, you'll go to "/messages"
To view a specific message (with id 56) , you'll go to "/messages/56"
To edit, "/messages/56/edit"
To create a new one: "/messages/new"
So, when you go to /messages/received_messages, the system, is attempting to show the message with id "received_messages"
If you want an action on the Collection of messages, you can setup your routes like:
resources :messages do
collection do
get :received
end
end
This will match up "/messages/received", and run the MessagesController#received action, and render the app/views/messages/received.html.erb file.

How to deal with routes that don't respond to GET in Rails?

I have a singleton route that looks like this:
resource :avatar, :only => [:edit, :update]
When a user edits the avatar, they go to /avatar/edit to view the form, when they save they are sent with a put request to /avatar and then redirected back to /avatar/edit. What should happen when we get a GET request to /avatar?
At the moment the route is not recognized and a generic 404 is returned. But this happens way more often than it should, so I feel we should do something about it. I'm tempted to add a:
get "/avatar" => redirection("/avatar/edit")
Any reason not to do that? any dangers in doing it?
I'm not sure I have all the reasons why this error happen, but I know some:
There's an error so instead of redirecting, the user is just shown the edit form again in the put route, but then, instead of re-submitting, the user re-uses the url (pressing enter in the url field, copying and pasting, bookmarking, etc).
The user at that point decides to change locale (happens often because the error message is the first time the person actually needs to understand the web site, so they decide to switch language to one that they understand) which of course generates a get in the same URL.
I now having a plain redirection wouldn't be the best in the second case, because the error is lost, but at least it's better than a 404.
Part of the confusion with this route is that it is plural and yet refers to a singleton. Any chance that you could use just "avatar"? If I went to a route "/avatars" I would expect a list of avatars. If it is singular, then I would expect "/avatar" to view the avatar. I also think this might be useful in a route like "/avatar.jpg" that would respond with the avatar image. However, if your specs define no use for a show and always to edit try:
get "/avatars" => "avatars#edit"
or the singular
get "/avatar" => "avatars#edit"

Resources