Mismatching route for rspec testing post on a singular resource - ruby-on-rails

I get the error no routes matches even tho in rake routes I have:
... POST /todo/:todo/todo_comments(.:format)
and in my rspec I have
post :todo_comments, params: { todo_id: 1 }

It sounds like your routes are defined as:
resources :todos do
resources :todo_comments
end
In a controller spec (type: :controller), you need to specify the action name in the controller that handles the request. In this case, that's :index:
post :index, params: { todo_id: 1 }
If you're in a request spec (type: :request), on the other hand, it requires the URL to request instead, which you can build using a routing helper:
post todo_todo_comments_path(1)
# or, without the helper:
post "/todos/1/todo_comments"
Note that these forms don't explicitly name the :todo_id parameter, because it will be extracted from the route.

Related

Rails Routes missing prefix for resources post route

I created a new controller and actions for a new model. I have setup the rails routes like below:
namespace :api do
namespace :v1 do
resources :universes
end
end
I am trying to write up some RSpec tests using the path helpers (ex. get(api_v1_universe_path(universe.id))). When I go to look at the post route for invites the route is missing the prefix as shown here:
POST /api/v1/universes(.:format) api/v1/universes#create
new_api_v1_universe GET /api/v1/universes/new(.:format) api/v1/universes#new
edit_api_v1_universe GET /api/v1/universes/:id/edit(.:format) api/v1/universes#edit
api_v1_universe GET /api/v1/universes/:id(.:format) api/v1/universes#show
I know I can manually add a line like post "/", to: "universe#create", as: "create" to get a route with a prefix. However, I wanted to know what was causing prefix to be missing from the post route so I can possibly fix that instead?

How to handle a Rails redirect that starts with "x" pattern in the url

