Using "default_url_options" for preserving locale in URLs -- status?

1,649 views
Skip to first unread message

Karel Minarik

unread,
Oct 22, 2008, 12:51:59 PM10/22/08
to rails-i18n
Hi,

a while ago Iain mentioned the "default_url_options" method in Rails,
which could be just what we need for preserving locale in URLs (thus
being restafarians! :)

Have you looked into any further, Iain? Has anybody else? It really
looks like this would be perfect & transparent solution.

Here are the docs:

http://www.railsbrain.com/api/rails-2.1.0/doc/index.html?a=M000494&name=default_url_options

Karel

> From: "Iain Hecker" <i...@iain.nl>
> Date: Oct 3, 3:50 pm
> Subject: Am I doing it right? (translating my first app)
> To: rails-i18n
>
> ...
>
> Rails seems to have an answer to it, called default_url_options[1],
> but it doesn't seem to work. I've overwritten the method like the api
> tells me, but somehow it is ignored into generating the path. It is
> called, because it will break if I raise somthing in it. The options
> passed to it are what you'd expect (containing all the parameters
> you'd pass to url_for)
>
> Here's my method:
>
> def default_url_options(options = {})
> { :locale => I18n.locale }
> end

Iain Hecker

unread,
Oct 22, 2008, 4:18:40 PM10/22/08
to rails...@googlegroups.com
Hi,

I'm sorry, I forgot all about it... Let's recap:

The problem is that Rails assigns non-hash objects to the first
variables in the route and only after that the default_url_options get
assigned. So if you have user_url(1) for routes like
"/:locale/users/:id" then 1 will be assigned to :locale, and after
that the default_url_options kick in. They want to set :locale to
"en-US", but there is no :locale left, so it appends it ?locale=en-US.
Then it raises a routing error because :id hasn't been filled.

If you don't have :locale in front, then this method works really
nice. You'd get what google uses (foo/bar?hl=en).
But I want to add the locale in front! (/en/foo/bar)

I have been wandering on lighthouse and found this ticket:
http://rails.lighthouseapp.com/projects/8994/tickets/22-default_url_options-is-being-ignored-by-named-route-optimisation

I don't know enough about the routing and url generation to solve
this, so I made a ticket:
http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1251-default_url_options-cant-be-used-with-named-routes

Iain

Karel Minarik

unread,
Oct 22, 2008, 5:19:57 PM10/22/08
to rails-i18n
Yes, indeed it behaves precisely like you describe, Iain. (I've tried
on a sample app -- one question, where do you define
`default_url_options`? I did in ApplicationController.)

Routes like `books_path` or `new_book_path` work perfect, but not any
route with params.

If this would work, it would be *awesome*, because it's so
transparent... I don't know nothing about routing internals as well,
so we are in the hands of Destiny on this one? :)

Best!,

Karel

Karel Minarik

unread,
Oct 24, 2008, 5:51:00 AM10/24/08
to rails-i18n
I did some further digging, and can confirm that the only (?) problem
so far lies in the order, in which the params in routes are filled,
precisely as Iain writes.

When you have this route definition:

map.resources :books, :path_prefix => '/:locale'

Routes like `books_path`, `new_book_path`, etc work great,
`book_path(1)` etc throw an exception, because the ID (1) gets filled
into :locale and the :id is blank.

When you call the helper like this: `book_path(I18n.locale, 1)`,
everything works fine and you get:

'/en-US/books/1'

If anyone is interested in this being fixed, and having the option to
transparently fill the locale in your routes, please visit the ticket
page http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1251
and add your +1s and comments.

Karel
> >http://rails.lighthouseapp.com/projects/8994/tickets/22-default_url_o...
>
> > I don't know enough about the routing and url generation to solve
> > this, so I made a ticket:
> >http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/12...
>
> > Iain
>
> > On Wed, Oct 22, 2008 at 18:51, Karel Minarik <karel.mina...@gmail.com> wrote:
>
> > > Hi,
>
> > > a while ago Iain mentioned the "default_url_options" method in Rails,
> > > which could be just what we need for preserving locale in URLs (thus
> > > being restafarians! :)
>
> > > Have you looked into any further, Iain? Has anybody else? It really
> > > looks like this would be perfect & transparent solution.
>
> > > Here are the docs:
>
> > >http://www.railsbrain.com/api/rails-2.1.0/doc/index.html?a=M000494&na...

Sven Fuchs

unread,
Oct 25, 2008, 5:44:34 AM10/25/08
to rails...@googlegroups.com
Hey Karel,

I'd happily +1 on that ticket :)

But I can not find any code or patch on the ticket, so what would I +1
on? Just the request?

