rails namespaced route with root only works in development - ruby-on-rails

namespace :admin do
root :to => "admin#index"
end
I can visit localhost:3000/admin and it works.
When I deploy to heroku myapp.herokuapp.com/admin does not. It produced this
ActionController::RoutingError (uninitialized constant Admin::AdminController):
My controller is actually AdminController, not Admin::AdminController and I'm not quite sure what the difference is or how to fix this.
Again, it all works locally.

You can see in rake routes output that for this namespaced route rails uses :controller => 'admin/admin'. When it comes to finding controller class it converts admin/admin into Admin::AdminController. So controllers for namespaced routes are usually placed under app/controllers/namespace_name directory and wrapped in NamespaceName module. In your case it should be Admin::AdminController class defined in app/controllers/admin/admin_controller.rb.
Though, it's really interesting why your configuration works fine in development but breaks in production mode (I tried and successfully reproduced it). I believe it has smth to do with loading and caching classes in production mode, because setting config.cache_classes = true in config/environments/development.rb cause it breaking in development mode as well.
And as zoltarSpeaks noted it's supposed to be root :to => "admin#index" instead of root :to => "Admin#index".
Another thing to note is that namespaces for routes are usually used when there are multiple related controllers. If all you need is single AdminController you can config your routes like that:
resources :admin, :only => :index
In that case no other changes are needed (if you want to have other default actions besides index just remove :only option).

I'm away from my laptop so can't check but is:
root :to => "Admin#index"
supposed to be:
root :to => "admin#index"
instead? It might not make any difference.
Do you have an Admin folder within controllers with an Admin controller inside it then?
If you could show us your controller code too it would be helpful thanks.

Related

Rails: simplest way to put a blog on a subdomain

I've been digging around on subdomains in Rails for a couple days and haven't found a good explanation of this yet...
I have a rails app which has a blog integrated into it, and I'd like to put that blog on a subdomain. Ie. blog.myapp.com.
Now, within the blog I want the user to be able to view posts, blog.myapp.com/posts/123. However, if the user were to click to any other resources on the site, say videos for example, I'd like them to be redirected back to root, ie. www.myapp.com/videos/123. I don't want blog.myapp.com/videos... to cause a routing error, I just want it to redirect.
Basically, I'm looking for the simplest way to setup a subdomain and specify that certain controllers use that subdomain and the others don't. Ideally I'd even like the controller layer to handle redirection both ways, so that in views I could link back and forth to things just using helpers like post_path(123) and video_path(123) and that the subdomain would automatically be used or not used based on which controller was serving the view.
I tried putting all the controllers in a constraints block, ie:
constraints :subdomain => 'www' do
resources :sessions
resources :users
resources :videos
root :to => 'home#show'
end
constraints :subdomain => 'nexturb' do
resources :posts
root :to => "posts#index"
end
root :to => 'home#show'
However this doesn't seem to work well, I've especially had trouble with getting redirection between links to work very consistently.
I'm pretty sure other people must have run into this issue in the past, but I can't seem to find a good example of this situation in writing. What's the best way to handle this?
With help from here, here, and here... I finally figured this out:
constraints :subdomain => 'blog' do
scope '', :subdomain => 'blog' do
resources :posts
end
root :to => 'posts#index'
end
This causes the posts_path helper to correctly send visitors to the subdomain.
I used #Andrew's answer. Some extra tips:
This railscast suggests using lvh.me to make subdomains work on localhost by visiting urls like blog.lvh.me:3000 or lvh.me:3000
Add the routes available in Andrew's answer
You may then have to add this to config/development.rb:
config.hosts += ["lvh.me", "blog.lvh.me"]

Single Rails codebase, two servers, two routing scopes

In a rails application with namespaced /admin functionality, consider the following routes:
namespace :admin do
root :to => 'home#index'
[.. resources cut here..]
end
get 'etc/:etc' => 'etc#etc'
[.. other top level routes cut..]
If I wanted to deploy the same Rails codebase to 2 separate servers, frontend.com would still see the top level routes 'etc/:etc'.
But what if I wanted to deploy the same codebase to an admin-only server, such that the request would simply be http://backend.com and have namespace :admin take over as the top level without having to type or use http://backend.com/admin.
Upon trying with .htaccess rewrite, I have run into URL generation issues within the admin namespace code, as well as assets no longer being loaded properly.
Is this just something that's not worth pursuing?
You can, of course, have a conditional around a root statement.
namespace :admin do
root :to => 'admin#index'
...
end
if SOMETHING
root :to => "admin#index"
end
(I used an AdminController instead of HomeController in this example.)
The user can type http://backend.com/, but at some point the /admin may appear on the browser's URL bar.
The SOMETHING could be a test for the hostname, or an ENV. You could set the ENV in the vhost configuration.

How to redirect in routes.rb for root?

I have the following at the bottom of my routes file:
root :to => 'threads#index', :constraints => lambda {|r| r.env["warden"].authenticate? }
The problem with this is the url is just /, not /threads
How can I get the above to redirect to threads#index or /threads ?
Thanks
If I understand your question correctly, you simply want to change the URL of the root of your site from http://....com/ to http://....com/threads.
In this case, you simply have to add this line:
config.action_controller.relative_url_root = '/threads'
to any of the standard config files, such as config/application.rb, config/development.rb or config/production.rb depending on whether your app is in production mode or development mode.
There is some more information about this on a rails guide: here
EDIT:
It seems that the above solution may not work. Here is one I tried myself. You can simply wrap all your pre-existing routes in a scope, inside your routes.rb file. i.e:
scope "/threads" do
..All your preexisting routes inside this..
end
Note that this will prepend /threads to EVERY path in your app. If you only want this to happen with root, then make sure only the root :to => ... line is wrapped in the scope.
Here's a simple explanation of scopes: here