I am new to Ruby and Rails. So far I've successfully:
updated a url from /dashboard to /specific_dashboard
gotten the redirect working for when you put in /dashboard, it now takes you to /specific_dashboard
The problem I am running into is redirecting when there are additional params in the url like /dashboard/program... or /dashboard/dashboard_page...
Is there Ruby syntax that would be equivalent to using a wild card like get "/dashboard/*" => redirect("/specific_dashboard"). I've tried this and match '/*dashboard' => redirect("/specific_dashboard"), via: :all and can't get it to work. If its helpful, I have this code in my routes.rb file.
you can use nested routes.
Example you have authors and books.
resources :authors do
resources :books
end
https://guides.rubyonrails.org/routing.html#nested-resources
It should be the following in routes.rb:
get 'dashboard/*section', to: '<controllerName>#<actionName>'
Here:
controllerName = Controller Name, e.g. Home
actionName = Action Name, e.g. Dashboard
class HomeController
def dashboard
# inside params[:section] you'll get 'dashboard_page'
# if you're accessing '/dashboard/dashboard_page'
end
end
Reference: https://guides.rubyonrails.org/routing.html#route-globbing-and-wildcard-segments

Rails 5.1+ routing: `resources` not working but explicit route definition does

Update
This was a legacy app I inherited, and I found out that the previous developers had removed the rack code that converted browser POST requests into PUT/PATCH based on the _method param that Rails adds to your forms.
# config/application.rb
# This is the line that caused the problem...
config.middleware.delete ::Rack::MethodOverride
Once I removed that line and restarted the server, things worked as expected.
Original Question
When I post a Rails form using the standard resources in the routes file, it raises a route not found error when I'm trying to update an existing record:
No route matches [POST] "/admin/lookups/record_types/1"
The model is namespaced as app/models/lookups/record_type.rb
# model file
module Lookups
class RecordType < ApplicationRecord
# ...
end
end
# form in view file
<%= form_with model: #record_type, scope: :record_type, url: [:admin, #record_type], local: true do |form| %>
<%= form.text_field :value %>
<% end %>
# Request being sent
POST admin/lookups/record_types/1
{ record_type: { _method: "patch", value: "value" } }
# in routes .rb
namespace :admin do
namespace :lookups do
# Does not work
resources :record_types
# Works when explicitly written out
post "record_types/:id", controller: record_types, action: :update
end
end
When I explicitly write out the POST request in the routes.rb file, it works as expected.
I know that Rails is actually POSTing the request and using the _method hidden attribute to map the routes file. However, something isn't converting that request properly.
It's an application I inherited, and at one point it was exclusively an JSON API (no direct UI), so I'm wondering if there was something removed that converted the Rails _method param to the proper controller? I don't know what that would be, though.
This is the output of my rake routes:
admin_lookups_record_types
GET /admin/lookups/record_types(.:format)
admin/lookups/record_types#index
POST /admin/lookups/record_types(.:format)
admin/lookups/record_types#create
new_admin_lookups_record_type
GET /admin/lookups/record_types/new(.:format)
admin/lookups/record_types#new
edit_admin_lookups_record_type
GET /admin/lookups/record_types/:id/edit(.:format)
admin/lookups/record_types#edit
admin_lookups_record_type
GET /admin/lookups/record_types/:id(.:format)
admin/lookups/record_types#show
PATCH /admin/lookups/record_types/:id(.:format)
admin/lookups/record_types#update
PUT /admin/lookups/record_types/:id(.:format)
admin/lookups/record_types#update
DELETE /admin/lookups/record_types/:id(.:format)
admin/lookups/record_types#destroy
The problem seems to be the use of the scope argument to the form_with method.
If you take a look at the routes you'll note that the route to the update action uses PUT or PATCH whereas the route to the create action uses POST.
As the documentation of the FormHelper module states:
in the options hash. If the verb is not GET or POST, which are natively supported by HTML forms, the form will be set to POST and a hidden input called _method will carry the intended verb for the server to interpret.
But nesting the special _method key inside record_type breaks this mechanism. Is the scope really necessary? I'd try removing it, it should work fine without it. The correct HTTP verb to use would be PUT or PATCH. Adding an additional POST route breaks the regular Rails structure without any real gain.

Rails 5 rename single resource route name

I am trying to create a separate :show route, to use route globbing on the :id parameter. For this, I created a resource route without the show route and also a separate show route:
resource :test, except: [:show]
get 'test/*id', to: 'test#show', as: :test
the problem is that I receive the error: You may have defined two routes with the same name using the:asoption, or you may be overriding a route already defined by a resource with the same naming.
If I remove as: :test it works. rails routes shows:
tests POST /tests(.:format)
new_test GET /tests/new(.:format)
edit_test GET /tests/:id/edit(.:format)
test PATCH /tests/:id(.:format) <-- WHY??
DELETE /tests/:id(.:format)
GET /tests/*id(.:format)
as you can see, resources renamed the PATCH route to :test. If I remove that route, the DELETE route is named test, and so on. How can I stop resources from using the test route name specifically? I cannot move my globbing route above the resource block obviously because then all other routes are globbed too.
What I want:
tests POST /tests(.:format)
new_test GET /tests/new(.:format)
edit_test GET /tests/:id/edit(.:format)
PATCH /tests/:id(.:format)
DELETE /tests/:id(.:format)
test GET /tests/*id(.:format)
Rails uses the same prefix (say, in your case "test") for all those four routes[show(GET), update(PUT/PATCH), destroy(DELETE)] and it recognises the different routes with the HTTP Verbs.
I don't understand your problem, but if you look on Rails Guides "Singular Resources" you can see:
Path Controller #Action Used for
GET /geocoder/new geocoders#new return an HTML form for creating the geocoder
POST /geocoder geocoders#create create the new geocoder
GET /geocoder geocoders#show display the one and only geocoder resource
GET /geocoder/edit geocoders#edit return an HTML form for editing the geocoder
PATCH/PUT /geocoder geocoders#update update the one and only geocoder resource
DELETE /geocoder geocoders#destroy delete the geocoder resource
show, create, update and destroy use the same route but with different HTTP verbs. And in your case, test wrote with PATCH verb, because this verb earlier in the table, empty name means that it uses the same name as upper line.
First of all,
test PATCH /tests/:id(.:format) <-- WHY??
DELETE /tests/:id(.:format)
GET /tests/*id(.:format)
Patch is for your Update method routes.
Delete is for destroy method route.
that add by your custom route generated by get 'test/*id', to: 'test#show', as: :test
So, here you can make your show route with different alias. Ex like using as :show_test

Rails routes generate Post request for New action in nested resources

I have the following nested resources:
resources :listings do
resources :offers do
member do
put "accept"
put "reject"
end
end
end
In my listings/show.html.haml, I have
= button_to "Make Offer", new_listing_offer_path(#listing)
Now, when I click button, rails generate a POST request, and thus an error:
Started POST "/listings/2/offers/new" for 127.0.0.1
ActionController::RoutingError (No route matches "/listings/2/offers/new"):
If I refresh (GET request), then the page displays correctly.
I believe this incorrect routing only happens when I added two extra actions: accept and reject, which happens to be POST actions.
Is it a bug in Rails, or it is my fault? How should I prevent this error?
Thank you.
The button_to helper creates a form for you which by default will send a POST request to the URL you've specified ("/listings/2/offers/new").
The routing you've specified will not generate a route to handle a POST request to /new. You can inspect your generated routes and the verbs to which they will respond by running the "rake routes" task.
If you are looking to merely link to the form, change your "button_to" to a "link_to" and add CSS for aesthetics.
= link_to "Make Offer", new_listing_offer_path(#listing)
(this GET would route to your OfferController's new action)
If you are looking to actually POST data, you will likely need to change your usage to:
= button_to "Make Offer", listing_offers_path(#listing)
(this POST would route to your OfferController's create action.)

Resources