Correctly mapping rails url - ruby-on-rails

I have a controller in a subdirectory called fridges (the higher-level directory it is in is called categories). I have made an index page for the fridges controller and it works correctly when I navigate to "categories/fridges/index". However, it doesn't work when browsing to 'categories/fridges' as I want it to.
Here is how it is being routed in the route config:
map.namespace :categories do |categories|
categories.resources :fridges
end
What should I be doing to make the index page appear when navigating to the url 'categories/fridges' ?

In Rails 3, you can do:
namespace 'category' do
match '/fridges' => 'fridges#index'
resources :fridges
end
A similar approach can be taken for Rails 2.x. What you are looking for is the match '/fridges' => 'fridges#index', which should be defined in your namespace.
Hope that helps!

Related

Nested routes in rails

I am someone who has always liked sinatra better than rails, and has never had to do a large enough scale project that rails was required (all the sources I have read say that rails is better for larger scale projects) and now I do have to do a large scale project. I have gotten very confused with the url structure of rails. What I am trying to do is the rails equivalent of this:
get "/" do
erb :index
end
get "/home" do
erb :dashboard
end
get "/home/profile" do
erb :profile
end
get "/home/friends" do
erb :friends
end
In the first one I understand that I should put in app/routes.rb I should put root home#index and in the home controller I should put def index end.
In the second one, I understand that I should do the same except replacing index with home.
But for the third and forth ones I have no idea what to do.
Also, is the a RESTful way to do the first two?
You probably want something like this
root 'home#index'
get 'home' => 'home#dashboard'
get 'home/profile' => 'home#profile'
get 'home/friends' => 'home#friends'
remember to use the command rake routes to see all your routes, where they lead and what their names are (if they have any)
I never understood what RESTful means, so someone else will have to answer that part of your question.
K M Rakibul Islam has shown you what can be called a "resourceful" way to do routes (because it uses the keyword resources) but it looks like you're just doing the static pages at this stage, so it's not necessary.
The simplest way to do routes is with this formula:
method url => controller::action, as: route_name
where method can be get, post, patch or delete so you can have different actions linked to the same URL depending on the method the request uses.
Putting a name on the route is optional, but it gives you a clean way to use the route in your views (route_name_path)
When you start making models then you'll find that using the resources keyword comes in handy. Read about it.
You can have this:
resources :home do
collection do
get :profile
end
collection do
get :friends
end
end
end
This will give you routes like this:
profile_home_index GET /home/profile(.:format) home#profile
friends_home_index GET /home/friends(.:format) home#friends
The standard way of declaring the root path:
root 'home#index'
And for the 2nd one, you have to do:
get 'home' => 'home#dashboard'
which will give you this route:
GET /home(.:format) home#dashboard
One route can be defined in many ways that works. But, Rails has conventions that should be followed while defining routes in your Rails app.
I would highly recommend you to take a look at the Rails Routing Guide

Understanding routing with rails

