I'm creating an engine that needs to insert some routes into the application's router. For this particular gem, I'd rather not application's routes.rb if possible. Is there a way to insert routes at a particular location in the router via code? I'm looking for an API that does something like:
Rails.application.routes.insert("resources :foos", :before => "some string in routes.rb")
If I create a config/routes.rb inside the engine and define some routes, this kind of works. Rails is smart enough to mix the engine's routes into the application's routes, but it tacks them on at the end of the route list. I need them to appear at the beginning so the engine's routes take priority.
I'm aware that I can namespace the routes by mounting the engine in the application's routes.rb, but this creates a routing structure that I don't really want. I want the engine's routes to look they are a part of the application by defining some routes in the actual application.
I have a workaround which is to add the following to the application's routes.rb.
Rails.application.routes.draw do
MyEngine.setup_routes(self)
#...other routes below
end
MyEngine.setup_routes looks like
def self.setup_routes(map)
map.get 'a_path', :to => 'a_controller#a_path'
end
This at least allows me to control the point where the routes get defined in the application's route list, but the user still has to manually update his routes.rb (or I have to build an installer that does it). It seems like there should be a way to tell rails to tack some routes onto the start of the route list...
Related
Setup
Our current Rails app is made out of sub-apps that are mounted as engines. Typically these engines are mounted on a subdomain in the main routes.rb file as follows
mount MySubApp::Engine => '/', as: :sub_app, constraints: {subdomain: 'sub_app'}
The Problem
Routes within MySubApp's routes.rb file do not get the subdomain when using the named _url helpers. For example the following in apps/my_sub_app/config/routes.rb
MySubApp::Engine.routes.draw do
resources :foos
end
gives us sub_app.foo_url(5) but it results in
http://www.example.com/foos/5
when we want
http://sub_app.example.com/foos/5
tl;dr
How can I get the engine's mounting constraints passed to its named routes?
EDIT: A Workaround
While I'd still prefer a better solution, the following will work. You can wrap all the routes in each of the sub apps routes.rb files that could be mounted on a subdomain like so
MySubApp::Engine.routes.draw do
constraints Rails.application.routes.named_routes[:sub_app].constraints do
resources :foos
end
end
EDIT 2: A much less desirable workaround
A commenter (since deleted?) pointed out you can pass a subdomain option to the helpers but we'd like to avoid having to use sub_app.foo_url(5, {subdomain: 'sub_app'}) for every cross subdomain link. Even if we moved the subdomain name into an ENV var and made a wrapper, this is not DRY.
check out the guide it says you can do it by
namespace :Engine do
resources :controller, :methods
end
the Engine is just name spacing your code
#Aaron not sure if you ever got this fixed, but look into the
config.action_dispatch.tld_length
setting (on the engine's config). I'm not sure how it'll react with engines, but in our case it lets us handle the case of sub-subdomains for our staging server (so when we use the _url helpers with the staging server it correctly does subdomain.staging.domain.com, rather than subdomain.domain.com).
I am trying to create a scaffold called 'Pages'.
So far everything is fine but the page structure now needs to change where it currently is:
http://0.0.0.0:3000/pages/the-page-name
What I need to do now is have this instead:
http://0.0.0.0:3000/the-page-name
In my routes.rb I have this:
resources :pages
This obviously maps all routes within the model to this base but I want to hide this.
Is it entirely possible?
Thanks,
Taken from the Rails Routing Guide, you could do this:
get '*pages', to: 'pages#show', format: false
I would recommend you make it the very last route you have, since the Rails router matches the request with the first route, and having a wildcard early in your routes file will end up clobbering all your other routes/resources.
You can specify a path
resources :pages, path: ''
First, why do we need to namespace controllers?
The example on rails guides shows
namespace :admin do
resources :post, :comments
end
In this case, we have paths such as GET /admin/posts. Is it identical to GET /posts? Or is GET /posts kept as original while another GET /admin/posts is added as extra?
Does rails create any other stuff for namespace?
You dont have to use namespaces if you dont want to, but it's there to make your life easier, specially in big applications with a lot of controllers. And no, routes arent duplicated if you namespace them, unless you specify the route again in your route file without the namespace, but that doesnt make much sense.
Here is a app contorller directory from Rails project
doing a self study for rails, but from what I understand if I create a directory in the app folder then I have to do the complete the routes files with a match that route like:
match "/editor/usynkdataeditor/saveusynkeditor",
Question to the community is there a better way that I can define different directory structure for a specific workflow or is it safe to define all the controllers in parent controllers directory.
If you create additional directory in controllers directory, you are effectively namespacing your controllers.
So this controller would be:
class Editor::UsynkdataeditorController < ApplicationController
def saveusynkeditor
end
end
As far as routes are defined, you can do something like:
MyApplication::Application.routes.draw do
namespace :editor do
get "usynkdataeditor/saveusynkeditor"
end
end
Whish will give you route:
$ rake routes
editor_usynkdataeditor_saveusynkeditor GET /editor/usynkdataeditor/saveusynkeditor(.:format) editor/usynkdataeditor#saveusynkeditor
Or, preferably just use restful routes instead of saveusynkeditor like this:
MyApplication::Application.routes.draw do
namespace :editor do
resources :usynkdataeditor do
collection do
get :saveusynkeditor
end
end
end
end
when you will get:
$ rake routes
saveusynkeditor_editor_usynkdataeditor_index GET /editor/usynkdataeditor/saveusynkeditor(.:format) editor/usynkdataeditor#saveusynkeditor
editor_usynkdataeditor_index GET /editor/usynkdataeditor(.:format) editor/usynkdataeditor#index
POST /editor/usynkdataeditor(.:format) editor/usynkdataeditor#create
new_editor_usynkdataeditor GET /editor/usynkdataeditor/new(.:format) editor/usynkdataeditor#new
edit_editor_usynkdataeditor GET /editor/usynkdataeditor/:id/edit(.:format) editor/usynkdataeditor#edit
editor_usynkdataeditor GET /editor/usynkdataeditor/:id(.:format) editor/usynkdataeditor#show
PUT /editor/usynkdataeditor/:id(.:format) editor/usynkdataeditor#update
DELETE /editor/usynkdataeditor/:id(.:format) editor/usynkdataeditor#destroy
There is a really good explanation http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing of what you are trying to achieve in rails guides.
Finally, to answer your question:
Better way? Well it's up to your preferences. How do you like your code organized? You can use namespacing but you don't have to. However,
at the same there is nothing wrong with having all controllers in parent controller directory.
This falls under Namespacing and it's generally considered the best approach to do what you're trying to do. Check it out.
I am new to Ruby on Rails and have some problems.
For the development I use RubyMine IDE, I manage to create models, controllers and views, but I have problems with the routing. By default, routes.rb file contains only this method Apis::Application.routes.draw do with an empty body.
For example, I create a controller TestController, then the index method and in routes.rb I add this instruction resources :test. So far, it works fine. But if I add another method, let's say method1 (and the view) I can't reach it in a browser http://localhost:3000/test/method1.
What else should I add in routes.rb file?
Is there any way to make the routing automatically from the IDE, with less editing the routes file?
resources :test
is a resourceful route which provides a mapping between HTTP verbs and URLs to controller actions. By convention, each action also maps to particular CRUD operations in a database
you can uncomment in your routes to enable the controller action mapping.
match ':controller(/:action(/:id(.:format)))'
or use -
match "/test/method1" => "test#method1"
Detailed routes info # http://guides.rubyonrails.org/routing.html