Best way to do Github-style URLS (/user/repo)

102 views
Skip to first unread message

Chris Lloyd

unread,
Sep 18, 2011, 10:36:10 PM9/18/11
to rails-...@googlegroups.com
Hello friends!

What is the current state of the art when trying to construct nice nested URLs? Don't know what I mean? Check out these bad boys:


Say I was building Github (I'm not!), I'd really just like to link_to @repo rather than every time having to specify link_to [@repo.owner, @repo]. That's not too much to ask is it?

I started down the road of using to param in the model:

    def to_param
      [owner, slug].to_param
    end

But that didn't end up working as I'd basically have to write my own catch all router in my app (as /user and /user/repo would be covered by the same route). I then tried overriding the default path helpers:

    def repo_path(repo)
      super(repo.owner, repo)
    end

However this has quickly turned into a cluster-cussin' mess as I have to make new helpers for each nested route. Is there some Rails-ey way of doing something like this? It seems like a common enough problem that somebody far smarter than me has already thought up a solution.

Cheers!

Chris

Dan Cheail

unread,
Sep 18, 2011, 10:49:37 PM9/18/11
to rails-...@googlegroups.com
Say I was building Github (I'm not!), I'd really just like to link_to @repo rather than every time having to specify link_to [@repo.owner, @repo]. That's not too much to ask is it?

What about a simple helper?

# app/helpers/application_helper
module ApplicationHelper
  def link_to_repo(caption, repo)
    link_to caption, [repo.owner, repo]
  end
end

<%= link_to_repo(@repo) %>

Simple, straight-forward, no magic.

Ryan Bigg

unread,
Sep 19, 2011, 12:36:44 AM9/19/11
to rails-...@googlegroups.com
Yeah I think this would be the way to do it. A helper is really suited for stuff like this.


--
You received this message because you are subscribed to the Google Groups "Ruby or Rails Oceania" group.
To post to this group, send email to rails-...@googlegroups.com.
To unsubscribe from this group, send email to rails-oceani...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/rails-oceania?hl=en.

Chris Lloyd

unread,
Sep 19, 2011, 1:19:44 AM9/19/11
to rails-...@googlegroups.com
I guess a helper feels a bit restrictive to me. I guess ideally it should just work like regular routes. The object has all the information it needs to generate a valid route. Also I've got a bunch of URLs for other actions like:

    [:branch, repo]

Helpers would get really complicated in that case and also you'd have to keep mimicking Rails' conventions (like when link_to takes a block for the caption).

The idea with overriding the *_path helpers is that anywhere I linked to a repo it would produce a pretty URL (and also in mailers where the full url is needed).

I guess this sounds simple on the surface but I've been doing what I do best and Googling a lot but nobody seems to have a clean solution (or isn't sharing it).

Chris

Ben Hoskings

unread,
Sep 19, 2011, 1:35:08 AM9/19/11
to rails-...@googlegroups.com
I've tried to go down this road before. In fact, I tried to build a gem to do it:

https://github.com/benhoskings/hammock

It kinda worked (well, it totally worked, in a limited set of cases), but the problem is that there are a lot of assumptions hidden in there.

The problem is that context really starts to creep in -- there'll be some exception to the "always use /:user_id/:repo_name" rule (e.g. on Repo#update, etc) that an association-aware or nesting-aware route helper doesn't know about.

If it were me, I'd just use helpers like Dan suggested until I had 3 or 4 of them, and then try to extract something more involved. You never know, you might get away with just a couple of one-liners :)

- Ben

> --
> You received this message because you are subscribed to the Google Groups "Ruby or Rails Oceania" group.

> To view this discussion on the web visit https://groups.google.com/d/msg/rails-oceania/-/nL91ta0AjSAJ.

Nicholas Faiz

unread,
Sep 19, 2011, 6:33:09 PM9/19/11
to rails-...@googlegroups.com
I do this in Inkling. The step I've taken which others haven't in their replies is to use a routing constraint - see https://github.com/tfw/inkling/blob/master/lib/inkling/routing.rb .

Then my routes look something like: 

  inkling_match(:archive_studies)
  inkling_match(:archive_catalogs)
  inkling_match(:pages)

Essentially, these routes say - build a route to a model called Page. Interrogate each request to see if a Page can match the current request. If it can, look up the id of the Page and place it in params and pass the request to the PagesController#show method. 

Building a link to the object is simple - link_to foo.title, foo.urn (where urn is a method that maps to the path which the routing constraint understands). Then, of course, your model uses the to_param solution for the clean URL.

I do this for CMSy apps (well, I call it knowledge management, as the content is usually more than a simple page). And the approach I've taken reflects that (all you have to  do is write acts_as_inkling on a model and it gets this behaviour). But you could probably use routing constraints for what you want - see http://guides.rubyonrails.org/routing.html#advanced-constraints

You were almost there when you reached the routing layer. You don't necessarily have to write the catch-all.

Hope this answered your question.

Cheers,
Nicholas

Fred Wu

unread,
Sep 20, 2011, 12:02:15 AM9/20/11
to rails-...@googlegroups.com
Inherited Resources does this. :)

https://github.com/josevalim/inherited_resources


Reply all
Reply to author
Forward
0 new messages