Rails routing for namespaced resource deletion - ruby-on-rails

I have a page model and a pages_controller within an admin namespace. My routes file looks like this:
map.resources :pages, :only => [:index,:show]
map.resources :admin, :only => [:index]
map.namespace :admin do |admin|
admin.resources :pages
end
I am not able to figure out the correct method to create a link for deleting a page (In the same way the scaffold generator generates a delete link on the index page).
Any ideas on the correct parameters for the link_to function?
TIA,
Adam

rake routes is your friend here. It'll spit out the list of your generated routes - particularly useful if you have a bunch of nested or custom routes.
the paths will be
admin_pages_path #(with GET) routes to :controller => 'admin/pages', :action => 'index'
admin_pages_path #(with POST) routes to :controller => 'admin/pages', :action => 'create'
new_admin_page_path #(with GET) routes to :controller => 'admin/pages', :action => 'new'
edit_admin_page_path(:id) #(with GET) routes to :controller => 'admin/pages', :action => 'edit'
admin_page_path(:id) #(with GET) routes to :controller => 'admin/pages', :action => 'show'
admin_page_path(:id) #(with PUT) routes to :controller => 'admin/pages', :action => 'update'
admin_page_path(:id) #(with DELETE) routes to :controller => 'admin/pages', :action => 'delete'
Your link_to for delete should therefore be:
<%= link_to("delete page", admin_page_path(#page), :confirm => "sure you want to delete this page?", :method => :delete) %>
Note that Rails will work its magic calling to_param on #page, so that you don't have to specify #page.id - useful for an example like this as you often want to use permalinks for 'pages'.

Related

Contact us gem route conflict - Rails 4

I am getting this error: ActionController::UrlGenerationError in ContactUs::Contacts#new, using this gem https://github.com/jdutil/contact_us .
The error: No route matches {:controller=>"contact_us/pages", :action=>"home"}
Where the error is occurring:
.col-xs-8
%ul
%li
= link_to "Home", :controller => 'pages', :action => 'home'
%li
= link_to "About", :controller => 'pages', :action => 'about'
%li
My routes:
devise_for :users
resources :available_times
root :to => "pages#home"
get 'about' => 'pages#about'
get 'pricing' => 'pages#pricing'
get 'users/my-bookings' => 'available_times#index'
get 'users/x34' => 'available_times#create'
get 'users/test_func/:id/:time' => 'available_times#test_func'
Gem routes
Rails.application.routes.draw do
resources :contacts,
:controller => 'contact_us/contacts',
:only => [:new, :create]
get '/contact-us' => 'contact_us/contacts#new', :as => :contact_us
end
Looks like you have a scoping issue. The view is rendered in the contact_us scope and calling a controller in that scope will have it look for it in contact_us/ rather than the entire app. I'm no big fan of using the :controller => 'pages', :action => 'home' for routes generation directly, try and use the path helper instead. It will probably work better.
= link_to "Home", root_path
= link_to "About", about_path
In routes:
get 'about' => 'pages#about', as: :about

Rails: Mapping Conflicting Routes by Detecting Param

Hey! I am trying to set up routes in a Rails application so that, depending on the type of parameter passed, Rails sends the request to a different action.
I have courses which have an attribute state which is a string with a two letter state abbreviation. When a user visits /courses/1, I want Rails to display the show action in the courses controller (and pass the parameter as :id). When a user visits /courses/CO though, I want Rails to display the index action and pass the parameter as :state.
So /courses/1 would be equivalent to
:controller => 'courses', :action => 'show', :id => '1'
And /courses/CO would be equivalent to
:controller => 'courses', :action => 'index', :state => 'CO'
I have tried this:
map.resources :courses, :except => { :index, :show }
map.connect 'courses/:state', :controller => 'courses', :action => 'index', :state => /[A-Z]{2}/
map.connect 'courses/:id', :controller => 'courses', :action => 'show', :id => /[0-9]+/
But it breaks (the rails server wont even start). I don't usually do things like this with routes, so I am outside of my know-how. Thanks!
Edit: Fixed a typo, thanks JC.
Current solution looks like this:
map.resources :courses, :except => [ :index, :show ]
map.courses '/courses', :controller => 'courses', :action => 'index', :state => 'AL', :method => :get
map.courses '/courses/:state', :controller => 'courses', :action => 'index', :requirements => { :state => /[A-Z]{2}/ }, :method => :get
map.course '/courses/:id', :controller => 'courses', :action => 'show', :requirements => { :id => /[0-9]+/ }, :method => :get
This works, but you will need to go edit all your links to the index to say things like courses_path('AA') and you won't be able to use some of the nice helpers, like form_for, which assume you are following the convention that #create is simply #index with a POST request. (Get comfortable with form_tag)
ActionController::Routing::Routes.draw do |map|
map.resources :courses, :except => [ :index, :show ]
map.courses '/courses/:state', :controller => 'courses', :action => 'index', :requirements => { :state => /[A-Z]{2}/ } , :method => :get
map.course '/courses/:id', :controller => 'courses', :action => 'show', :requirements => { :id => /[0-9]+/ } , :method => :get
end
It will keep your routes named the same, though.
(by the way, your /co does not match your regex, which requires upper case chars)
Fun aside: Do we really need the abstraction of a router? http://blog.peepcode.com/tutorials/2010/rethinking-rails-3-routes
I'm afraid this won't work since the structure that maps paths to controllers and actions is setup on start of the rails application, parameter handling happens at request time.
What you could do is to match the :id-parameter in the show-action of the CoursesController against a list of valid states and then either redirect or render a different action.
Hope this helps.

Custom dynamic error pages in Ruby on Rails not working

I'm trying to implement custom dynamic error pages following this post:
http://www.perfectline.co.uk/blog/custom-dynamic-error-pages-in-ruby-on-rails
I did exactly what the blog post says. I included config.action_controller.consider_all_requests_local = false in my environment.rb. But is not working.
My browser shows:
Routing Error
No route matches "/555" with {:method=>:get}
So, it looks like the rescues are not fired.
I get the following in my log file:
ActionController::RoutingError (No route matches "/555" with {:method=>:get}):
Rendering rescues/layout (not_found)
Is there some routing interfering with the code? I'm not sure what to look for. I'm running rails 2.3.5.
Here is the routes.rb file:
ActionController::Routing::Routes.draw do |map|
# routing van property-url
map.connect 'buy/:property_type_plural/:province/:city/:address/:house_number', :controller => 'properties' , :action => 'show', :id => 'whatever'
map.myimmonatie 'myimmonatie' , :controller => 'myimmonatie/properties', :action => 'index'
map.login "login", :controller => "user_sessions", :action => "create", :conditions => {:method => :post}
map.login "login", :controller => "user_sessions", :action => "new"
map.logout "logout", :controller => "user_sessions", :action => "destroy"
map.buy "buy", :controller => 'buy'
map.sell "sell", :controller => 'sell'
map.home "home", :controller => 'home'
map.disclaimer "disclaimer", :controller => 'disclaimer'
map.sign_up "sign_up", :controller => 'users', :action => :new
map.contact "contact", :controller => 'contact'
map.resources :user_sessions
map.resources :contact
map.resources :password_resets
map.resources :messages
map.resources :users, :only => [:index,:new,:create,:activate,:edit,:profile,:password]
map.resources :images
map.resources :activation , :only => [:new,:resend]
map.resources :email
map.resources :properties, :except => [:index,:destroy]
map.namespace :admin do |admin|
admin.resources :users
admin.resources :properties
admin.resources :order_items, :as => :orders
admin.resources :blog_posts, :as => :blog
end
map.connect 'myimmonatie/:action' , :controller => 'users', :id => 'current', :requirements => {:action => /(profile)|(password)|(email)/}
map.namespace :myimmonatie do |myimmonatie|
myimmonatie.resources :messages, :controller => 'messages'
myimmonatie.resources :password, :as => "password", :controller => 'users', :action => 'password'
myimmonatie.resources :properties , :controller => 'properties'
myimmonatie.resources :orders , :only => [:index,:show,:create,:new]
end
map.root :controller => "home"
map.connect ':controller/:action'
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
ActionController::Routing::Translator.translate_from_file('config','i18n-routes.yml')
The code works, something is wrong with the line in my environment.rb
config.action_controller.consider_all_requests_local = false
It seems to be overridden somewhere.
So, CASE CLOSED, thanks!
Rails detects when you are browsing with ip 127.0.0.1 and shows you the development environment errors even if you are in production environment. You should try accessing from a different machine to get the proper errors.

Ruby routes and link_to, custom :action route problem

I'm trying to get this link:
<%= link_to('Edit', :action => 'manage', :id => user) %>
even tried explicitly <%= link_to('Edit', {:controller => 'users', :action => 'manage', :id => user}, :method => :get) %>
to show the link in HTML as
'/users/manage/1' or '/users/1/manage'
but it shows up as
'/users/manage?id=1'
I can see in my routes:
manage_users GET /users/manage(.:format) {:action=>"manage", :controller=>"users"}
...
edit_user GET /users/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
so I added a map.connect, but it was added to users
users GET /users/manage/:id(.:format) {:action=>"manage", :controller=>"users"}
but without any success. The link is still '/users/manage?id=1'
This doesn't work anymore than the above.
GET /users/:id/manage(.:format) {:action=>"manage", :controller=>"users"}
Now, when I put the :action in link_to, to 'edit' i.e.
<%= link_to('Edit', :action => 'edit', :id => user) %>
The routes.rb edit_user GET /users/:id/edit/(.:format) works, with a link showing up of
'/users/1/edit'
How do I get my link_to to show the same link when it is 'manage' instead of 'edit', i.e. showing a link of 'users/1/manage' instead of '/users/manage?id=1'??? Is it because my above map.connect is being added to users, when it should be added to 'manage_users'?
Thank for the help. I'll be trying to figure it out.
Peace.
BTW, /users/manage?id=1 works, I just want the proper rewrite link to click on.
EDIT routes.rb
map.resources :users, :collection => {:manage => :get}
#map.manage_user '/users/:id/manage', :controller => :users, :action => :manage
#map.resources :users, :member => { :manage => :get }
#map.connect 'users/manage/:id(.:format)', :controller => 'users', :action => 'manage', :conditions => { :method => :get }
map.resources :categories
map.resources :posts
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
so I added a map.connect, but it was added to users
I suspect you added map.connect after other definitions, which would give it lowest priority. Try putting it in the beginning of routes.rb file.
You can also use named routes to avoid confusion:
map.manage_user '/users/:id/manage', :controller => :users, :action => :manage
and then refer it as
link_to 'Manage', manage_user_path(:id => user)
edit
If that doesn't work, please show your routes.rb file.
You should change collection to member in your routes.rb when defining map.resources :users. Then you'll get nice /users/1/manage link.
Also, when creating a link try this:
<%= link_to 'Manage', manage_user_path(user) %>

Rails: Routing subdomain to a resource

Is it possible to map a subdomain to a resource? I have a company model. Currently, using subdomain_fu, my routing file contains:
map.company_root '', :controller => 'companies', :action => 'show',
:conditions => { :subdomain => /.+/ }
My Company model contains a "subdomain" column.
Whilst this works as intended, it's a named route and isn't restful. Essentially, I need to map "name.domain.com" to the show action for the companies controller. Is a named route the way to go, or can I use a resource route?
One can pass conditions to a resource route as well as a named route. In an application I am involved with everything is scoped to an account. A :before_filter loads the account using the subdomain. Thus for resources scoped to an account, we want to scope the routes to urls with subdomains. The DRY way to do this is to use map with options:
map.with_options :conditions => {:subdomain => /.+/} do |site|
site.resources :user_sessions, :only => [:new, :create, :destroy]
site.resources :users
site.login 'login', :controller => "user_sessions", :action => "new"
site.logout 'logout', :controller => "user_sessions", :action => "destroy"
…
end
map.connect 'accounts/new/:plan', :controller => "accounts", :action => "new"
map.resources :accounts, :only => [:new, :create]
As you can see a named route will accept a conditions hash with a subdomain too. You can also adopt the approach Ryan illustrated above or you can specify conditions on a per resource basis:
map.resources :users, :conditions => {:subdomain => /.+/}
I don't know of a way to do this with map.resources. It does accept a :conditions option but I'm not sure how to remove the /companies/ portion of the URL. However, map.resources is primarily a convenient way to generate a bunch of named routes, which you can do manually. Something like this.
map.company '', :controller => 'companies', :action => 'show', :conditions => { :subdomain => /.+/, :method => :get }
map.new_company 'new', :controller => 'companies', :action => 'new', :conditions => { :subdomain => /.+/, :method => :get }
map.edit_company 'edit', :controller => 'companies', :action => 'edit', :conditions => { :subdomain => /.+/, :method => :get }
map.connect '', :controller => 'companies', :action => 'create', :conditions => { :subdomain => /.+/, :method => :post }
map.connect '', :controller => 'companies', :action => 'update', :conditions => { :subdomain => /.+/, :method => :put }
map.connect '', :controller => 'companies', :action => 'destroy', :conditions => { :subdomain => /.+/, :method => :delete }
Untested, but it should get you close.
Here's a complete example implementation of Rails 3 subdomains with authentication (along with a detailed tutorial). It's much easier to do this in Rails 3 than in Rails 2 (no plugin required).
Using the resource linked from Daniel's answer, in Rails 3 the way to route '/' to a different controller depending on the subdomain is as follows:
match '/' => 'somecontroller#action', :constraints => { :subdomain => 'yoursubdomain' }

Resources