Rails Routing from a plural to singular resource - ruby-on-rails

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)

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).

RoR Routes: Why does the app assume I want the show action with every URL?

So, I'm trying to access other actions in my controller, and it assums I want "show" every time, when I really just want... the action I just had in my URL.
this is in my routes:
map.resources :attachments
And when I do
domain/attachments/any_action?params
I get this error:
ActionController::UnknownAction (No action responded to show. Actions: {list of actions}
Using rails 2.3.8
I think I know what you are getting at.
Yes show is assumed for singular uses and index for plural.
This is a convention.
Much of the power / magic in rails comes from "convention over configuration" and this is one of them. Yes it could have been /attachment/show/ or /attachments/index but why not just eliminate the show and index if these are the most common and have them available as defaults and that is what rails does.
Now, as for actions not being available, lets look at that. First of all, right off the bat, please do a rake routes at the command line and see what you get. Also please indicate which actions you are trying. The restful setup "resources" will make 7 actions available:- index, show, new, create, edit, update and destroy, but not "any action"
The rule in Rails is first route matched, first route served.
Because you define a resource, it will consider everything like domain/attachments/whatever to be show action for the whatever stuff.
So two choices here:
define your other routes and declare them before the resource
nest your other routes inside the resource (I don't know how to do that in Rails 2.x)

Why is the scaffold generating routes like this? Why do they work?

The book "Agile development with Rails" shows in the second chapter, that you can say:
<%= link_to "Goodbye",say_goodbye_path %>
Instead of hardcoding the path to "/say/goodbye". Makes sense, I thought to myself. Probably Ruby is splitting the say_goodbye_path by _, assigns the first part as the controller name, the second part as the action name. But, afterwards, I generated the following scaffold:
rails generate scaffold User name:string mail:string
And I noticed in the index.html.erb view, that it had methods like: edit_user_path(user). I tried to rewrite it to user_edit_path(user), but of course, it didn't work. My question is, why are the scaffold links the other way around? How would I know if I should write them in the way the author uses them in link_to, or in the way they are generated by the scaffold. Can you shed some light on this?
The helper functions like user_edit_path are automatically generated by rails to map operations on resources to the matching routes and thus HTTP paths and HTTP verbs. You have to understand that you are dealing with resources here, not necessarily with simple controllers.
While most of the time your resources can map to a single controller, it doesn't have to be that way. You can have nested or combined resources which can result in rather complex routing definitions.
Resources are typically defined by giving it a name (userin this case) and defining some allowed operations on them. Rails encourages to follow the REST pattern there, so you can have shortcuts to have some operations pre-defined. One of them is edit, which by default matches to a GET request to users_controller#edit. Default operations on RAILS resources are:
HTTP verb path matching controller action
===================================================
GET /users #=> index
GET /users/1 #=> show
GET /users/new #=> new
GET /users/1/edit #=> edit
PUT /users/1 #=> update
POST /users #=> create
DELETE /users/1 #=> destroy
These mappings can be customized on your routes.rb (changing methods, adding or removing operations, ...) Generally you are encouraged to use the default mappings as these are supported by standard helpers and make your app easier to understand.
Scaffolds are code generated by a template which is not related to the routing.
Routing is based on the route.rb in your config folder. All resources are routed by default (when generated by scaffolds) but there's a default rule /:controller/:action/:id that you can enable. Think of a "catch all" case.
One way to see what routes to have is to edit route.rb and run rake routes and see how they change. There's an official guide here too: http://guides.rubyonrails.org/routing.html

Can someone please explain to me in clear, layman's terms what the deal is with mapped resources and named routes in Ruby on Rails?

I've been using Ruby for the first time on a project at my work, so I am still somewhat learning the ropes (and loving every minute of it).
While I understand the point of the map.connect functions in the route.rb file, I don't understand the "resources" and "named route" features of Rails. I have my Rails book here and read it over several times, but I still don't get it. The named routes I kinda get - I think that they are either rules, either explicitly defined, or calculated by a code block, but the resources are a complete mystery to me; the only thing I've gleamed rom them is that you just NEED them if you want some of the cool stuff to work, such as being able to call 'resource_path' (and its awesome related family of methods).
My current project has:
map.resources :application_forms
map.resources :sections
map.resources :questions
map.resources :seed_answers
map.resources :question_types
map.resources :form_questions
map.resources :rules
map.resources :form_rules
..but my Rails book has this awesome kinda "has_many" and "only" type hashes and parameters hanging off them and I can't work out exactly when I am supposed to use them, nor what the benefit is.
Can anyone set me straight?
Named routes are just that; a route with a name attached, so that you can easily refer to it when you want to generate a URL. Among other things, it can eliminate ambiguity.
A resource is basically a 'thing' that you want to have routes to manipulate. When you define that 'sections' is a resource, what you're doing is saying "I want a route to get all the sections. I want a route to add a new section. I want a route to edit an existing section. I want a route to delete a section." That sort of thing. These routes point to standardized method names like index, new, edit, and so on. Each of these routes will have a name assigned based on what it is; so there is now a route named 'edit_section'.
The :has_many parameter lets you say that a certain kind of thing has sub-things. For example, you can say map.resources :sections, :has_many => [:questions]. This means that a question belongs to a section, and this will be reflected in the url and the route. You'd get urls like '/sections/27/questions/12' and named routes like 'section_questions'.
The :only parameter says "only make routes for these actions"; you could use it if you only want to allow listing, viewing, and adding items, not editing or deleting.
Honestly the Rails Routing Guide will give you a good explanation in about as plain wording as you can get. Just know that a resource route == RESTful route and you're good to go.
We all struggled with understanding resources and REST when DHH introduced it to the Rails community at the first RailsConf in 2006, so it is not wonder you have trouble grasping the concept.
I admit there is much better and more up-to-date explanations of the concepts today, but back then, right after David's keynote, I wrote a blog post in which I, from discussion with other conference attendees, tried to understand and explain it. It might help you, as it doesn't take for granted that you know everything about REST as more recent articles do.

Resources