Sinatra & Rails 3 routes issue - ruby-on-rails

I have just setup Sinatra v1.1.0 inside my rails (v3.0.1) app. But I can't invoke any routes that are more than 1 level deep, meaning this works - http://localhost/customer/3,
but this one does not work - http://localhost/customer/3/edit and I get a "Routing Error"
Here's the Sinatra object
class CustomerApp < Sinatra::Base
# this works
get "/customer/:id" do
"Hello Customer"
end
# this does NOT work
get "/customer/:id/edit" do
"Hello Customer"
end
end
This is what I have in my rails routes.rb file -
match '/customer/(:string)' => CustomerApp
I am guessing I need some magic in the routes file? What could be the problem?

In your routes file, you can specify the mapping this way:
mount CustomerApp, :at => '/customer'
Now, inside your sinatra application, you can specify your routes without the /customer part.
Dont't forget to require your sinatra application somewhere (you can do it directly in the route file)

You need to add an additional route to match the different URL:
match '/customer/(:string)/edit' => CustomerApp

Related

Rails view template path loading seems incorrect

I have a problem where Rails is searching an additional subdirectory based on the controller path. Is there a way to get rails to stop searching one extra subdirectory? I kind of like the directory structure that I have now. Here's the details:
Rails will return this error message. As you can see, it's going for v1 twice:
Template is missing
Missing template api/v1/v1/print
I have a controller in app/controllers/api/v1/v1_controller.rb and a view in app/views/api/v1/print.html.erb
The specific route in config/routes.rb is (semi-truncated):
namespace :api do
scope module: :v1 do
match "v1/print",
:to => "v1#print"
end
end
Based on the routes, it looks OK. Rake routes show this:
api_v1_print GET|POST /api/v1/print(.:format) api/v1/v1#print {:format=>"html"}
Why is it going one directory too deep?
The problem is that Rails assumes there's a subdirectory per each controller. The duplication is formed since you have v1 in the module and in the controller name. I wouldn't go against Rails' conventions. Instead I would change the name of the controller to API controller (or something similar) and put the templates under the directory called API.
In case you still want to do this, simply use render within your print action and specify the exact file you'd like to use (see here)
just remove the v1 from the match, like this:
namespace :api do
scope module: :v1 do
match "print",
:to => "v1#print"
end
end
EDIT
sorry, the problem is in your template folder.
app/views/api/v1/print.html.erb
app/views/(namespace)/(module)/(action) <- you have forgoten the controller
the right one would be:
app/views/api/v1/v1/print.html.erb

Splitting Routes File Into Multiple Files

