Rails routing like github - ruby-on-rails

I am using Rails 3.2
I want to have routing pretty much exactly like github, so:
root/(username)
root/(username)/(projectname)
root/(username)/(projectname)/issus
etc.
I am trying something like this:
resources :publishers do
resources :magazines do
resources :photos
end
end
But that gives routes like this:
/publishers/1/magazines/2/photos/3
A project I am looking at does the following which seems to work but does not seem to be for me.
resources :projects, :constraints => { :id => /[^\/]+/ }, :except => [:new, :create, :index], :path => "/" do
member do
get "team"
get "wall"
get "graph"
get "files"
end
resources :wikis, :only => [:show, :edit, :destroy, :create] do
member do
get "history"
end
end

If you want to get rid of the id number (which is rails default) and use a name I suggest the FriendlyId gem.
watch this railscast http://railscasts.com/episodes/314-pretty-urls-with-friendlyid
and here is the github page https://github.com/norman/friendly_id
EDIT
This is the article I was looking for, I forgot I bookmarked it months ago.
http://jasoncodes.com/posts/rails-3-nested-resource-slugs

You must to use friendly_id and scope
scope '/:username/:projectname', module: 'users/projects', as: 'users_project' do
resources :issus
resources :photos
end

Related

Named routes for nested resources

I'm actually having trouble finding the documentation for this so if you have a link handy that would be really appreciated too.
So I have:
resources :users do
resources :posts, only: [:index, :create, :show]
end
I wanted to access the index action of posts through a named route. I tried this: <%= link_to 'User Posts', user_posts_path %> but it said it was missing user_id. Any ideas?
When using the nested resource routes, you would need to provide the reference id of the parent resource. In your case resource user. You could do: user_posts_path(user). The route generated would be something like: /users/1/posts where 1 is the :user_id or if you would rather want a route like: /users/posts you should do:
resources :users do
collection do
resources :posts
end
end
Find full routing documentation here
it's asking for user_id because you're defining :users as a resource, change it for a namespace instead:
namespace :users do
resources :posts, only: [:index, :create, :show]
end

Trouble with routing for my semi-static pages

I'm trying to implement semi-static pages as per this railscast
At first I named my class 'About', but that threw the following error:
Invalid route name, already in use: 'page' (ArgumentError)
You may have defined two routes with the same name using the :as option, or you may be overriding a route already defined by a resource with the same naming.
After some googleing, it seemed like it was conflicted with active_admin for some reason, so I rename the table to 'Page' and I've carefully renamed all the appropriate files, classes and methods etc. from 'About' to 'Page'
This is my Page model:
class Page < ActiveRecord::Base
validates_uniqueness_of :url
def to_param
url
end
end
And these are my routes:
get 'signup', to: 'users#new', as: 'signup'
get 'login', to: 'sessions#new', as: 'login'
get 'logout', to: 'sessions#destroy', as: 'logout'
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
resources :users
resources :sessions
resources :password_resets
resources :posts do
resources :comments
resources :votes, only: [:new, :create]
resources :flags, only: [:new, :create]
end
resources :comments do
resources :comments
resources :votes, only: [:new, :create]
resources :flags, only: [:new, :create]
end
resources :newsletters
resources :pages, except: :show
resources :subscribers, only: [:index, :new, :create]
# resources :prelaunch
# get 'about', to: 'prelaunch#about'
root to: 'posts#index'
get ':id', to: 'pages#show', as: :page
I'm still getting the same error as described above.
The only way I can get it to half-work is by dropping the 'as: :page' bit, which stops the conflict, and hardcoding the url I want to point to into the code e.g.
<%= link_to page.name, "localhost:3000/#{page.url}" %>
which is far from ideal.
I can't find any help in Routing from the Outside In.
Could anyone help?
Here's the fix:
#config/routes.rb
resources :pages, except: :show
(remove get ':id', to: 'pages#show', as: :page)
This will create the standard RESTful routes, which will create a routing structure except the show action
Slugs
How to create app-wide slug routing for Rails app?
If you want to have /about etc, you'll have to generate them specifically:
#config/routes.rb
if Page.all.any?
Page.all.each do |page|
get page, to: "pages#show", id: page.id
end
end
This can also be handled with friendly_id
Have you considered using a gem that "does the work for you"? I've been using the https://github.com/thoughtbot/high_voltage gem to take care of static pages for me, without any hassle. It takes care of both routing and controller, only leaving the creation of the pages in a dedicated view/pages folder. Linking to a static page is as simple as creating a link to page_path(:name_of_the_page)
Ok, after a lot of hacking around and a helpful pointer from Rich Peck, I've got a working solution.
Routes:
resources :pages, except: :show
if Page.all.any?
Page.all.each do |page|
get "#{page.url}", to: "pages#show", as: "#{page.url}", id: page.id
end
end
Controller:
def show
#page = Page.find(params[:id])
end
Note, I've used the friendly_id gem as suggested.
To dynamically generate links:
Application controller:
def about_us
#pages = Page.all
end
helper_method :about_us
Pages helper:
def about_link(page)
link_to page.name, "/#{page.url}"
end
NB: - you need to include the / otherwise it will try to prepend the name of the controller for the page you're on (I'm not sure why).
My footer:
<% about_us.each do | page | %>
<%= about_link(page) %>
<% end %>
UPDATE:
I've had a lot of trouble deploying my app to Heroku, and I believe it's because of the pages routes.
I've now changed to a much simpler solution:
resources :pages, path: ""
and the problem's have gone away.

Rails routes with polymorphic and owner relationships

I have a rails app where Users can create Programs and other things yet to come, we'll say Plans (hypothetically).
Users can also like Programs and Plans. (Like is polymorphic)
I am trying to figure out routes so I can see the Programs a User creates, all the things a User likes, or just Programs or just Plans a User likes.
I have these routes, but this doesn't seem to be right.
resources :users, :only => [:index,:show] do
resources :programs, :only => [:index]
resources :likes, :only => [:index] do
resources :programs, :only => [:index]
end
end
The route for programs that a user likes requires a URL like: users/user_id/likes/like_id/program.
How do I create a URL like: users/user_id/likes/programs and get all programs that are liked.
I am using the Socialization Gem which has a method for "likeables_relation(Class)" which returns a relation of whatever class is requested. I just need help with the routing.
I've just tried with the following routes:
resources :users, :only => [:index,:show] do
resources :programs, :only => [:index]
resources :likes, :only => [:index] do
collection do
get :programs
end
end
end
and the
http://localhost:3000/users/1/likes/programs
works fine.
It required adding a new action 'programs' to the LikesController class.
This is what rake routes returns:
programs_user_likes GET /users/:user_id/likes/programs(.:format) likes#programs

Renaming path helpers in Rails 3 routing

I have a projects controller/model. Instead of listing projects on the #index page, I show a list of drop downs, which submits to projects#select, which finds the right Project (I've made sure there can only be 1 for each combination of options) and forwards the user to the #show page for that Project.
So for my routes I do this...
resources :projects, :only => [:index, :show] do
collection do
get 'select'
end
end
And thats fine, but the helper method for #select is 'select_projects', which is understandable but in my case I really want 'select_project'. And I really don't want to alias this in another file. No problem I can use :as...
resources :projects, :only => [:index, :show] do
collection do
get 'select', :as => 'select_project'
end
end
But now my helper is 'select_project_projects'. So I cheat a little (still better than aliasing in another file)...
resources :projects, :only => [:index, :show]
match '/projects/select', :to => 'projects#select', :as => 'select_project'
This looks like it might work, but it doesn't because /project/select actually matches the route for 'project#show'. Changing the order of the lines does the trick.
match '/projects/select', :to => 'projects#select', :as => 'select_project'
resources :projects, :only => [:index, :show]
But is there a more elegant way of handling this? I realize this is borderline OCD, but I'd like to be able to have complete control over the route name within the resources block.
use resource instead of resources
you probably don't want to make it a collection route but a member route:
resources :projects, :only => [:index, :show] do
member do
get 'select'
end
end
This way you'll have the select_project helper.
For those that want to rename the helper method side of things (as the title suggests):
resources :posts, as: "articles"

Namespaced resources

This is an excerpt from my config/routes.rb file:
resources :accounts do |account|
account.resource :profile, :except => [:new, :create, :destroy]
account.resources :posts,
:collection => { :fragment => :get },
:has_many => [:comments, :likes]
# even more code
end
I would like that each nested resource to be loaded from from the account namespace such as Account::PostsController instead of PostsController.
Using resources :accounts, :namespace => 'account' tries to load AccountPostsController.
Trying to nest the structure doesn't really work all that well:
map.namespace :account do |account|
..
end
The previous code will load the files from the locations I want, however it does add the namespace to the url and the generated paths so I'll have methods such as account_account_posts_url and similar paths.
Another alternative is to use something like:
account.resource :profile, :controller => 'account/profile'
I really don't like this as it involves both code duplication and forces me to remove some of the rails magic helpers.
Any thoughts and suggestions?
Changing my routes.rb and running rake routes I came up with the following:
map.resources :accounts do |accounts|
accounts.namespace :account do |account|
account.resource :profile, :except => [:new, :create, :destroy]
end
end
This gets you what you want. The correct url and pointing to account/... controller.
See Rails Routing for more detailed info and options on what can be done with Rails Routes.
So what's specifically wrong with namespacing? I think this is what you're trying to do:
map.namespace :account do |account|
account.resource :profile
end
This will try to load the controller at app/controllers/account/profiles_controller.rb and will generate routes such as account_profile_path.
Updated based on comment:
map.resources :accounts do |account|
account.resource :profile
end
Will give you /accounts/22/profile.

Resources