IIRC the resource_fu plugin solves this kind of thing by "anchoring"
positioned arguments on the right side, instead of the left (like
Rails does it by default).

http://www.artweb-design.de/2007/5/13/concise-localized-rails-url-helpers-solved-twice

This won't handle "old-school", non-named urls though using
the :controller => 'foo', :action => 'bar' syntax, or will it?

Iain Hecker

unread,
Oct 25, 2008, 6:18:16 AM10/25/08
to rails...@googlegroups.com
Yes, just the request. The routing code is not something you can
easily fix. I spent a few hours on trying to figure out where the
actual parsing of arguments happen, but I can't really find the right
spot. Not like the i18n_label stuff where there was this one easy spot
which I had to change (and in the plugin override) to achieve the
effect I wanted.

Karel Minarik

unread,
Oct 25, 2008, 11:10:34 AM10/25/08
to rails-i18n
> > I'd happily +1 on that ticket :)
> > But I can not find any code or patch on the ticket, so what would I +1
> > on? Just the request?

Probably, I am not sure how the process works. I had the idea, that
+1s on the ticket mean "I am affected by this as well"?

> > This won't handle "old-school", non-named urls though using
> > the :controller => 'foo', :action => 'bar' syntax, or will it?

That would be OK, if it wouldn't mean, that it also won't handle named
routes, which I suspect is the case...

Like Iain, I have also spent an hour or so digging in the route
generation code just to try pinpoint the exact code where the params
are assigned, but to no success (not surprisingly). At least I can
confirm that Iains findings are true and exact...

This "automagic" filling of locale `:prefix` in routes would be
*really great* to have.

Karel

Raul Murciano

unread,
Oct 27, 2008, 6:21:50 PM10/27/08
to rails...@googlegroups.com
Hi Karel,

> This "automagic" filling of locale `:prefix` in routes would be
> *really great* to have.

My translated_routes plugin[1] does this kind of filling on a
different way: it generates a helper for each localized route and
replaces the original one with a dinamic one which calls the
appropiate helper. An example will explain this better than my words:
- let's say you have generated a users_path helper, and two locales:
en_US and fr_FR
- the plugin generates two helpers: users_en_us_path and
users_fr_fr_path, with their corresponding locale's param value
- the plugin replaces the original users_path helper by some code
which calls users_en_us_path if the current locale is en-US and
users_fr_fr_path if the current locale is fr-FR.

Of course all this code generation and replacement is done after
routes generation (i.e: when the app starts), so there are no serious
performance penalties once the app is working.

If somebody is interested, I have just released a new branch[2] of the
plugin, now Rails2.2-oriented to support your I18n translation API,
which is *very cool* by the way: thanks so much guys! :)

Best regards,

--
Raul Murciano - Freelance Web Developer
http://raul.murciano.net

[1] http://github.com/raul/translate_routes/tree/master
[2] http://github.com/raul/translate_routes/tree/rails2.2

José Valim

unread,
Nov 16, 2008, 8:06:49 AM11/16/08
to rails-i18n
Hi guys,

I was playing around with this and I worked out a solution which lets
url helpers locale wise:

map.user ':locale/user/:id'

Then we can do:

I18n.locale = 'en-US'
user_url(1) #=> http://host/en-US/user/1

I18n.locale = 'pt-BR'
user_url(1) #=> http://host/pt-BR/user/1

I18n.locale = 'pt-BR'
user_url('en-US', 1) #=> http://host/en-US/user/1

How it works?

If the route has a :locale segment, we add the locale to url hash
options: { :locale => I18n.locale }

Even more, if the route has a :locale segment and the number of
arguments are less than it was supposed to (for example, user_url
expects 2 arguments), we discard the :locale segment assigning
correctly the :id.

Gist is here: http://gist.github.com/25476

Tell me how it's working out for you! =)

Regards,
José Valim.

--
http://josevalim.blogspot.com/
http://www.pagestacker.com/