I'm working w/ a Rails 3 application and I want to split up the routes into separate files depending on the subdomain. Right now I have this in my routes.rb file:
Skateparks::Application.routes.draw do
constraints(:subdomain => 'api') do
load 'routes/api.rb'
end
end
And In my routes/api.rb file I have:
resources :skateparks
This doesn't seem to work though because if I run rake routes I get
undefined method `resources' for main:Object
Also, if I try to navigate to http://0.0.0.0:3000/ I get:
Routing Error
No route matches "/"
In Rails 3.2, config.paths is now a hash, so #sunkencity's solution can be modified to:
# config/application.rb
config.paths["config/routes"] << File.join(Rails.root, "config/routes/fooroutes.rb")
Sunkencity's answer seems to be identical to the following link, but for completeness' sake: https://rails-bestpractices.com/posts/2011/05/04/split-route-namespaces-into-different-files/
Note that routes defined later will override routes defined earlier. However, if you use something like
config.paths.config.routes.concat(
Dir[Rails.root.join('config/routes/*.rb')])
you don't know in what order the files will be read. So use
config.paths.config.routes.concat(
Dir[Rails.root.join('config/routes/*.rb')].sort)
instead, so you at least know they will be in alphabetical order.
Add the route file to the app route loading path:
# config/application.rb
config.paths.config.routes << File.join(Rails.root, "config/routes/fooroutes.rb")
Wrap your other route file in a block like this.
#config/routes/fooroutes.rb
Rails.application.routes.draw do |map|
match 'FOO' => 'foo/bar'
end
Works for me in rails 3.0
We used this in our app:
config.paths['config/routes'] = Dir["config/routes/*.rb"]
If you try to access config.paths['config/routes'] normally, it returns the relative path to config/routes.rb, so by doing the above you're giving it relative paths to all of the files in your routes folder and removing the reference to config/routes.rb

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

Routes with Dash `-` Instead of Underscore `_` in Ruby on Rails

I want my urls to use dash - instead of underscore _ as word separators. For example controller/my-action instead of controller/my_action.
I'm surprised about two things:
Google et al. continue to distinguish them.
That Ruby on Rails doesn't have a simple, global configuration parameter to map - to _ in the routing. Or does it?
The best solution I've is to use :as or a named route.
My idea is to modify the Rails routing to check for that global config and change - to _ before dispatching to a controller action.
Is there a better way?
With Rails 3 and later you can do like this:
resources :user_bundles, :path => '/user-bundles'
Another option is to modify Rails, via an initializer.
I don't recommend this though, since it may break in future versions (edit: doesn't work in Rails 5).
Using :path as shown above is better.
# Using private APIs is not recommended and may break in future Rails versions.
# https://github.com/rails/rails/blob/4-1-stable/actionpack/lib/action_dispatch/routing/mapper.rb#L1012
#
# config/initializers/adjust-route-paths.rb
module ActionDispatch
module Routing
class Mapper
module Resources
class Resource
def path
#path.dasherize
end
end
end
end
end
end
You can overload controller and action names to use dashes:
# config/routes.rb
resources :my_resources, path: 'my-resources' do
collection do
get 'my-method', to: :my_method
end
end
You can test in console:
rails routes -g my_resources
my_method_my_resources GET /my-resources/my-method(.:format) my_resources#my_method
You can use named routes. It will allow using '-' as word seperators. In routes.rb,
map.name_of_route 'a-b-c', :controller => 'my_controller', :action => "my_action"
Now urls like http://my_application/a-b-c would go to specified controller and action.
Also, for creating dynamic urls
map.name_of_route 'id1-:id2-:id3', :controller => 'my_controller', :action => "my_action"
in this case 'id1, id2 & id2 would be passed as http params to the action
In you actions and views,
name_of_route_url(:id1=>val1, :id2=>val2, :id3=>val3)
would evaluate to url 'http://my_application/val1-val2-val3'.
if you use underscores in a controller and view file then just use dashes in your routes file, and it will work..
get 'blog/example-text' this is my route for this controller
def example_text
end <-- this is my controller
and example_text.html.erb is the file
and this is the actual link site.com/blog/example-text
i figured this is works for me, and it's more effective than underscores SEO wise

Recognize routes in rails console Session

Say I have a router helper that I want more info on, like blogs_path, how do I find out the map statements behind that in console.
I tried generate and recognize and I got unrecognized method error, even after I did require 'config/routes.rb'
There is a good summary with examples at Zobie's Blog showing how to manually check URL-to-controller/action mapping and the converse. For example, start with
r = Rails.application.routes
to access the routes object (Zobie's page, a couple years old, says to use ActionController::Routing::Routes, but that's now deprecated in favor of Rails.application.routes). You can then check the routing based on a URL:
>> r.recognize_path "/station/index/42.html"
=> {:controller=>"station", :action=>"index", :format=>"html", :id=>"42"}
and see what URL is generated for a given controller/action/parameters combination:
>> r.generate :controller => :station, :action=> :index, :id=>42
=> /station/index/42
Thanks, Zobie!
In the console of a Rails 3.2 app:
# include routing and URL helpers
include ActionDispatch::Routing
include Rails.application.routes.url_helpers
# use routes normally
users_path #=> "/users"
Basically(if I understood your question right) it boils down to including the UrlWriter Module:
include ActionController::UrlWriter
root_path
=> "/"
Or you can prepend app to the calls in the console e.g.:
ruby-1.9.2-p136 :002 > app.root_path
=> "/"
(This is all Rails v. 3.0.3)
running the routes command from your project directory will display your routing:
rake routes
is this what you had in mind?
If you are seeing errors like
ActionController::RoutingError: No route matches
Where it should be working, you may be using a rails gem or engine that does something like Spree does where it prepends routes, you may need to do something else to view routes in console.
In spree's case, this is in the routes file
Spree::Core::Engine.routes.prepend do
...
end
And to work like #mike-blythe suggests, you would then do this before generate or recognize_path.
r = Spree::Core::Engine.routes

Resources