Inserting variable into routes - map.resources :posts, :as => X - is this possible? - ruby-on-rails

Ok, so I am working on a blog application of sorts. Thus far, it allows for a user to sign up for their own account, create posts, tags, comments, etc.
I have just implemented the ability to use www.myapp.com/brandon to set #user to find by username and therefore correctly display the users information at each url. So when you go to www.myapp.com/brandon you see all Brandon's posts, tags, and comments associated with those posts, etc. Works great.
I'm implementing this URL mapping through the routes.rb file by adding the following:
map.username_link '/:username', :controller => 'posts', :action => 'index'
And then just setting the #user variable in the PostController and corresponding views to find_by_username. Now the issue is this. Once at www.myapp.com/brandon when you click on a post title, it sends to myapp.com/posts/id without the username in the URL.
How do I tell rails to replace the /posts with /username.
Is it even possible to insert the user_username variable into this code?
map.resources :posts, :as => [what goes here]

You said there's going to be more than just posts on the page? comments and tags too? Sounds like we need some resource aggregation here...
Another concern: what if a user picks the name faq and you want domain.com/faq down the road? You can't possibly know all the URLs you will want in the future. Prefixing paths with /profiles is a great way to build a little "namespace" to prevent this from happening. So...
Why not a ProfilesController?
script/generate controller profiles index show
routes.rb
ActionController::Routing::Routes.draw do |map|
map.resources :profiles, :only => [:index, :show] do |profile|
profile.resources :posts, :only => [:index, :show]
profile.resources :comments, :only => [:index, :show]
profile.resources :tags, :only => [:index, :show]
end
# ...
end
This will give you the following routes
profiles GET /profiles(.:format) {:controller=>"profiles", :action=>"index"}
profile GET /profiles/:id(.:format) {:controller=>"profiles", :action=>"show"}
profile_posts GET /profiles/:profile_id/posts(.:format) {:controller=>"posts", :action=>"index"}
profile_post GET /profiles/:profile_id/posts/:id(.:format) {:controller=>"posts", :action=>"show"}
profile_comments GET /profiles/:profile_id/comments(.:format) {:controller=>"comments", :action=>"index"}
profile_comment GET /profiles/:profile_id/comments/:id(.:format) {:controller=>"comments", :action=>"show"}
profile_tags GET /profiles/:profile_id/tags(.:format) {:controller=>"tags", :action=>"index"}
profile_tag GET /profiles/:profile_id/tags/:id(.:format) {:controller=>"tags", :action=>"show"}
profiles_controller.rb
class ProfilesController < ApplicationController
# show all profiles; profile browser
# /profiles
def index
end
# show one profile
# /profiles/:id
def show
#user = User.find_by_username(params[:id])
end
end
posts_controller.rb (and others)
class PostsController < ApplicationController
before_filter :find_profile, :only => [:index, :show]
# list all posts for this profile
# /profiles/:profile_id/posts
def index
end
# show one post for this profile
# /profiles/:profile_id/posts/:id
def show
end
protected
def find_profile
#user = User.find_by_username(params[:profile_id])
end
end

