How to override Rails app routes from an engine? - ruby-on-rails

I have a Rails app that I am trying to integrate a Rails engine in to.
The host app has some catch all routes:
# magic urls
match '/' => 'admin/rendering#show'
match '*path/edit' => 'admin/rendering#show', :defaults => { :editing => true }
match '*path' => 'admin/rendering#show'
It looks like the engine routes are loaded after the application catches all routes.
/sitemap.xml(.:format) {:format=>"xml", :controller=>"admin/sitemaps", :action=>"show"}
/(.:format) {:controller=>"admin/rendering", :action=>"show"}
/*path/edit(.:format) {:controller=>"admin/rendering", :action=>"show"}
/*path {:controller=>"admin/rendering", :action=>"show"}
engine_envs GET /engine/envs/:id(.:format) {:controller=>"engine/envs", :action=>"show"}
PUT /engine/envs/:id(.:format) {:controller=>"engine/envs", :action=>"update"}
jammit /assets/:package.:extension(.:format) {:extension=>/.+/, :controller=>"jammit", :action=>"package"}
So far, everything is hitting the /engine/envs routes are getting caught by the application catch all routes. However I see that the jammit route is loaded after the engine and I don't believe those are getting caught. Any way to override the app routes?

You could stick your engine routes in a method and then call that in your host app.
# engine routes.rb
module ActionDispatch::Routing
class Mapper
def engine_routes
engine_envs GET /engine/envs/:id(.:format)
# ...
end
# ...
and then in your host app add the method before the catch-all route
# host app routes.rb
MyTestApp::Application.routes.draw do
# ...
engine_routes
match '/' => 'admin/rendering#show'
match '*path/edit' => 'admin/rendering#show', :defaults => { :editing => true }
match '*path' => 'admin/rendering#show'
end

Routes are used in the order they are defined. The first routes to be read are the one of the host application, then of your engine.
As soon as a matching route is found, the search for a route is stopped.
As far as I know, there are no way (I may be wrong about this) to override this feature other than to change your "mag
UPDATE: So that means that the order you see them in "rake routes" is the order they are processed. As soon as a matching route is found, there you go.

Related

Multiple 'root to' routes in rails 4.0

I am trying to get rails to go to different controller#action according to the subdomain, and this is what I have so far in routes.rb
Petworkslabs::Application.routes.draw do
get '/', to: 'custom#show', constraints: {subdomain: '/.+/'}, as: 'custom_root'
get '/', to: "welcome#home", as: 'default_root'
end
rake shows the correct routes I want it to take
rake routes
Prefix Verb URI Pattern Controller#Action
custom_root GET / custom#show {:subdomain=>"/.+/"}
default_root GET / welcome#home
But for some reason, I can't get requests like abc.localhost:3000 to hit the custom controller. It always routes it to welcome#home. Any ideas? I am fairly new to rails, so any tips about general debugging would also be appreciated.
EDIT: I stepped through the code using the debugger and this is what I found
(rdb:32) request.domain
"abc.localhost"
(rdb:32) request.subdomain
""
(rdb:32) request.subdomain.present?
false
Looks like for some reason rails thinks that the subdomain is not present, even though its there. I wonder if its because I am doing this localhost.
Updated Answer:
Worked for me on Rails 3 & 4:
get '/' => 'custom#show', :constraints => { :subdomain => /.+/ }
root :to => "welcome#home"
#manishie's answer is right, but you'll still likely have issues in your devo environment if you're using localhost. To fix it add the following line to config/environments/development.rb:
config.action_dispatch.tld_length = 0
and then use #manishie's answer in routes.rb:
get '/' => 'custom#show', :constraints => { :subdomain => /.+/ }
root :to => "welcome#home"
The issue is that tld_length defaults to 1 and there's no domain extension when you're using localhost so rails fails to pickup the subdomain. pixeltrix explains it really well here: https://github.com/rails/rails/issues/12438
For some reason request.subdomain was not getting populated at all (I suspect this is because I have doing this on localhost, I have opened a bug here https://github.com/rails/rails/issues/12438). This was causing the regex match in routes.rb to fail. I ended up creating a custom matches? method for Subdomain which looks something like this
class Subdomain
def self.matches?(request)
request.domain.split('.').size>1 && request.subdomain != "www"
end
end
and hooking that up in routes.rb
constraints(Subdomain) do
get '/', to: "custom#home", as: 'custom_root'
end
this seems to work.
EDIT: More information in the github issues page https://github.com/rails/rails/issues/12438

Rails 3 add new routes to resources

I have the following problem:
I created one entity "Film" with the command "scaffold" and automatically added in my routes file "resources: films", and then I try to added an autocomplete via ajax, but always the calling ajax calls the "show" action instead of call the route that I added "autocomplete_term"
My routes files (routes.rb)
resources :films
I tried the following possibilities (routes.rb)
match 'films/autocomplete_term' => "films#index", :via=>:get
match "films/autocomplete_term/:term" => "films#autocomplete_term", :controller=>"films", :action=>"autocomplete_term", :as => :films_autocomplete, :via => :get
resources :films do
collection do
get 'autocomplete_term'
end
end
The route
** localhost.com:3000/films/autocomplete_term?term=a**
The ERROR
Couldn't find Film with id=autocomplete_term
app/controllers/films_controller.rb:28:in `show'
When I run the command rake routes
GET /films/autocomplete_term/:term(.:format) films#autocomplete_term
films_autocomplete
GET /films/autocomplete_term/:term(.:format) films#autocomplete_term
autocomplete_term_films
GET /films/autocomplete_term(.:format) films#autocomplete_term
Sorry for my English
And thanks in advance
The url to access this route
GET /films/autocomplete_term/:term
should be
localhost.com:3000/films/autocomplete_term/a
if you do localhost.com:3000/films/autocomplete_term?term=a it will think it is the show action, it will ignore the ?term=a
GET /films/:id
Thanks to Anezio, solved the problem, basicament had two things wrong:
1 - The route
match "films / autocomplete_term /: term"
2: The order in my routes.rb file (Rails routes are matched in the order they are specified)
resources: films
match 'films / autocomplete_term /: term' => "films # autocomplete_term"
The Final Solution: (routes.rb)
match 'films / autocomplete_term' => "films # autocomplete_term"
resources: films

Routing error for GET] "/firstapp"

I was trying to write my first program after installation, but I got an error like below:
Routing Error
No route matches [GET] "/firstapp"
I've tried to change my config/routes.rb file but nothing changed. This is my config/routes.rb
Firstapp::Application.routes.draw do
resources :apptables
# The priority is based upon order of creation:
# first created -> highest priority.
# continues with default `config/routes.rb` explanations...
end
How can I configure the config/routes.rb to make it run properly?
Just saying resources :apptables sets up the standard seven routes:
GET /apptables
GET /apptables/new
POST /apptables
GET /apptables/:id
GET /apptables/:id/edit
PUT /apptables/:id
DELETE /apptables/:id
There is no /firstapp in that list so that route won't work. If you want a GET on /firstapp to work then you can set up that route manually:
match '/firstapp' => 'firstapp#some_method', :via => :get
That would route GET /firstapp to FirstappController#some_method.

A very basic issue with routes in ruby

I am new to ruby and while creating a sample application found out an issue that whenever I go to http://127.0.0.1:3000/people/index by default show action is executed and index is taken as a parameter. This is server log:
Started GET "/people/index" for
127.0.0.1 at 2010-12-23 18:43:01 +0500 Processing by PeopleController#show as
HTML Parameters: {"id"=>"index"}
I have this in my route file:
root :to => "people#index"
resources :people
match ':controller(/:action(/:id(.:format)))'
What is going on here and how can I fix the issue?
The route
resources :people
creates "sub"-routes
get '/people' => 'people#index'
get '/people/new' => 'people#new'
post '/people' => 'people#create'
get '/people/:id' => 'people#show'
get '/people/:id/edit' => 'people#edit'
put '/people/:id' => 'people#update'
delete '/people/:id' => 'people#destroy'
Actually, all of these sub-routes include (.:format) at the end of the recognized path.
The path /people/index would be recognized by the route /people/:id, mapping to the action #show.
The path /people would be recognized by the route /people, mapping to the action #index.
Use the URL helpers people_path and people_url for the /people route.
To get Rails to travel backward in time to before it espoused REST and to understand /people/index, do this:
resources :people do
get :index => 'people#index'
end
You might want to watch this Railscast episode.
A couple things to keep in mind when working with your routes:
rake routes dumps the map of URLs to your controllers
When providing backwards compatibility, redirect the user to the correct path
I personally have yet to upgrade my app to Rails 3, and I'll be dragging my feet until I really need to do it (just got it out the door not too long ago). In Rails 2.x you had resource routes, but if you kept the default controller/action/id route it would fall through and resolve. It appears that is no longer the case in Rails 3. Essentially your resource routes handle all URLs in that resource namespace (/people in your case).
To provide backwards compatibility, I would add a redirect route to resolve that incompatibility.
match "/people/index", :to => redirect("/people")
The main reason for that is to prevent users from saving an incorrect URL for their personal links--while allowing legacy users to still be able to get where they meant to go.
Edit: New answer, removed pointing out the typo in the question.

Ruby on Rails 3: Change default controller and parameter order in routing

I have a Rails app that has a controller called domain which has a nested controller called subdomain and stats. I have defined them in routes.rb:
resources :domains do
resources :subdomains, :stats
end
I have changed the to_param of the domain and subdomain models to use the name of the domain, e.g.: the routing I get is http://site/domains/foo/subdomains/bar.
I would like to tidy it up to so that instead of using http://site/domains/foo/subdomains/bar I could access it with just http://site/foo/subdomains/bar. I have tried the following in routes.rb:
match "/:id/" => "domains#show", :as => :domain
Which works fine, but it only gives me the ability to use the path http://site/foo but for example http://site/foo/subdomains/bar doesn't. I could create match lines for every respective model and nested model but that does nothing to other helpers besides domain_url - i.e. edit_domain_url points to /domains/foo/edit/ instead of /foo/edit.
Is there a way to change the routing so that the resources generates helpers that point to the root url without the 'domains' part?
The single match in your routes creates only one route. Resource helpers create many routes at once. Luckily there are a lot of options for customisation. If you want to omit /domains/ from your paths, it's as simple as:
resources :domains, :path => "/" do
resources :subdomains, :stats
end
With the above in config/routes.rb, running rake routes says the following:
domain_subdomains GET /:domain_id/subdomains(.:format)
domain_subdomains POST /:domain_id/subdomains(.:format)
new_domain_subdomain GET /:domain_id/subdomains/new(.:format)
edit_domain_subdomain GET /:domain_id/subdomains/:id/edit(.:format)
domain_subdomain GET /:domain_id/subdomains/:id(.:format)
domain_subdomain PUT /:domain_id/subdomains/:id(.:format)
domain_subdomain DELETE /:domain_id/subdomains/:id(.:format)
domain_stats GET /:domain_id/stats(.:format)
domain_stats POST /:domain_id/stats(.:format)
new_domain_stat GET /:domain_id/stats/new(.:format)
edit_domain_stat GET /:domain_id/stats/:id/edit(.:format)
domain_stat GET /:domain_id/stats/:id(.:format)
domain_stat PUT /:domain_id/stats/:id(.:format)
domain_stat DELETE /:domain_id/stats/:id(.:format)
domains GET /(.:format)
domains POST /(.:format)
new_domain GET /new(.:format)
edit_domain GET /:id/edit(.:format)
domain GET /:id(.:format)
domain PUT /:id(.:format)
domain DELETE /:id(.:format)
Looks like all the routes you need!

Resources