Overriding named routes provided by Rails 3 Engines

I am working on a Ruby on Rails 3(.0) application that uses a Rails engine. However, in my local application, I want to override one of the routes provided by the Rails engine.
From the engine config/routes.rb:
match 'their_named_route' => 'controller#action', :as => 'the_route'
From my application config/routes.rb:
match 'my_named_route' => 'controller#action', :as => 'the_route'
However, when I inspect the routes, both seem to be active (and their route appears to "win", at least within the engine controllers)
$ rake routes
the_route /my_named_route(.:format) {:controller=>"controller", :action=>"action"}
the_route /their_named_route(.:format) {:controller=>"controller", :action=>"action"}
Is there a good way to force my local application's named route to take priority?
I got around this by moving my engine's routes from config/routes.rb to a class method in the engine class itself:
module MyEngine
class Engine < Rails::Engine
def self.routes
MyRailsApp::Application.routes.draw do
resources :products
end
end
end
end
and then in the base app's routes file:
MyRailsApp::Application.routes.draw do
# Routes for base app including the ones overriding MyEngine::Engine.
MyEngine::Engine.routes
end
I can then happily override any routes in the base app with those in the engine.
Note that the overriding routes need to be defined before the overridden routes since the earlier defined routes take precedence over later ones.
I'm afraid that there's no such easy way. The routes are defined in lib/action_dispatch/routing/mapper.rb:271, which calls add_route on the RouteSet (defined in rack-mount-0.6.14/lib/rack/mount/route_set.rb, and on line 71 the name is attached). There's no remove_route method, and the Engine's route is added last. You can add your route manually after the application is initialized with Rails.application.routes.draw instead of having it in routes.rb, or you can patch the Engine.
There is no way to override a route within an engine. Instead, you must define an overruling route. You can do this by calling prepend on the engine's router:
An::Engine.routes.prepend do
root :to => "somewhere#action"
end
If the engine's namespace is isolated, this will use the SomewhereController from inside the engine's namespace. If not, it will use the typical SomewhereController.
If you want to override a route to return a 404, the best way I can think of is to redirect to a 404 page:
match "/route_goes_here" => redirect("/404")
You need add initializer hook to config/application.rb, like this:
class Application < Rails::Application
config.encoding = "utf-8"
...
initializer :add_routing_paths do |app|
their_routes_path = app.routes_reloader.paths.select{|path| path =~ /DIR/}.first
app.routes_reloader.paths.delete(their_routes_path)
app.routes_reloader.paths.unshift(their_routes_path)
end
end
It's load roues.rb of you engine first and you can override their routes.
You can prepend routes as suggest by Ryan Bigg above. I found that in order overrule the named route helper with my custom route I need to call append instead of prepend, like so:
An::Engine.routes.append do
root :to => "somewhere#action"
end
Otherwise the app contains both routes and the named helper for engine's router is the last definition, and therefore the one that is applied.
Routing rules defined in routes.rb are applied from the top down until a match is found. I was able to override the route defined in the mounted engine simply by moving the higher-priority rule above the line where the engine is mounted. So,
get 'about', controller: 'static', action: 'about', as: 'about'
mount My::Engine => '/'
results in the app routing /about/ requests to (in this case) the static controller, whereas:
mount My::Engine => '/'
get 'about', controller: 'static', action: 'about', as: 'about'
results in the app routing /about/ requests to the route defined in the mounted engine.
To Replace the default routes path provided by gem or engine we can achive that in following way.
For me I wanted to replace 'spree_user' with 'account' etc from all routes
/user/spree_user/sign_in I did this in following way
Step 1
Create config/some_engine_route_override.rb
Copy the content of engine route file and update the routes as per need
Step 2
in application.rb use the folllowing hook
# Override Spree Core routes in order to translate products routes
initializer "delete_spree_core_routes", after: "add_routing_paths" do |app|
new_spree_auth_route_path = File.expand_path('../../config/some_engine_route_override.rb', __FILE__)
routes_paths = app.routes_reloader.paths
spree_devise_auth_route_path = routes_paths.select{ |path| path.include?("spree_auth_devise") }.first
if spree_devise_auth_route_path.present?
spree_core_route_path_index = routes_paths.index(spree_devise_auth_route_path)
routes_paths.delete_at(spree_core_route_path_index)
routes_paths.insert(spree_core_route_path_index, new_spree_auth_route_path)
end
end

The :as attribute in my root line in config/routes.rb is messing up my application. What's wrong with it?

I have a model and controller called coves_controller. I have this line in my routes.rb file right now: root :to => 'coves#index', :as => 'coves'
When I comment it out and go to localhost:3000/coves, everything works fine. When I uncomment it, I'm unable to create a new cove object.. There is no error statement, it just doesn't add to the database.
When I change 'coves' to 'cove' at the end, I'm can create new cove objects, but after doing so I'm routed to coves/.5 which should be coves/5
If you look at how the root path is defined, it's just a convenience method which creates a named route for you. The reverse_merge method used to load in the options means that your :as => 'coves' part of the hash will be getting ignored and changed back to :as => :root. You cannot rename the root path when using the root method.
As #apneadiving said, you need to use resources :coves to get RESTful CRUD routes for it.
I guess there is a conflict with the paths created by:
resources :coves
That is basic REST behaviour.
Don't add a 'as' statement for you root, root is just root :)

Resources