Rails 4.2+: глубокое вложение ресурсов, когда необходимо отобразить данные из всей цепочки ресурсов
Я знаком с рекомендацией не вкладывать более 1 уровня в глубину, и я понимаю различные дискуссии о том, чтобы иметь как можно более короткие URL-адреса как внутри, так и вне кода.
На большинство вопросов о Stackru и поиске в Google я ответил на это, представив варианты использования, при которых не требуется доступ ко всем элементам во всей цепочке.
Но что вы делаете, когда вам нужно получить доступ к родительским ресурсам дальше по цепочке для каждой страницы, с которой вы работаете?
/{ACCOUNT_SLUG}/applications/{APPLICATION_UUID}/borrower/employments/{UUID}
Когда имеешь дело с одним employment
запись, я должен отобразить информацию об учетной записи взять от родителя account
объект через ACCOUNT_SLUG
, так же как application
Информация. И технически мой borrower
это также запрос к БД, но, поскольку для каждого приложения есть только 1, мне не нужно добавлять id/slug в URL.
Общий совет - сделать что-то вроде:
/employments/{UUID}
Но если я это сделаю, то в коде моего контроллера (и в других местах) мне все равно придется сделать:
@employment = Employment.find_by(uuid: params[:uuid])
@account = @employment.borrower.application.account
Поэтому я должен пройти всю цепочку родительских ассоциаций и выполнить эти запросы к базе данных ассоциаций. Как можно разрешить такую ситуацию, когда необходимо сохранить глубокую вложенную связь от первого родителя до последнего ребенка?
1: Добавить атрибуты ассоциации для всех детей
class Employment
belongs_to :borrower
belongs_to :application
belongs_to :account
end
Теперь у меня есть куча ассоциаций, которые происходят повсюду, просто чтобы пройти ясную цепь. Это похоже на "ад зависимости"?...
2: идти с глубокими вложенными маршрутами; Github делает это
Я заметил, что Github на самом деле использует глубокие вложенные маршруты:
github.com/{USERNAME}/{REPO}/settings/hooks
Хотя они не так глубоко вложены, как мой сценарий использования, они все же вкладывают все под username
а также repo
и если вы перечислите их подробный URL, то это:
/github.com/accounts/{USERNAME}/repos/{REPO_NAME}/settings/hooks
Кто-нибудь знает, есть ли у Github метод оптимизации этого глубокого вложения, или они просто ищут account
а также repo
с каждым запросом и кусанием запроса к БД (вероятно, не такая уж большая проблема...)?
3: Глубокое вложение маршрутов, но создайте свои собственные помощники URL, чтобы держать его в чистоте
С помощью /{ACOUNT_SLUG}/applications/{APPLICATION_UUID}/borrower/employments/{UUID}
, помощник URL будет выглядеть примерно так:
account_applications_borrower_employments_path(@account, @application, @borrower, @employment)
Это можно исправить с помощью некоторых помощников:
def borrower_employment_path(@employment)
@borrower = @employment.borrower
@application = @borrower.application
@account = @application.account
account_applications_borrower_employments_path(@account, @application, @borrower, @employment)
end
1 ответ
Очень подробный вопрос. Вроде поздно, чтобы ответить, но в прошлом, когда проблема с вложенными ресурсами укусила меня, обычно заканчивалось тем, что мне нужно было пересмотреть способ реляционного моделирования моей базы данных.
Из возможных решений, которые вы предложили, номер 1, вероятно, является наилучшим, учитывая самоуверенный характер платформы Rails. Ассоциации Rails очень мощные, и их использование полезно по мере масштабирования вашего приложения.
Решение проблем, связанных с зависимостями между вашими моделями:
Не видя вашей схемы, я могу только догадываться, но ваше моделирование может выглядеть так:
Class Account
has_many :applications
end
Class Application
belongs_to :account
has_one :borrower
has_one :employment
end
Class Borrower
belongs_to :application
end
Class Employment
belongs_to :application
has_one :account, through: :application
end
Это мое лучшее предположение из рассекающей информации выше. С помощью этого моделирования вы сможете сделать это в действии контроллера:
def action_name
@employment = Employment.find_by(uuid: params[:uuid])
@account = @employment.account
end
Вы могли бы добавить дополнительные ассоциации, скажем, если бы вы хотели это сделать: @ job.borrower
добавляя:
class Employment
belongs_to :application
has_one :account, through: :application
has_one :borrower, through: :application
end
Я всегда хорошо читаю эту статью один раз и просто, чтобы она была свежей:
http://guides.rubyonrails.org/association_basics.html
Rails, как правило, препятствует сильно вложенной маршрутизации, несмотря на реализацию Github их приложения: