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 их приложения:

http://guides.rubyonrails.org/routing.html

Другие вопросы по тегам