how to change multiple nested routes in rails - ruby-on-rails

i'm doing a course system, and i would like to simplify the routes.
i routed like this:
resources :courses do
resources :modules do
resources :lesson
end
end
and returned this:
/courses/:course_id/modules/:module_id/lesson/:id
/courses/:course_id/modules/:id
/courses/:id
etc...
i want my routes like that:
/courses/:course_name/:module_name/:lesson_name
/courses/:course_name/:module_name/
/courses/:course_name/
etc...
but how?! :(

in the routes file
get "/courses/:course_name/:module_name/:lesson_name", as: :courses
then you should be able to generate the path:
courses_path(course_name: course.name, module_name: module.name, lesson_name: lesson.name)
But I would recommend against it as:
1) This is fighting conventions: don't expect good support for this, none of the new developers who join the project will like you for this.
2) You will have to make sure all course/module/lesson names are unique and url-friendly
3) You'll have to make sure the names never change, because then the urls would change.
I would advice sticking to the default nested paths and overriding #to_param on every module
to smth like:
def to_param
"#{super}-#{name.downcase.gsub(' ', '-')}" # you need a better regex here
end
so the urls look like
/courses/33-computer-science/modules/23-engineering/lesson/56-design-patterns
More about custom routes: http://guides.rubyonrails.org/routing.html#dynamic-segments

Related

Rails 5 - how to add a prefix for a scaffold route?

I have generated a scaffold model car.
So if I want to create a new car, the URL looks like this: /cars/new. I need to pass another information to the URL and the easiest way is to simply add it as a parameter in the end, so the URL would look something like /cars/new?listing=123.
What I am trying to do is to get something like this in the URL: /l/123/cars/new (l = listings). Same for the other actions as well (eg. /l/123/cars/4/edit.
How do I need to modify the routes for such an example? listing is another model, and every listing has a car.
Thank you
AFAIK, you can't achieve this with resourceful way. You have to define non-resourceful routes to achieve what you want. For instance, the route for cars#new would be defined like below
get /:listing_id/:extra_param/cars/new, to: "cars#new"
I think you can use nested resources:
resources :listings do
resources :cars
end
It will generate routes like listings/:listing_id/cars/:id. If you do not have listings controller or you do not want to generate routes for it just use resources :listings, only: [] do ...

Extract params fro url in rails

From the url below how can I extract the value 1?
`http://localhost:3000/category/products/1`
I tried params[:id] and params[:products][:id] but got nothing.
Did you make suitable change in your routes.rb file? You need to include something like
GET /category/products/:id , ...
to make it work with params[:id].
Routes
The direct answer to your question is to fix your routes.rb file
As per the Rails RESTful routing structure, you should be able to use a named scope to achieve this:
#config/routes.rb
scope 'category' do
resources :products
end
#/category/products/1 -> params[:id]
Nested
What I recommended above should fix your problem directly
However, I think you're trying to achieve nested resources. If this is the case, you should use something like this:
#config/routes.rb
resources :categories do
resources :products
end
This will allow you to do:
#categories/:id/products/:product_id

RESTful nested controller in has_one relationship

Say I have a User that has_one ContactInfo.
An unrestful way to edit the contact_info would be to do this all through a single controller with a route of:
myapp.com/users/15/edit_contact_info
A more restful way would be to use two controllers, and route it like this:
myapp.com/users/15/contact_infos/23/edit
However, I don't like this, as the route includes the contact_info_id, which isn't really necessary for identifying the correct contact_info to update. Additionally, the contact_info_id is a confusing number for a user to see. (They may know their own user id, but the contact_info_id will seem like an arbitrary number).
Is there any way to RESTfully route like below:
myapp.com/users/15/contact_infos/edit
or something similar? Is this a bad idea?
resources :users do
get "contact_info/edit" => 'users#edit_contact_info'
end
I'd used a plural route, instead of a singular route. With the singular route, I get myapp.com/users/15/contact_info/edit.
Had:
resources :users do
resources :contact_infos
end
Changed to
resources :users do
resource :contact_info
end

Rails routes, using something other than model_id in resources route

I have some nested resources. Here's an example:
resources :contests do
resources :scoring_periods do
resources :entries
end
end
I'd ultimately like to have a URL that looks like the following:
/contests/1/scoring_periods/10/entries/new
The catch here is that the /10/ in scoring_periods is not the ScoringPeriod#id. It is instead another attribute named period_count in this case. I'd like to be able to reference the period_count in the URl instead of the ID as my system might have millions of IDs later and it's just not intuitive to list it there. The actual period_count number, makes a lot more sense to the users entering this contest.
Is there a way to munge the resources entry in routes.rb in order to allow me to reference scoring_periods by an attribute other than :scoring_period_id ?
Something like this should work:
resources :contests do
scope path: '/scoring_periods/:period_count/' do
resources :entries
end
end

Nesting the same resource in multiple locations in routes

So I am, like many before me, introducing the concept of "liking" items in my app. There are many different types of resources that could be liked (posts, replies, lists, actions etc.), and I am looking for the best way of structuring my routing file.
This may involve making a routes.rb file that looks something like:
resources lists do
resources posts do
resources replies do
resources likes
end
resources likes
end
resources likes
end
and a LikesController that doesn't know what it is meant to be load_and_authorize - ing:
class LikesController < ActionController:Base
load_and_authorize :list # only works if list_id exists in this request
load_and_authorize :post, through: :list # only works if post_id exists in this request
# and so on...
end
Are there any better ways of doing this? I had thought about just having a /likes path that everything posts to, but that means I can't use load_and_authorize, and also means it is harder to sensibly do things like Likes#index for a given list, post, reply, etc.
Thanks.
Instead of nesting Likes inside other resources, try this:
scope "/lists/:list_id(/posts/:post_id(/replies/:reply_id))" do
resources :likes
end
I believe that should get you a single set of LikesController routes which require a :list_id parameter and which optionally take a :post_id and a :reply_id. The url is pretty ugly, but I'm just trying to match the default for a quadruple-nested rails resource route. I recommend cleaning it up a bit.
Edit: It looks like this will also require some additional logic in your LikesController--like a before_filter that detects which params you've got and loads_and_authorizes only those objects. But that seems like a solvable problem to me?

Resources