GitHub

Tensho

Заметки непутевого программиста

Rails Routing Path vs URL

22/02/2021

Представим, что у нас имеется простой ресурсный маршрут для пользователей:

# config/routes.rb

resources :users

В Rails впилено куча магии для поддержки маршрутных хелперов, чтобы на базе ресурса можно было выдавать разного рода ссылки. Например, user_path возвращает относительный путь, а user_url – абсолютный (схема, хост, порт). По умолчанию во всех Rails окружениях не настроены опции для составления полноценного URL и попытка выписать себе абсолютную ссылку заканчивается вполне ождиаемым исключением:

> Rails.application.routes.default_url_options
{}
> Rails.application.routes.url_helpers.users_path
"/users"
> Rails.application.routes.url_helpers.users_url
Traceback (most recent call last):
        1: from (irb):3
ArgumentError (Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true)

Для разных компонентов Rails, которые работают вне цикла запроса-ответа, есть отдельная настройка default_url_options. Например, хост для ActionMailer можно настроить через Rails.application.config.action_mailer.default_url_options, чтобы все ссылки в письме были “абсолютными”. Сейчас обсуждается вариант унификаиции этой настройки для всех компонентов, но пока что нужно выставлять для каждого отдельно. В частности для примера выше нужно явно выставить соответствующие опции в Rails.application.routes.default_url_options:

> Rails.application.routes.default_url_options = { protocol: 'https', host: 'www.example.com', port: 3000 }
> Rails.application.routes.url_helpers.users_path
"/users"
> Rails.application.routes.url_helpers.users_url
"https://www.example.com:3000/users"

Если не указывать схему и порт, то по умолчанию будут использоваться HTTP и неявный 80 порт.

ActiveStorage является еще одним компонентом, который опирается на маршртуные хелперы.

# app/models/user.rb

class User < ApplicationRecord
  has_one_attached :avatar
end
> Rails.application.routes.default_url_options
{}
> Rails.application.routes.url_helpers.url_for(user.avatar)
Traceback (most recent call last):
        1: from (irb):2
ArgumentError (Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true)
> Rails.application.routes.default_url_options = { host: 'www.example.com' }
> Rails.application.routes.url_helpers.url_for(user.avatar)
"http://www.example.com/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBEQT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--ba7683b438ba5be31fac57cba6385b2e15cde4db/headspace.png"

В общем, если надо выставлять абсолютные ссылки, то не забываем указывать для этого схему, хост и порт. Ну по крайней мере хост ^_^