Change paths for link_to missing out the model name - ruby-on-rails

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

Related

Rails 3 Finding the right :id in a controller using a specific route

I have my routes arranged so that when visiting the site the :id is displayed before the slug like so
match "/causes/:id/:slug" => "causes#show", :as => :cause, :via => 'get'
But I also have a nested attribute called "post" that belongs to causes like so
match "/causes/:id/:slug/posts" => "causes#posts", :via => 'get', :as => :posts
When I use this, everything works great for the causes, but not for the posts.
If I use
#post = Post.find(params[:id])
in causes or posts controller it always looks for the ID of the causes, and not the :id of the posts. So if the post :id is 9, and the cause :id is 1, and I use
#post = Post.find(params[:id])
it will always look for post[1] and not 9 or whatever the post id really is.
What am I doing wrong? Is there a way to make this work in the routes, or maybe a different way to find the id of a nested object in the controller?
I need the route to be the way I have it set up, :id/:slug...
rake routes information:
cause GET /causes/:id/:slug(.:format) causes#show
edit_cause GET /causes/:id/:slug/edit(.:format) causes#edit
PUT /causes/:id/:slug(.:format) causes#update
posts GET /causes/:id/:slug/posts(.:format) causes#posts
POST /causes/:id/:slug/posts(.:format)
PUT /causes/:id/:slug/posts(.:format) causes#update_post
DELETE /causes/:id/:slug/posts(.:format) causes#destroy_post
causes GET /causes(.:format) causes#index
POST /causes(.:format) causes#create
Any help would be great.
To solve your immediate problem, you'll want to add something like this to routes.rb
# config/routes.rb
match "/causes/:cause_id/:slug/post/:id" => "causes#update_post", :via => 'put', :as => :update_post
And then you can generate the URL in your views like this...
link_to 'Update this post', update_post_path(#cause, #post)
...and access the parameters in your controller as params[:id] (for the post) and params[:cause_id] (for the cause).
More generally, though, the way you are specifying your routes is pretty cumbersome, and I suspect you're making your life harder than it needs to be. If this were me, I would do something like
# config/routes.rb
resources :causes do
resources :posts
end
This would accomplish something pretty close to what you have now, the main difference being that it wouldn't contain slugs. I'm not sure why you need to have both slugs and IDs, maybe you could just identify your causes by their slugs? Stringex is a good gem for generating slugs, and you can set it so that slugs are guaranteed to be unique.
Here is the section of the Rails guide on nested resources
http://guides.rubyonrails.org/routing.html#nested-resources
And here is a Railscast about using slugs with nested resources
http://railscasts.com/episodes/314-pretty-urls-with-friendlyid?view=comments
Hope this helps.
This is because you're using the id of the cause, and if you're doing /causes/:id/posts shouldn't you be doing #posts = #cause.postsanyway?
I would look into the new router syntax for rails 3 if I were you, as there is a nicer way to nest resources http://guides.rubyonrails.org/routing.html
edit:
use the friendly_id gem and nest your resources, to avoid confusion follow REST best practises that resource in question is at the end so
/causes/:slug/posts/:slug

How can I rename a Rails controller with a route?

I have a controller in a Rails 3 app named "my_store." I would like to be able to use this controller as is, except replacing "my_store" in all the URL's with another name. I do not want to rename the controller file, and all the references to it. Is there a clean way to do this with just a routing statement?
If you use RESTful routes:
resources :another_name, :controller => "my_store"
Otherwise:
match "another_name" => "my_store"
If your routes are RESTful, this is pretty easy.
resources :photos, :controller => "images"
You can see how to do this and other helpful Rails routing information in the Rails routing guide.
Update, the other guys are correct, to replace all references you would change the resources name and corresponding controller in routes.rb! My answer is only good to set a specific route.
Yup, you would do this in your routes.rb using the :as option to specify
example:
match 'exit' => 'sessions#destroy', :as => :logout
source

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.

Implicit creation of helpers - routes.rb and 'match' statements

I am reading Obie Fernandez' "The Rails 3 Way", and there is a bit of it that I am not sure I understand correctly. I am new to rails, and want to make sure I understand it correctly. I have some experience with vanilla Ruby. Not much, but some.
The text in question is as follows: (regarding routing and the config/routes.rb file)
"...
By creating a route like
match 'auctions/:id' => "auction#show", :as => 'auction'
you gain the ability to use nice helper methods in situations like
link_to item.description, auction_path(item.auction)
..."
My question is, specifically what part of match 'auctions/:id' => "auction#show", :as => 'auction' creates the helper functions? (such as link_to auction and auction_path() ) Is it the :as => 'auction' part? Would any helpers be created without appending :as => 'auction'?
My confusion stems from other guides I have seen where this is omitted, and yet helpers seem to be created regardless. What specifically does rails use in match statements in the routes.rb file to create helpers? If it isn't the :as => 'auction' part, then what is the specific purpose of appending this to the match statement?
I know this seems like a super basic question, but this detail seems to get glossed over in the texts I have read thus far. Thanks in advance for any light you can shed on this.
I just tried this:
match "alfa/beta", to: 'users#new'
In this case, even without an :as => 'named_route', I got for free the following helper
alfa_beta_path
which, as expected, points to users#new.
So, it seems that helpers are also automagically generated by parsing the route's string, in case there is no :as specification.
Yes, it is the :as => 'named_route' part that creates the named route (which in turn creates the helpers). As for leaving it off, are you referring to instances of resources :something in routes.rb? The resources method generates a set of URL helpers based on the name of the resource automagically.

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