On Oct 22, 6:18 pm, "Iain Hecker" <i...@iain.nl> wrote:
> Hi,
>
> I'm sorry, I forgot all about it... Let's recap:
>
> The problem is that Rails assigns non-hash objects to the first
> variables in the route and only after that the default_url_options get
> assigned. So if you have user_url(1) for routes like
> "/:locale/users/:id" then 1 will be assigned to :locale, and after
> that the default_url_options kick in. They want to set :locale to
> "en-US", but there is no :locale left, so it appends it ?locale=en-US.
> Then it raises a routing error because :id hasn't been filled.
>
> If you don't have :locale in front, then this method works really
> nice. You'd get what google uses (foo/bar?hl=en).
> But I want to add the locale in front! (/en/foo/bar)
>
> I have been wandering on lighthouse and found this ticket:http://rails.lighthouseapp.com/projects/8994/tickets/22-default_url_o...
>
> I don't know enough about the routing and url generation to solve
> this, so I made a ticket:http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/12...
>
> Iain
>
> On Wed, Oct 22, 2008 at 18:51, Karel Minarik <karel.mina...@gmail.com> wrote:
>
> > Hi,
>
> > a while ago Iain mentioned the "default_url_options" method in Rails,
> > which could be just what we need for preserving locale in URLs (thus
> > being restafarians! :)
>
> > Have you looked into any further, Iain? Has anybody else? It really
> > looks like this would be perfect & transparent solution.
>
> > Here are the docs:
>
> >http://www.railsbrain.com/api/rails-2.1.0/doc/index.html?a=M000494&na...

Karel Minarik

unread,
Nov 17, 2008, 10:02:28 AM11/17/08
to rails-i18n
Thanks for the patch, José!

NZkoz recently updated the ticket:

http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1251

But I still cannot run it in my test app.

Out of desperation I have put it up on Github:
http://github.com/karmi/test_default_url_options/tree/master , so
please do tell me what I may be doing wrong.

See Lighthouse ticket for more info.

--karmi

On Nov 16, 2:06 pm, José Valim <jose.va...@gmail.com> wrote:
> Hi guys,
>
> I was playing around with this and I worked out a solution which lets
> url helpers locale wise:
>
>   map.user ':locale/user/:id'
>
> Then we can do:
>
>   I18n.locale = 'en-US'
>   user_url(1) #=>http://host/en-US/user/1
>
>   I18n.locale = 'pt-BR'
>   user_url(1) #=>http://host/pt-BR/user/1
>
>   I18n.locale = 'pt-BR'
>   user_url('en-US', 1) #=>http://host/en-US/user/1
>
> How it works?
>
> If the route has a :locale segment, we add the locale to url hash
> options: { :locale => I18n.locale }
>
> Even more, if the route has a :locale segment and the number of
> arguments are less than it was supposed to (for example, user_url
> expects 2 arguments), we discard the :locale segment assigning
> correctly the :id.
>
> Gist is here:http://gist.github.com/25476
>
> Tell me how it's working out for you! =)
>
> Regards,
> José Valim.
>
> --http://josevalim.blogspot.com/http://www.pagestacker.com/

Karel Minarik

unread,
Nov 17, 2008, 10:15:54 AM11/17/08
to rails-i18n
OK, this was quick. It will work, *not* ideally, but it's tolerable.

Head over to Lighthouse for info: http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1251

This is what you have to do:
http://github.com/karmi/test_default_url_options/commit/d55ef3335cb9b067d5089afa5896cacb1c8eb70e

--karmi

On Nov 17, 4:02 pm, Karel Minarik <karel.mina...@gmail.com> wrote:
> Thanks for the patch, José!
>
> NZkoz recently updated the ticket:
>
> http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1251
>
> But I still cannot run it in my test app.
>
> Out of desperation I have put it up on Github:http://github.com/karmi/test_default_url_options/tree/master, so

José Valim

unread,
Nov 17, 2008, 11:54:41 AM11/17/08
to rails-i18n
Karel,

The patch I sent allows you to do:

book_path(1)

And:

book_path('cz', 1)

default_url_options DOES work with positional arguments, but the
problem is that positional arguments expects a fixed number of
arguments.

I, personally, don't like the syntax: book_path(:id => 1).

I will add the patch to Lighthouse and wait for further comments! =)

José Valim
--
http://josevalim.blogspot.com
http://www.pagestacker.com

On Nov 17, 1:15 pm, Karel Minarik <karel.mina...@gmail.com> wrote:
> OK, this was quick. It will work, *not* ideally, but it's tolerable.
>
> Head over to Lighthouse for info:http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1251
>
> This is what you have to do:http://github.com/karmi/test_default_url_options/commit/d55ef3335cb9b...

Karel Minarik

unread,
Nov 18, 2008, 6:10:02 AM11/18/08
to rails-i18n
Hi José,

definitely look into that, if you can find the path thru routing.

For me, I'd say that book_path(:id => 1) is something I can live with.
Just the docs need to be updated.

Karel

On Nov 17, 5:54 pm, José Valim <jose.va...@gmail.com> wrote:
> Karel,
>
> The patch I sent allows you to do:
>
>   book_path(1)
>
> And:
>
>   book_path('cz', 1)
>
> default_url_options DOES work with positional arguments, but the
> problem is that positional arguments expects a fixed number of
> arguments.
>
> I, personally, don't like the syntax: book_path(:id => 1).
>
> I will add the patch to Lighthouse and wait for further comments! =)
>
> José Valim
> --http://josevalim.blogspot.comhttp://www.pagestacker.com