I am trying to make a stupid simple CMS for one of my clients using rails. I generated scaffolding for Page and have been successful at creating and rendering those pages, however, the routing is ugly.
Right now, if I want to view the home page, I get a url like this: example.com/pages/1
I'd like to accomplish 2 things:
How do I set the routing so that example.com automagically grabs the page named "home"
and
How do I set the routing so that example.com/page/page_name performs a
#page = Page.find_by name: 'page_name'
Q1:
How do I set the routing so that example.com automagically grabs the page named "home"
In `routes.rb:
root :to => '[controller]#[action]'
#'pages#home' for example, if your home page is in `pages_controller`
# and uses the `home` action
Q2:
How do I set the routing so that example.com/page/page_name performs a
#page = Page.find_by name: 'page_name'
match '/page/:name', :to => 'pages#some_name', :as => :some_name
this would generate the following in $rake routes:
some_name /page/:name(.:format) pages#some_name
when you link to (or redirect, or otherwise access) this page, you'd write
link_to "click this link!", some_name_path(#SomeModel.some_name)
To accomplish the first thing you need to open the file routes.rb which is in the config folder and add the following:
root to: "home#index"
I'm assuming you have a controller named home which contains a method called index and this is the one that displays the home page.
If you want to make it the same as example.com/pages then you would have to use
root to: "pages#index"
to make a general rule you need to use
root to: "controller#method"
Don't forget to remove the index.html from the public folder too.
I recommend you make the blog application presented here:
http://guides.rubyonrails.org/getting_started.html
It can help you understand more.
Here's a solution that assumes your controller is named pages_controller instead of page_controller.
Add these routes in config/routes.rb:
root to: 'pages#show', page_name: 'home'
get 'pages/:page_name', to: 'pages#show'
For the controller app/controllers/pages_controller.rb:
class PagesController < ApplicationController
def show
#page = Page.find_by(name: params[:page_name])
end
end
Note: In rails4 the find_by dynamic finders have been deprecated... so if you're app is on 4 you should look into updating them. These docs have further details.
Also, if you're just trying to get static looking urls then I would definitely go with Marian Theisen's suggestion and use friendly_id.

Rails view template path loading seems incorrect

I have a problem where Rails is searching an additional subdirectory based on the controller path. Is there a way to get rails to stop searching one extra subdirectory? I kind of like the directory structure that I have now. Here's the details:
Rails will return this error message. As you can see, it's going for v1 twice:
Template is missing
Missing template api/v1/v1/print
I have a controller in app/controllers/api/v1/v1_controller.rb and a view in app/views/api/v1/print.html.erb
The specific route in config/routes.rb is (semi-truncated):
namespace :api do
scope module: :v1 do
match "v1/print",
:to => "v1#print"
end
end
Based on the routes, it looks OK. Rake routes show this:
api_v1_print GET|POST /api/v1/print(.:format) api/v1/v1#print {:format=>"html"}
Why is it going one directory too deep?
The problem is that Rails assumes there's a subdirectory per each controller. The duplication is formed since you have v1 in the module and in the controller name. I wouldn't go against Rails' conventions. Instead I would change the name of the controller to API controller (or something similar) and put the templates under the directory called API.
In case you still want to do this, simply use render within your print action and specify the exact file you'd like to use (see here)
just remove the v1 from the match, like this:
namespace :api do
scope module: :v1 do
match "print",
:to => "v1#print"
end
end
EDIT
sorry, the problem is in your template folder.
app/views/api/v1/print.html.erb
app/views/(namespace)/(module)/(action) <- you have forgoten the controller
the right one would be:
app/views/api/v1/v1/print.html.erb

Custom urls and paths in rails

I have two models: Books and pages in a typical one_to_many relationship.
How can I make the following
page_path(#page)
output this path:
bookname/page/pageid
instead of
page/pageid
If I override the to_param, all I can do is make a path like localhost/page/bookid/pageid but that's not what I want.
Not sure if it's possible to get exactly what you want, but you can make the Page a nested resource under book like this:
resources :books do
resources :pages
end
Then you will get:
localhost/book/bookid/page/pageid
Then you can override `to_param' to get:
localhost/book/bookid-bookname/page/pageid
I'm assuming you mean to have path as /:book_name/page/:id
In routes.rb:
match '/:book_name/page/:id' => "page#show", :as => :page
In the controller you would access params[:id] to get page.id and params[:book_name] to get the name of the book.
I discovered that to have full control over path helpers, you have to override those inside the application_helper.erb file. The following code worked for me:
def pages_path(#page)
#bookpath = Book.find(#page.book_id)
#bookpath + '/page/' + #page.id
end
The helper only creates the path. You still need to link it to a particular action in routes.rb. You may even nest the pages resource inside the books resource. The only important thing is that the path generated by the above helper must be recognizable by the rails application.

How to remove controller name in REST design in Rails3?

Given a User resource, it goes like this
/user/:shortname
But how can the controller name be removed to get just
/:shortname
How can I declare this in routes.rb while keeping all CRUD functionality instant?
Updated: After reading this I'm moving to Sinatra over Rails to handle this API-like design better.
Define a custom match:
match ':shortname' => 'users#action'
Replace action in users#action with the name of the action that is supposed to receive the request. Just remember to place it in the appropriate order in your routes file. Rails looks at each line of your routes file starting at the top and selects the first matching route. ':shortname' would match any first-level path, including /users! So put it below any routes using a first-level path, which would include all of your resource routes. Here's an example:
resources :users
resources :posts
match '/blog' => 'posts#index'
match ':shortname' => 'users#action'
In routes, you should be able to do something like
resource :users, :path => '/:shortname'
Try that out and rake routes to see if that comes out as expected.

Resources