25

How can I get a full url in rails?

url_for @book is returning only a path like /book/1 and not www.domain.com/book/1

Thanks (and sorry if the answer is obvious. Im learning rails!)

Victor
  • 23,172
  • 30
  • 86
  • 125

6 Answers6

67

According to the docs, this shouldn't happen. The option you're looking for is :only_path and it's false by default. What happens if you set it to false explicitly?

url_for(@book, :only_path => false)

While you can use url_for you should prefer Ryan's method when you can - book_url(@book) for a full url or book_path(@book) for the path.

Andy Gaskell
  • 31,495
  • 6
  • 74
  • 83
  • 2
    Adding :only_path => false solved it for me using rails 3.1.1 – gucki Nov 07 '11 at 11:30
  • 11
    url_for(@book, :only_path => false) raises an exception here because you've passed in 2 arguments when its expecting 1. Seems like they would build this method to accept options, but in the latest versions of rails it accepts only one: either a string/instance or a hash of options. – a moose Jan 20 '13 at 04:23
  • 1
    ```link_to(@book.title, book_path(@book, only_path: false))``` worked for me (Rails 3) – raycchan Apr 01 '13 at 22:12
  • 1
    This says that :only_path is true by default. http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html – Arcolye Apr 13 '13 at 18:25
  • @amoose In Rails 4, it is possible to pass the the hash and more arguments though an array, see [my answer](http://stackoverflow.com/a/25633769/895245). – Ciro Santilli OurBigBook.com Oct 24 '14 at 17:30
  • Worked perfectly for what I needed : ``. Note that now you can use the option key column suffixed notation rather thar prefixing it and using `=>`. – psychoslave May 05 '17 at 09:20
  • How do you get a url if it's a subdomain? `polymorphic_url` always returns the `domain.com` in my situation not `sub.domain.com` which is what I want. – Burak Kaymakci Feb 23 '20 at 11:52
23

If it's a RESTful resource you'll be able to use this:

book_url(@book)
Ryan Bigg
  • 106,965
  • 23
  • 235
  • 261
16

In Rails 4, url_for only takes one argument, so you need to pass an array with an explicit hash inside for the only_path option.

Good:

url_for([@post, @comment, {only_path: true}])

Bad:

url_for(@post, @comment, {only_path: true})
url_for([@post, @comment], {only_path: true})

From the source, url_for with an Array input just calls:

polymorphic_url([@post, @comment], {only_path: true})

as shown in @moose's answer.

As noted by @lime, only_path is generally not needed for polymorphic_url since you distinguish that with the _url _path suffixes.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 1
    This instead gives me a `#`... Will investigate. – lime Nov 04 '14 at 14:47
  • @lime weird, it seemed to work on my tests and I pushed it to gitlab: https://github.com/gitlabhq/gitlabhq/blob/652f4c8090793de4737b904b5feb11c27424f4c5/app/views/notify/_reassigned_issuable_email.text.erb#L3 Let me know if you find something. – Ciro Santilli OurBigBook.com Nov 04 '14 at 16:51
  • 1
    Yeah, I ended up using `polymorphic_url` directly. That way, I can pick between `_url` and `_path` in the method name instead of passing a hash. Still don't know what caused the error though. – lime Nov 05 '14 at 09:04
5

It seems that this would work:

url_for(@book)

But it does not. The url_for method accepts only one argument, which can be either a string, an instance of a model, or a hash of options. This is rather unfortunate, as it would seem like you may need to link to @book and add options like :only_path or :host as well.

One way around it is to use polymorphic_url, which would render the correct absolute url even though your model is (likely) not actually polymorphic:

polymorphic_url(@book, :host => "domain.com")

Perhaps the best route would be to use a named route, which is set up automatically for you when declaring resources in your routes or using the :as option:

# in routes.rb:
resources :books
# or
get "books/:id" => "books#show", as: :book

# in your view:
book_path(@book, :host => "domain.com")
a moose
  • 311
  • 4
  • 4
  • You don't need to pass the 'host' parameter to polymorphic_url. To get the relative path you can use polymorphic_path. – Wheeyls Feb 09 '13 at 20:08
2

Use the :host option. For example, you can use:

url_for(@book, :host => "domain.com")

Note: with Rails 3 and above, use polymorphic_url instead of url_for.

Joshua Muheim
  • 12,617
  • 9
  • 76
  • 152
venables
  • 2,584
  • 2
  • 17
  • 17
  • 7
    I don't think this is supported in Rails 3 - might be better to use polymorphic_url – amaseuk May 10 '12 at 16:55
  • 1
    This does not work with the latest releases of Rails (> 3.2 and maybe even 3.1). url_for accepts only one argument, which can be either a string, an instance of a model, or a hash of options. – a moose Jan 20 '13 at 04:22
  • 2
    In rails 4 `url_for` calls `polymorphic_url`. – Ciro Santilli OurBigBook.com Sep 02 '14 at 23:11
  • Here's a link to `polymorphic_url` http://api.rubyonrails.org/classes/ActionDispatch/Routing/PolymorphicRoutes.html I used it with an object like so `polymorphic_url(object, subdomain: "something")` – Clam Feb 07 '18 at 04:15
2

In Rails 5, if you want the full url for the current controller/action (== current page), just use:

url_for(only_path: false)

Long answer:

In Rails 5, url_for in a view is ActionView::RoutingUrlFor#url_for. If you look at it's source code (https://api.rubyonrails.org/classes/ActionView/RoutingUrlFor.html#method-i-url_for), you'll see if you pass a Hash (keyword parameters are cast into a Hash by Ruby), it actually calls super, thus invoking the method of same name in it's ancestor.

ActionView::RoutingUrlFor.ancestors reveals that it's first ancestor is ActionDispatch::Routing::UrlFor.

Checking it's source code (https://api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html#method-i-url_for), you'll read this:

Missing routes keys may be filled in from the current request's parameters (e.g. :controller, :action, :id and any other parameters that are placed in the path).

This is very nice, since it will build automatically a URL for you for the current page (or path, if you just invoke url_for without the only_path: false). It will also intelligently ignore the query string params; if you need to merge those, you can use url_for(request.params.merge({arbitrary_argument:'value'})).

sandre89
  • 5,218
  • 2
  • 43
  • 64