Dynamic Routing not rendering - ruby-on-rails

So, I have a named route:
match 'ip/get/:ip' => 'ip_addresses#show', :via => :get
As you can see, I'd like the ip (after 'get') to be dynamic, but I keep getting a routing error when I try it out. Here are my routes:
root / ip_addresses#index
ip_add POST /ip/add(.:format) ip_addresses#create
GET /ip/add(.:format) ip_addresses#new
ip_all GET /ip/all(.:format) ip_addresses#index
GET /ip/get/:ip(.:format) ip_addresses#show
DELETE /ip/all(.:format) ip_addresses#destroy
And here's my show action:
def show
IpAddress.find(params[:id])
end
EDIT: Routing error:
ActionController::RoutingError (No route matches [GET] "/ip/get/1.2.3.4"):
I've read the Rails Routing from the Outside In Guide (http://guides.rubyonrails.org/routing.html) but naturally I may be overlooking something. Any help is appreciated. Thanks!

The answer to your question lays in article you gave.
Take a look at section:
By default dynamic segments don’t accept dots – this is because the
dot is used as a separator for formatted routes. If you need to use a
dot within a dynamic segment add a constraint which overrides this –
for example :id => /[^/]+/ allows anything except a slash.
Look at the example there:
match ':controller(/:action(/:id))', :controller => /admin\/[^\/]+/
So in your example I believe it would be:
match 'ip/get/:ip' => 'ip_addresses#show', :id => /[^/]+/ , :via => :get
And also change params[:id] to params[:ip]

Related

Rails implement an API using Routes pointing to existing controller actions

I have a Rails app that does everything I need it to do via a HTML interface, now I'd like to bolt on an API providing access to bits of the functionality.
How would I do this selective forwarding of some API controller actions to another controller's actions using the Routes.rb?
I have tried the following:
My regular controller routes work fine using:
match 'stuff' => 'stuff#index'
get 'stuff/index'
get 'stuff/some_get_action'
post 'stuff/some_post_action'
But then when I try for my API:
match 'api' => 'api#index'
match 'api/some_get_action' => 'stuff#some_get_action', :via => :get
match 'api/some_post_action' => 'stuff#some_post_action', :via => :post
or...
match 'api' => 'api#index'
get 'api/some_get_action', :to => 'stuff#some_get_action'
post 'api/some_post_action', :to => 'stuff#some_post_action'
I get an error. When I navigate to /api/index to server a HTML page that contains forms for testing the API URLs the url_for raises a 'Routing error' exception saying 'No route matches...'.
You may want to include ':as => ' and define your route names that you may be using as your link paths.
get 'api/some_get_action' => 'stuff#some_get_action', :as => 'some_get_action'
and the link path in your index file will have 'some_get_action_path'. Not sure that 'match' or 'get' automatically resolves to a path name, which by setting ':as' it definitely will.
I like your idea for setting up this page for testing. I'm always doing it in the console, which is surely more difficult than simply clicking a link. Your links probably need to infer that they are :json requests, not :http.

Change paths for link_to missing out the model name

I've managed to get my routes set up (with help from these questions Routing without the model name and Permalinks with Ruby on Rails (dynamic routes)) so that articles can be accessed via my-domain/permalink rather than my-domain/articles/permalink or, the original my-domain/articles/id
Now I would like to make the paths that the link_to helper gives point to /permalink rather than /articles/permalink. I've looked at http://guides.rubyonrails.org/routing.html#overriding-the-named-helpers and see how I could redirect to eg. /images/permalink, but can't see how to have no model name present.
Can anyone suggest a way to do this?
Using :as on a match ... line in your routes file will make this work (it operates a little differently from using :as on a resources ... line):
match '/:id' => 'articles#show', :as => "article_permalink", :via => 'get'
Then you can do:
link_to "Show", article_permalink_path(article)
See Naming Routes in the Rails Guides

Rails routes match starting with a numeric character

I have a an url like "http://domain.com/1and2" that I wanted to set up in config/routes.rb like this:
match "1and2" => "frontpage#oneandtwo"
(with controllers and views in place).
Running 'rake routes' outputs 'Invalid route name: '1and2''. This error is apparently triggered when you start a match with a numeric character.
Is there a workaround, or am I doing it wrong?
match '/:id' => "frontpage#oneandtwo", :constraints => {:id => /1and2/}
The root of the problem is that methods in Ruby cannot start with a number. Since Rails routing will generate an accessor method for each route, you'll get an error.
You can pass by the issue by naming your route differently with the :as parameter.
I had an issue where I wanted to redirect from a URI /2012 -- which resulted in an error. I corrected it by adding :as => current_year to the routing:
match "/#{Time.now.year}" => redirect("..."), :as => :current_year
Further information:
https://github.com/rails/rails/issues/3224