iain hecker

unread,
Jan 9, 2009, 8:48:42 PM1/9/09
to rails-i18n
Hello everybody.

It's now well into the night, but by inspecting a superb recent commit
to Rails edge [1] (done by one of the Merb guys), I believe I found
the answer to this problem.

I made it into a patch and submitted it to the previously mentioned
Lighthouse ticket [2].

What it does is, it doesn't fill routing segments provided by
default_url_options with nameless options anymore. This makes it
possible to do this:

class ApplicationController < ActionController::Base
def default_url_options(options = nil)
{ :locale => I18n.locale }
end
end

with this route:

map.resources :posts, :path_prefix => '/:locale'

so you can:

post_url(@post) # => http://www.example.com/en/posts/1

To apply it to all routes, do this:

ActionController::Routing::Routes.draw do |map|
map.with_options :path_prefix => '/:locale' do |m|
m.resources :posts
m.resources :users
m.resource :session
end
end

After this, one can simply create this before_filter to set the
locale:

def set_locale
I18n.locale = params[:locale] if params[:locale]
end


So, have a look at the patch, try it out, and if you find it okay,
please +1 it.

Hope this is right answer to an old (and stale) problem.

Cheers!
Iain Hecker
http://iain.nl/


[1] http://github.com/rails/rails/commit/a2270ef2594b97891994848138614657363f2806
[2]
http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1251-default_url_options-cant-be-used-with-named-routes#ticket-1251-15


On Nov 18 2008, 12:10 pm, Karel Minarik <karel.mina...@gmail.com>
wrote:
> Hi José,
>
> definitely look into that, if you can find the path thru routing.
>
> For me, I'd say that book_path(:id => 1) is something I can live with.
> Just the docs need to be updated.
>
> Karel
>
> On Nov 17, 5:54 pm, José Valim <jose.va...@gmail.com> wrote:
>
> > Karel,
>
> > The patch I sent allows you to do:
>
> >   book_path(1)
>
> > And:
>
> >   book_path('cz', 1)
>
> >default_url_optionsDOES work with positional arguments, but the
> > > > > > that thedefault_url_optionskick in. They want to set :locale to
> > > > > > "en-US", but there is no :locale left, so it appends it ?locale=en-US.
> > > > > > Then it raises a routing error because :id hasn't been filled.
>
> > > > > > If you don't have :locale in front, then this method works really
> > > > > > nice. You'd get what google uses (foo/bar?hl=en).
> > > > > > But I want to add the locale in front! (/en/foo/bar)
>
> > > > > > I have been wandering on lighthouse and found this ticket:http://rails.lighthouseapp.com/projects/8994/tickets/22-default_url_o...
>
> > > > > > I don't know enough about the routing and url generation to solve
> > > > > > this, so I made a ticket:http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/12...
>
> > > > > > Iain
>
> > > > > > On Wed, Oct 22, 2008 at 18:51, Karel Minarik <karel.mina...@gmail.com> wrote:
>
> > > > > > > Hi,
>
> > > > > > > a while ago Iain mentioned the "default_url_options" method in Rails,
> > > > > > > which could be just what we need for preserving locale in URLs (thus
> > > > > > > being restafarians! :)
>
> > > > > > > Have you looked into any further, Iain? Has anybody else? It really
> > > > > > > looks like this would be perfect & transparent solution.
>
> > > > > > > Here are the docs:
>
> > > > > > >http://www.railsbrain.com/api/rails-2.1.0/doc/index.html?a=M000494&na...
>
> > > > > > > Karel
>
> > > > > > >> From: "Iain Hecker" <i...@iain.nl>
> > > > > > >> Date: Oct 3, 3:50 pm
> > > > > > >> Subject: Am I doing it right? (translating my first app)
> > > > > > >> To: rails-i18n
>
> > > > > > >> ...
>
> > > > > > >> Rails seems to have an answer to it, calleddefault_url_options[1],
> > > > > > >> but it doesn't seem to work. I've overwritten the method like the api
> > > > > > >> tells me, but somehow it is ignored into generating the path. It is
> > > > > > >> called, because it will break if I raise somthing in it. The options
> > > > > > >> passed to it are what you'd expect (containing all the parameters
> > > > > > >> you'd pass to url_for)
>
> > > > > > >> Here's my method:
>
> > > > > > >>   defdefault_url_options(options = {})
> > > > > > >>     { :locale => I18n.locale }
> > > > > > >>   end
>
>
Reply all
Reply to author
Forward
0 new messages