Nested named routes in rails? - ruby-on-rails

Lets say you have a two models with blog posts and comments set up like this:
class post
has_many :comments
and the routing was set up pretty much the same way:
map.resources :posts, :has_many => :comments
When I go to make a new comment it shows up as localhost::3000/postname/comments/new
What should you do in order to make the url read something like: localhost::3000/postname/shoutout ?
The reason I want to do this is because this particular page will have more than just a new comment form on it.
I have no trouble naming routes but I'm having trouble figuring out what to do with a nested one.

map.resources :posts, :has_many => :comments, :collection => {:shoutout => :get}
Key feature is :collection, which points of pairs: 'name' => 'method', and you need to implement this name in controller (and views)

The routes have nothing to do with the forms that are on the page, I'm not sure what the problem is?
If you want to have /postname/shoutout go to to CommentsController#new you'll need to map the route manually:
map.connect '/:post_id/shoutout', :controller => 'comments', :action => 'new'

Related

Mask URL path on Ruby on Rails

I'm trying to mask the following Route
get '/products/1' => 'products#show', :as => "map"
as hotels/2/map inside my Application, but I'm having no luck. I'm not sure what I'm doing wrong here, as this is already nested inside the Hotels resource. I'm automatically creating two products when the hotel is created, so 1 will be the Map and 2 will be the App.
resources :hotels do
resources :contacts
resources :products
get '/products/1' => 'products#show', :as => "map"
end
What you've got will create hotel_map_path at /hotels/:hotel_id/products/1(.:format). If you instead want map_path without the hotel_prefix, you need to move the map route out of the hotel namespace, like so:
resources :hotels do
resources :contacts
resources :products
end
get 'hotels/:hotel_id/products/1' => 'hotels/products#show', :as => "map"
Hope that helps
edit
I'm gonna revise my suggestion. What you're trying to do will create a dependency between the routes and the details of db storage (the id), which feels wrong. Instead, I'd suggest pushing that dependency into the active_record model, which is the only class that should be responsible for knowing about how Hotels and Products are persisted.
So, your route would be something like:
resources :hotels do
member do
get :map
end
resources :contacts
resources :products
end
which should give you
/hotels/:id/map
in the hotels_controller you'll have
def map
#hotel = Hotel.find(params[:id])
#map = #hotel.location_map
end
and in the Hotel model:
def map
products.location_map
end
and in the Product model:
def location_map
...
end
or add a scope instead.
It's more lines to get the same routing effect, but less brittle.

Can't add sub pages in a controller

Using RoR 2.3.8
This is my cities_controller.rb
class CitiesController < ApplicationController
def show
#city = City.find(params[:id])
...
end
def shops
...
end
def countries
...
end
end
Here's my routes.rb
map.resources :cities, :collection => {:shops => :get, :countries => :get}
The show url for each id is:
http://localhost/cities/1
I want to have some contents shops and countries for each associated id, which I want:
http://localhost/cities/1/shops
http://localhost/cities/1/countries
I can't get the pages showed in empty code in the first place. What have I done wrong?
Thanks.
The :collection option is for when you want to act on the whole collection - so your routes will show up as:
http://localhost/cities/shops
http://localhost/cities/countries
What you want is
map.resources :cities, :member => {:shops => :get, :countries => :get}
Reference: http://apidock.com/rails/ActionController/Resources/resources
Shops and Countries would probably not be methods in the controller but other models. you would want a Countries.rb and Shops.rb
You would then nest the resources like
resources :cities do
resources :shops
end
and you would need a belongs_to :city in the shops model and a has_many :shops in the cities model which would let you access cities/1/shops.... or something like that
However think about the way the data is structured, do countries really belong to cities (which nesting the resources would imply) or would countries contain cities. You would want cities belongs_to :country and so on...
This help?

Is it possible to add more routes when I already did resources :posts

In my routes i have:
resources :posts
now say I want to create a new action/view, is it possible to add it inside a block like:
resources :posts do
// new routes other than the show/new/create/delete/update that REST gives me.
end
Yep
resources :post do
get :action, :on => :member
get 'other', :on => :collection
post :change, :on => :member
resources :another_model
end
note: these are just samples of what you can do and this does assume Rails 3. For more information you should read the Ruby on Rails Guide: Rails Routing from the Outside In
Yes, just add them in. For example, if you want to be able to post to "new_action" you would do
resources :posts do
post "new_action"
end
Have you looked at the Rails Guide: Rails Routing from the Outside In? Section 2.9 Adding More RESTful Actions describes exactly what you're looking for. I frequently refer to the other guides there too.
You can do this for a resource member
resources :posts do
get :preview, :on => member
end
or this for a resource collection
resources :posts do
get :active, :on => collection
end
When I was starting out with rails I was confused about what members and collections were. For a Post resource a member is an individual post while a collection is the collection of all posts. For example...
# url for a member
/posts/5/preview
# url for a collection
/posts/active
The rails guide goes into more detail on routing

Route alias in Rails

I have a model stories in Rails 3.
I want to make an alias "books" for "stories" so I can have routes /books/192 instead of /stories/192, and also that all my generated links (e.g. link_to) point to books' routes instead of stories' routes.
How can I do that?
Thanks
resources :stories, :path => :books
If you want to rename the path AND helper methods, then you do:
resources :stories, :path => :books, :as => :books
See: Overriding the Named Helpers
That's why they made the path option on match which is also available on resources:
resources :stories, :path => "books"
Try something like this:
match 'books/:id' => 'books#show'
match 'books' => 'books#index'

Nested Routes with has_one in rails

G'day guys,
Having a bit of an issue with Rails routes, at the moment.
Have a top resource: /Customer/ which itself has only one /Quote/ resource
Quotes can have both first_resources and second_resources
which are collections of resources associated with the quotes
Building the route, though how do I nest multiple routes under a has_one route?
map.resources :customer, :has_one => :quote
how do I do?
quote.resources :first_resources
quote.resources :second_resources
by mapping them as sub-elements to the substructure?
Or would it be easier to manage the collection in a different way?
for this, I would nest inside of a block:
map.resources :customers do |customer|
customer.resource :quote do |quote|
quote.resources :first_resources
quote.resources :second_resources
end
end
alternative syntax:
map.resources :customers do |customer|
customer.resource :quote, :has_many => [:first_resources, :second_resources]
end
This would give you urls of
customers/:customer_id/quote/first_resources/:id
customers/:customer_id/quote
customers/:id
Or the way you provided I believe you would need to map plural quotes in order to be able to get to a specific quote if you don't want to nest
map.resources :customers, :has_one => :quote
map.resources :quotes, :has_many => [:first_resources, :second_resources]
that would give you urls of
customers/:customer_id/quote
customers/:id
quotes/:quote_id/first_resources/:id
I think the first one is what you are after. Hope this helps.
Resources: http://api.rubyonrails.org/classes/ActionController/Resources.html
map.resources :customers, :has_one => :quote
map.resource :quote, :has_many => :first_resources
map.resource :quote, :has_many => :second_resouces

Resources