Routing more than one action to the same controller and action

I am trying to get something like this working on my Rails app:
match '/:language', :to => 'posts#search_result'
match '/:tag', :to => 'posts#search_result'
match '/:language/:tag', :to => 'posts#search_result'
I am using this search_result action to filter some posts depending of the language and the tag.
The problem is that sometimes :tag will be nil or :language will be nil; so i have these 3 possibilities when calling the action:
<%=link_to "Spanish", {:controller => 'posts', :action => 'search_result', :language => "spanish"} %>
<%= link_to "Spanish", {:controller => 'posts', :action => 'search_result', :language => "spanish", :tag => #tag} %>
<%=link_to "#{tag.name}", {:controller => 'posts', :action => 'search_result', :tag => #tag} %>
And I am expection to have URLs like:
/spanish (for the first case)
/spanish/rails (where rails is a tag, for the second case)
/rails (for the third case)
But right now i am getting the rigth thing for the first and third case, but for the second case i am getting:
/spanish?tag=rails
or again /spanish (depending on if i had selected a tag first or a language first).
I hope i explained myself right. Any idea??. thanks!.
The router cannot tell the difference between a :language and a :tag.
Just because your routes say "language" and "tag" when you are constructing your code in the view.. remember that in the html this has been translated into just plain ole URLs eg /spanish or /rails
the route then has to be figured out from this URL.
Now as I said, the router can't tell that a particular word is a language or a tag... and the plain-ole-URL doesn't have the word "tag" or "language" in it anymore... so your two routes here:
match '/:language', :to => 'posts#search_result'
match '/:tag', :to => 'posts#search_result'
are both the same kind of URL
Just a single token after the slash. Here are some examples that will match that route:
/greek
/spanish
/rails
/urdu
/whatever
They will all match the first route that matches on "a single token after a slash"... which means your router will match all of them to the "language" route and will never ever match the "/:tag" route, because it's already matched on the route above.
he he: it's all greek to the router ;)
Edit:
Hi, this is helping me a lot to understand how routing works.. but still i can't see it clear. I understand what you said, and so basically i understand i should do something like match '/tags/:tag to at least only route to posts#search_result the URLS starting by /tag .. what would be a solution??
yes, "/tags/:tag" would be clear and unambiguous, but if you want it to truly flexible in tag vs language you would be better served by the simple:
match '/posts/search', :to => 'posts#search_result'
which can use any of your link_to examples above to generate eg:
/posts/search?tag=rails
/posts/search?language=spanish
/posts/search?language=spanish&tag=rails
It's also far more clear what is being passed and why.
The description of the third URL is "I'm searching for a set of posts which have language = spanish and tag = rails"
Your URL should reflect the resource (which in this case is a set of posts) everything else is better done as query params.
Instead of defining /:language and /:language/:tag separately, define them together, with /:tag as an optional URI element.
match '/:language(/:tag)', :to => 'posts#search_result'
I believe routes are matched (and URIs generated from them) in the order that the routes are defined. You defined /:lang before you defined /:lang/:tag, so it matched /:lang and made :tag a GET parameter. I suppose you could optimize the ordering of your definitions, but I believe using the above syntax is the preferred method.

Question about routes.rb

Rails newbie here.
Can anyone please explain the difference to me between the following lines of code:
match '/' => 'posts#index'
and
match '/' => 'posts#index', :as => 'posts'
The reason I'm asking is because when I use the latter code, I cannot create new posts :|
The latter is creating a named route. It creates a helper that you can call from your views, in this case, posts_path & posts_url.
That being said, I'm not sure how you are able to create new posts with either of those as you are not defining the posts#new or posts#create. Is there more to your routes file than these? Also, I'm not sure if it's a requirement or not, but you should pass your :as option as a symbol, so :as => :posts.
For reference, you can run rake routes from console and see a list of all the routes that are defined in your application. You'll also see how they are named—that's the column all the way to the right—which you can then append _path or _url to.

Resources