Rails route if no route matched - ruby-on-rails

Is there a solution to redirect the user to a specific controller#action if no route matched? I had a "last rule" like this:
match ":rest" => "application#notfound", :constraints => { :rest => /.*/ }
to redirect all "other" stuff to application#notfound. The problem is that plugins with own routes where set below shis rule and never gets called.

Make a catch-all route and put it as the last rule in your routes.rb file.
match "*rest" => "application#notfound"
you also get whatever the path was as a parameter thru params[:rest] in your controller.

You are definitely not the only person having this problem. I know it's frustrating, but give it some time - I'm confident the Rails team will put together something simple and elegant. I'm in a similar position, only I need to know the incorrect url resource the user entered.
A quick Google search and I found this article demonstrating a full solution to the Rails 3.0 rescue_from ActionController::RoutingError problem. The solution involves Route Globbing and solves my need to both handle incorrect urls and capture the url entered. Hope this helps!

Put this rule last.. Routing matches from top to bottom so if it did find a match then it stops there.

Maybe it's not the best approach, but it will works while you don't find better solution
for rails 2.3, at the application controller, catch the exception like
rescue_from(ActionController::RoutingError) { redirect_to "/xpto" #add your code here }
Rails 3
At initializer put a code like:
module ActionDispatch
class ShowExceptions
def render_exception(env, exception)
if exception.kind_of? ActionController::RoutingError
render(500, 'it was routing error')
else
render(500, "some other error")
end
end
end
end
or something more clean like:
https://gist.github.com/522944
https://gist.github.com/522924
or:
match '/:anything', :to => "home#routing_error", :constraints => { :anything => /.*/ }
but maybe this last match won't be good for you as it'll override all routes from plugins/engines. I think that best solution is to use custom rack middleware for handling special cases.

Related

Nested routes in rails

I am someone who has always liked sinatra better than rails, and has never had to do a large enough scale project that rails was required (all the sources I have read say that rails is better for larger scale projects) and now I do have to do a large scale project. I have gotten very confused with the url structure of rails. What I am trying to do is the rails equivalent of this:
get "/" do
erb :index
end
get "/home" do
erb :dashboard
end
get "/home/profile" do
erb :profile
end
get "/home/friends" do
erb :friends
end
In the first one I understand that I should put in app/routes.rb I should put root home#index and in the home controller I should put def index end.
In the second one, I understand that I should do the same except replacing index with home.
But for the third and forth ones I have no idea what to do.
Also, is the a RESTful way to do the first two?
You probably want something like this
root 'home#index'
get 'home' => 'home#dashboard'
get 'home/profile' => 'home#profile'
get 'home/friends' => 'home#friends'
remember to use the command rake routes to see all your routes, where they lead and what their names are (if they have any)
I never understood what RESTful means, so someone else will have to answer that part of your question.
K M Rakibul Islam has shown you what can be called a "resourceful" way to do routes (because it uses the keyword resources) but it looks like you're just doing the static pages at this stage, so it's not necessary.
The simplest way to do routes is with this formula:
method url => controller::action, as: route_name
where method can be get, post, patch or delete so you can have different actions linked to the same URL depending on the method the request uses.
Putting a name on the route is optional, but it gives you a clean way to use the route in your views (route_name_path)
When you start making models then you'll find that using the resources keyword comes in handy. Read about it.
You can have this:
resources :home do
collection do
get :profile
end
collection do
get :friends
end
end
end
This will give you routes like this:
profile_home_index GET /home/profile(.:format) home#profile
friends_home_index GET /home/friends(.:format) home#friends
The standard way of declaring the root path:
root 'home#index'
And for the 2nd one, you have to do:
get 'home' => 'home#dashboard'
which will give you this route:
GET /home(.:format) home#dashboard
One route can be defined in many ways that works. But, Rails has conventions that should be followed while defining routes in your Rails app.
I would highly recommend you to take a look at the Rails Routing Guide

Rails catch-all/globbing routes

I am using rails 3.0.14, and I am constructing routes.rb using the resourceful style. I'd like to have a wildcard route that catches all requests that do not match to any route stated.
What's the appropriate way to construct such a route?
put
match '*path' => 'your_controller#your_action'
at the end of the routes.rb file. This is important, since the routes are stepped through top down.
See also http://guides.rubyonrails.org/routing.html -> 3.10
For Rail 4, you need to specify the request type:
match "*path", to: "application#custom_action", via: :all
As others have said, put this at the very bottom of your routes file.
It is not mandatory to use exactly "path" in the match '*path' statement. You can set a whatever token there:
get "*string1"
or
get "*string2"
Rails will assign your real HTTP-query to the param named after your token, example:
get "*user" => "users#show"
in console:
Started GET "/john" ....
Processing by UsersController#show as HTML
Parameters: {"user"=>"john"}
You can use more than one asterisks, say get "*id*user". But in this case you will get some unpredictable result, because Rails processes 2 or more asterisks "in an intuitive way" - for more info see http://guides.rubyonrails.org/routing.html#route-globbing-and-wildcard-segments
In addition to #steel and #awenkhh, I recommend adding the following to that route's controller action
respond_to do |format|
format.html
# other formats you already support
format.all { render text: '' }
end
Otherwise, you'll wind up with some ActionView::MissingTemplate: Missing template errors for formats that you weren't expecting.
[rant]Particularly helpful for those people trying erroneous attack vectors around /wp-admin/css/wp-admin.css and the like. I seem to get about 100 requests for /wp-admin/* a day, from super annoying people who apparently would like me to get a more expensive Rollbar account plan.[/rant]

Set Up Route for Accessing Private S3 Content

I've been following
https://github.com/thoughtbot/paperclip/wiki/Restricting-Access-to-Objects-Stored-on-Amazon-S3
and
Rails 3, paperclip + S3 - Howto Store for an Instance and Protect Access to try and get Paperclip's expiring links to work. I believe most of what I'm running into is one of the routing variety.
In my pieces_controller I put a method in like this
def download
redirect_to #asset.asset.expiring_url(1000)
end
And then in my routes, I put this:
match "pieces/download"
Then in my view I have:
<%= link_to download_asset_path(piece)%>
It would seem to be far from working, and I'm not sure what is messed up. I know I'm getting routing errors for one, but it's also telling me that my download_asset_path is undefined, which is likely also routing related... I feel like I'm doing everything all wrong.
Tearing my hair out. Thanks!
Try modifying your routes file to:
match 'pieces/download' => 'pieces#download', :as => 'download_asset'
Your match needs to tell which controller#action to go to, and the as option will allow you to name the route download_asset_path.
If your pieces controller is for a Piece resource it could be cleaner like:
resources :pieces do
member do
get :download
end
end
But then you would want to change the link to:
link_to 'Link text', download_piece_path(piece)
For further reading: http://guides.rubyonrails.org/routing.html

make pretty url with routes.rb

I would like to do something to this effect, I believe:
map.connect 'show/:company_name/:id',
:controller => 'companies',
:action => 'show'
Basically, each time the show action is called, I would like it to take the company_name param and place it into the url as such (show/:company_name/:id)
However, it seems I am using old (rails 2.x routing api) and cannot use map.connect without getting an error. How can I upgrade this?
Is there some way to do this with "match"?
Thanks!
===================
This is the error I see when I try to use map.connect:
undefined local variable or method `map' for #<ActionDispatch::Routing::Mapper:0x103757458>
I think your routes lack a "/" symbol in the first line.
Try this:
match '/show/:company_name/:id' => 'companies#show'
You can check your routes path with command rake routes.
--
Besides, the show action is the default RESTful method in Rails. I'll suggest you change a equivalent word, and reserve "show" action for future or other situation.
In Rails convention, you can write resources :companies, and the path will be /companies/:id using show action.
Some adjustment, in app/models/company.rb
def to_param
self.name
end
So your url will look like http://yourdoamin.com/companies/37signals.
In app/controllers/companies_controller.rb
#company = Company.find_by_name(params[:id])
If I'm understanding your goal, try
match 'companies/show/:company_name/:id' => 'companies#show'

restful route customization

How can i customize restful route urls to friendly urls like stackoverflow ?
i have
stackoverflow.com/questions/424/
and i want to have
stackoverflow.com/questions/424/title-of-the-page
map.resources :questions
map.friendly 'questions/:id/:title', :controller => 'questions', :action => 'show'
These are my final customizations. Any better ideas ?
If there's only one controller you want to do this with, the simplest solution would probably be to add a route with an ignored parameter, like so:
# config/routes.rb
map.connect 'questions/:id/:ignored', :controller => 'questions', :action => 'show'
Make sure you put this before the default routes at the bottom of that file. Or, even better, comment them out if you're using named routes and resources (as suggested in the auto-generated comments).
StackOverflow ignores the string second parameter at request processing time. At URL construction time it adds it for humans and (probably) SEO.
I'd start by looking at the capabilities of something like friendly_id and see if those aren't what you're looking for...

Resources