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

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.

Related

Making Rails Resource and Custom Routes Conflict Work

I am new to rails and was wondering how I can make this work. I want a URL to look like this:
http://localhost:3000/businesses/coldfire-gundam
using this route:
match "/businesses/:permalink", :to => "businesses#show", :as => :business_permalink
however when I place this route before this:
resources :businesses
any call to /businesses/1 (1 as param[:id]) does not work anymore, obviously because it is caught by the permalink declaration
how can I make it work then?
You need a way to differentiate /businesses/:id and /businesses/:permalink. The :id should always be numeric (unless of course you're using MongoDB) so if you can force your :permalink to always contain something non-numeric then a simple :constraints should do the trick:
match '/businesses/:permalink', :to => 'businesses#show`, :constraints => { :permalink => /.*\D/ }, :as => :business_permalink
The /.*\D/ forces the route to only match if :permalink contains at least one non-numeric character. You need the .* because route regexes are implicitly anchored at the beginning.
If you happen to be using MongoDB then your :id will probably be a hex BSON ID so you'd want to use /.*\H/ as your constraint and you'd want some way to ensure that your :permalink always contains at least one non-hex character.
Once all that's in place you can put your match "/businesses/:permalink" before your resources :businesses in routes.rb and everything should work fine. And routes are checked in the same order that they appear in routes.rb so you will want your match before your resources.
I would suggest using the friendly_id gem for creating permalink routes. This will handle most of the 'magic' for you in an easily reusable way.
Resources for the gem and railscast:
https://github.com/norman/friendly_id
http://railscasts.com/episodes/314-pretty-urls-with-friendlyid

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 "pretty URLs", using entries/23 or 2011/07/some-post-slug-here for creating URLs via helpers

I'm attempting to create "pretty URLs" for linking to posts in a blog. I want to maintain access to the blog entries via entries/23 and 2011/07/some-post-slug-here as I only generate a slug once an entry has been published (just in case the title of the posts changes, and, though not a strict requirement, I would prefer to be able to edit/delete posts via the entries/23 style URL. Currently, the appropriate part of what I have in my config/routes.rb:
root :to => 'entries#index'
resources :entries
match ':year/:month/:slug' => 'entries#show', :constraints => {
:year => /[0-9][0-9][0-9][0-9]/,
:month => /[0-9][0-9]/,
:slug => /[a-zA-Z0-9\-]+/
}, :as => :vanity_entry
and I use this (in my application helper) function for creating the links:
def appropriate_entry_path entry
if entry.published
vanity_entry_path entry.published_on.year.to_s, entry.published_on.month.to_s, entry.slug
else
entries_path entry
end
end
def appropriate_entry_url entry
if entry.published
vanity_entry_url entry.published_on.year.to_s, entry.published_on.month.to_s, entry.slug
else
entries_url entry
end
end
Basically, I check if the article is published (and therefore has a slug) and then use that URL/path helper, or otherwise use the default one.
However, when trying to use this, I get the following from Rails:
No route matches {:slug=>"try-this-one-on-for", :month=>"7", :controller=>"entries", :year=>"2011", :action=>"show"}
I have tried a few different solutions, including overriding to_param in my Entry model, however then I would have to create match routes for the edit/delete actions, and I would like to keep my routes.rb file as clean as possible. Ideally, I would also love to lose the appropriate_entry_path/appropriate_entry_url helper methods, but I'm not sure that this is possible?
Is there any thing I am missing regarding routing that might make this easier and/or is there any specific way of doing this that is the cleanest?
Thanks in advance.
You might want to take a look at friendly_id. It's a gem for creating seo friendly slugs :)
I found the issue with what I had been doing, the regex for :month in the route wanted two numbers, whereas I was only passing in one number. Anyways, I decided that the URLs look nicer (in my opinion) without the month padded to 2 digits, so I updated my route accordingly.

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.

Using named routes vs. using url_for()

When should one use named routes vs. using url_for with a {:controller => "somecontroller", :action => "someaction"} hash?
Is one preferred over the other and why? Is one more maintainable or more efficient w.r.t. performance?
It might help to understand what named routes are doing.
Defining a Named route creates a wrapper around url_for providing the options required for the created route. Routing resources creates many named routes.
With that in mind, the overhead of calling a named route as opposed to url_for with the options needed is negligible. So if you're linking to a specific resource, named routes are the way to go. They're easier to read, type and maintain.
However, don't discount url_for. It has many creative uses thanks to the way it handles missing options. It is very useful when it comes to keeping views DRY that are used from multiple nested sources. Ie: when you have a blog_posts controller and posts_controller sharing the same views.
I strongly encourage you to read the url_for documentation. To help figure out where those places it makes sense to use url_for are.
I would prefer named routes as it's shorter and does the same thing.
named route is very neat.
map.with_options :controller => "company", :action => "show", :panel => "name" do |m|
m.company '/company/:action/:id/:panel'
end
Then you can call
company_url :id => 1
If you set up your routes and resources carefully, you shouldn't need any hash routes, only named ones (either built-in via map.resource or custom map.<something> ). Hash routes are useful, if you have to create links based on dynamic content. Something like:
link_to #post.title, :controller => (#user.is_admin ? 'admin/posts' : 'public/posts'), :action => 'show', :id => #post
(This is just a forced example, but you should get the gist of it :)

Resources