You should be able to create the link using:
= link_to "User Posts", subdomain_link_url(#user.username, #post)
In your PostController, then, I would use a before_filter to lookup and set the #user variable:
class PostController < ApplicationController
before_filter :find_user
def other_method
# Some code here
end
protected
def find_user
#user = User.find_by_username(params[:username])
end
end

I don't know much about routes and stuff, so forgive me if this doesn't make sense, but doesn't it works for you?
map.resources :posts, :path_prefix => '/:username' do |post|
post.resources :comments
end
I can see here that this will generate the following
posts GET /:username/posts(.:format) {:controller=>"posts", :action=>"index"}
POST /:username/posts(.:format) {:controller=>"posts", :action=>"create"}
new_post GET /:username/posts/new(.:format) {:controller=>"posts", :action=>"new"}
edit_post GET /:username/posts/:id/edit(.:format) {:controller=>"posts", :action=>"edit"}
post GET /:username/posts/:id(.:format) {:controller=>"posts", :action=>"show"}
PUT /:username/posts/:id(.:format) {:controller=>"posts", :action=>"update"}
DELETE /:username/posts/:id(.:format) {:controller=>"posts", :action=>"destroy"}
post_comments GET /:username/posts/:post_id/comments(.:format) {:controller=>"comments", :action=>"index"}
POST /:username/posts/:post_id/comments(.:format) {:controller=>"comments", :action=>"create"}
new_post_comment GET /:username/posts/:post_id/comments/new(.:format) {:controller=>"comments", :action=>"new"}
edit_post_comment GET /:username/posts/:post_id/comments/:id/edit(.:format) {:controller=>"comments", :action=>"edit"}
post_comment GET /:username/posts/:post_id/comments/:id(.:format) {:controller=>"comments", :action=>"show"}
PUT /:username/posts/:post_id/comments/:id(.:format) {:controller=>"comments", :action=>"update"}
DELETE /:username/posts/:post_id/comments/:id(.:format) {:controller=>"comments", :action=>"destroy"}

Related

How to write routes right in Ruby-on-Rails?

In my routes.rb file, I have the following code:
Rails.application.routes.draw do
get 'getTodos', to: 'todos#get'
get 'getUsers', to: 'users#get'
get 'getStates', to: 'states#get'
post 'addTodo', to: 'todos#add'
post 'addUser', to: 'users#add'
delete 'deleteTodo/*id', to: 'todos#delete'
delete 'deleteUsers/*IDs', to: 'users#delete'
delete 'deleteAllTodos', to: 'todos#delete_all'
put 'updateTodo', to: 'todos#update'
end
How can I modify this code to make it more beautiful and correct?
The biggest issue with this code is that its completely unidiomatic. In Rails you create, read, update and destroy (CRUD) resources through the following routes:
HTTP Method Path Controller#Action
GET /todos(.:format) todos#index
POST /todos(.:format) todos#create
GET /todos/new(.:format) todos#new
GET /todos/:id/edit(.:format) todos#edit GET /todos/:id(.:format) todos#show
PATCH /todos/:id(.:format) todos#update
PUT /todos/:id(.:format) todos#update
DELETE /todos/:id(.:format) todos#destroy
The key here is the combination of the HTTP method and path.
GET /todos gets you all the todos while GET /todos/:id shows you a specific resource.
GET /todos/new displays the form to create a new todo. POST /todos actually creates the resource from a form submission.
GET /todos/:id/edit displays the form to edit a todo. PATCH /todos/:id actually updates the resource from a form submission.
DELETE /todos/:id - You should be able to guess what this does.
You can generate these routes with:
Rails.application.routes.draw do
resources :todos
end
If you want to define a routes that deletes all the todos RESTfully it should be defined as DELETE /todos (without an id).
Rails.application.routes.draw do
resources :todos do
delete '/', on: :collection, action: :destroy_all
end
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
See:
Rails Routing from the Outside In
I would do something like this. Try to use default Rails REST actions instead of overwriting them
Rails.application.routes.draw do
resources :todos, only: [:index, :create, :update, :destroy] do
collection do
delete :delete_all, to: 'todos#delete_all'
end
end
resources :users, only: [:index, :create, :destroy]
resources :states, only: :index

Routes on Rails application are failing

I'm taking an MOOC and the goal of this exercise is to add a new functionality to typo, where i can merge two articles together.
When I add the route to my new function merge to the routes.rb I'm losing the functionality to delete articles. I think something clashes here, but I have no idea what.
The original routes.rb:
%w{advanced cache categories comments content profiles feedback general pages
resources sidebar textfilters themes trackbacks users settings tags redirects seo post_types }.each do |i|
match "/admin/#{i}", :to => "admin/#{i}#index", :format => false
match "/admin/#{i}(/:action(/:id))", :to => "admin/#{i}", :action => nil, :id => nil, :format => false
end
This method in articles.rb creates the correct url for deleting
def delete_url
blog.url_for(:controller => "/admin/content", :action =>"destroy",:id => id)
end
correct url:
http://example.com/admin/content/destroy/7
If i follow this link i can successfully delete an article.
However, if I add the following before that to my routes.rb:
namespace "admin" do
resources :content do
post :merge, on: :member, as: :merge
end
end
The new merging functionality and forms are working fine, but the method delete_url now produces something like this:
http://example.com/admin/content/7
and if I follow a link created by this method i get:
Unknown action
The action 'show' could not be found for Admin::ContentController
Maybe I'm overwriting something? I can't figure out what's happening here and why this affects the delete action / route.
Thanks in advance!
EDIT: rake routes | grep content:
with the original routes.rb gives me:
admin_content /admin/content {:controller=>"admin/content", :action=>"index"}
/admin/content(/:action(/:id)) {:action=>nil, :id=>nil, :controller=>"admin/content"}
whereas my modified routes.rb produces
merge_admin_content POST /admin/content/:id/merge(.:format) {:action=>"merge", :controller=>"admin/content"}
admin_content_index GET /admin/content(.:format) {:action=>"index", :controller=>"admin/content"}
POST /admin/content(.:format) {:action=>"create", :controller=>"admin/content"}
new_admin_content GET /admin/content/new(.:format) {:action=>"new", :controller=>"admin/content"}
edit_admin_content GET /admin/content/:id/edit(.:format) {:action=>"edit", :controller=>"admin/content"}
admin_content GET /admin/content/:id(.:format) {:action=>"show", :controller=>"admin/content"}
PUT /admin/content/:id(.:format) {:action=>"update", :controller=>"admin/content"}
DELETE /admin/content/:id(.:format) {:action=>"destroy", :controller=>"admin/content"}
/admin/content {:controller=>"admin/content", :action=>"index"}
/admin/content(/:action(/:id)) {:action=>nil, :id=>nil, :controller=>"admin/content"}
Okay, thanks to #guitarman i worked through my routes code and found out I can add the following except:
namespace "admin" do
resources :content, except: [:index, :show, :update, :destroy, :edit, :new, :create] do
post :merge, on: :member, as: :merge
end
end
after that, the rake routes just shows the additional merge route I wanted and my destroy action works fine again.
Check rake routes command. I think there is a route /admin/content/:id which will be created by resources :content in the namespace "admin".
Your request to http://example.com/admin/content/7 will be catched be the defined route but I gess you have no show action in the controller.
Better:
namespace "admin" do
post "/content/:id/merge", to: "admin/content#merge", as: :merge
end
For more information about recources and the CRUD operations please see the rails routing guide.

Rails Route Redirecting to different view by default

The following is my routes.rb
Rails.application.routes.draw do
resources :admin do
post 'user_creation', on: :collection
end
get 'admin/user_creation'
resources :admin, :only => [:user_creation, :create, :new]
end
the following is my controller
class AdminController < ApplicationController
def new
#dashboard_user = DashboardUser.new
end
def create
#dashboard_user = DashboardUser.new(dashboard_params)
#dashboard_user.save!
end
def user_creation
end
private
def dashboard_params
params.require(:dashboard_user).permit(:user_name, :password, :last_name, :first_name, :middle_name , :phone)
end
end
then its a simple .html.erb file
what happens is that when i try to open the link admin/user_creation it automatically redirects to show.html.erb file
rake routes output
rake routes
Prefix Verb URI Pattern Controller#Action
user_creation_admin_index POST /admin/user_creation(.:format) admin#user_creation
admin_index GET /admin(.:format) admin#index
POST /admin(.:format) admin#create
new_admin GET /admin/new(.:format) admin#new
edit_admin GET /admin/:id/edit(.:format) admin#edit
admin GET /admin/:id(.:format) admin#show
PATCH /admin/:id(.:format) admin#update
PUT /admin/:id(.:format) admin#update
DELETE /admin/:id(.:format) admin#destroy
admin_user_creation GET /admin/user_creation(.:format) admin#user_creation
POST /admin(.:format) admin#create
GET /admin/new(.:format) admin#new
root GET / admin#new
You are clicking the link for the url. admin/user_creation
But your route says it is a POST url .
It need to added as GET.
Rails.application.routes.draw do
resources :admin do
post 'user_creation', on: :collection
get 'user_creation', on: :collection
end
get 'admin/user_creation'
resources :admin, :only => [:user_creation, :create, :new]
end
Your route not looking good. Whenever we try to go to any url directly from browser it consider request as get type. routes file try to find route from top to bottom. That why it's considering /admin/user_creation as show action of admin_controller and user_creation as id to show.
Don't know why you need get and post request for same action. But your routes should look like this:
Rails.application.routes.draw do
resources :admin, :only => [:create, :new] do
post 'user_creation', on: :collection
get 'user_creation', on: :collection
end
end
One thing with above routes there is no route for show action. Now you will properly go to user_creation path.
if you don't need any post path then it should look like:
Rails.application.routes.draw do
resources :admin, :only => [:create, :new] do
get 'user_creation', on: :collection
end
end
if you need all the default action then:
Rails.application.routes.draw do
resources :admin do
get 'user_creation', on: :collection
end
end

Namespaced controller without having to name space route helpers

Is it possible to reference app/controllers/admin/categories_controller.rb using categories_path instead of admin_categories_path ?
I'm using Rails 4.
# app/controllers/admin
class Admin::CategoriesController < Admin::BaseController
end
# visiting localhost:3000/admin/categories causes route not found error 'admin/categories'
scope module: "admin" do
resources :categories
end
# visiting localhost:3000/admin/categories causes uninitialized constant CategoriesController
scope "/admin" do
  resources :categories
end
I believe that you have to reference the controller at the resources
scope 'admin' do
resources :categories, controller: 'admin/categories'
end
so the routes became
categories GET /admin/categories(.:format) admin/categories#index
POST /admin/categories(.:format) admin/categories#create
new_category GET /admin/categories/new(.:format) admin/categories#new
edit_category GET /admin/categories/:id/edit(.:format) admin/categories#edit
category GET /admin/categories/:id(.:format) admin/categories#show
PATCH /admin/categories/:id(.:format) admin/categories#update
PUT /admin/categories/:id(.:format) admin/categories#update
DELETE /admin/categories/:id(.:format) admin/categories#destroy

Rails route which disappears in application but is present in rake routes

I have a mystic problem....
In my routes.rb I have some routes defined and for exemple
resources :projects, :except => [:destroy] do
get :edit_flyer, :on => :member
get :guests, :on => :member
end
If I run a rake routes, I get
edit_flyer_project GET /projects/:id/edit_flyer(.:format) {:controller=>"projects", :action=>"edit_flyer"}
guests_project GET /projects/:id/guests(.:format) {:controller=>"projects", :action=>"guests"}
GET /projects(.:format) {:controller=>"projects", :action=>"index"}
projects POST /projects(.:format) {:controller=>"projects", :action=>"create"}
new_project GET /projects/new(.:format) {:controller=>"projects", :action=>"new"}
GET /projects/:id(.:format) {:controller=>"projects", :action=>"show"}
project PUT /projects/:id(.:format) {:controller=>"projects", :action=>"update"}
edit_project GET /projects/:id/edit(.:format) {:controller=>"projects", :action=>"edit"}
As you can see, the show action is defined.
But in my rails applications, the route show is not defined.
I add this in my application controller just to monitored the routes.
before_filter :zba
def zba
ActionController::Routing::Routes.named_routes.routes.each do |name, route|
puts "%20s: %s" % [name, route]
end
exit
end
And it appears that the route action is not defined ....
Then, I tryed to clean my routes.rb, like removing all my back namespace, and magically it works.
It seems to be a bug, or I don't know what appened.
Have you any idea how to debug this ? I also tryed to remove plugin/gems. No change.
I run with Rails3.rc with ruby 1.8.7 !
Thanks for your help !
Try this
resources :projects, :except => [:destroy] do
member do
get :edit_flyer
get :guests
end
end

Resources