Rails упорядочивает отношение has_many, используя сквозную таблицу - PullRequest
0 голосов
/ 15 ноября 2018

В моем приложении rails есть модель User и Campaign. Кампания has_many пользователей и кампания пользователей has_one.

Я хочу заказать пользователей в кампании по дате, когда они были добавлены в нее.

Для этого я создал сквозную таблицу с именем CampaignUser. Я думал, что смогу сделать заказ по столбцу created_at в этой таблице, но я не мог найти простой способ сделать это. Смотрите классы ниже:

class Campaign < ApplicationRecord
  has_many :campaign_users
  has_many :users, through: :campaign_users
end

class User < ApplicationRecord
  has_one :campaign, through: :campaign_users, dependent: :destroy
end

class CampaignUser < ApplicationRecord
  belongs_to :campaign
  belongs_to :user
end

В идеале я хотел бы написать такую ​​строку в своем классе Campaign:

has_many :users, through: campaign_users, -> { order(created_at: :desc) }

Где created_at относится к campaign_users, а не к users. Есть способ сделать это?

Я мог бы просто написать метод в Campaign, чтобы заказывать пользователей вручную, но тогда я должен был бы убедиться, что вместо этого я вызываю этот метод везде. Кажется, должен быть более легкий путь.

Edit:

Добавление области действия для пользователя, , как предлагается в других ответах в этом случае более проблематично. Я хочу упорядочить пользователей по свойству сквозной таблицы, а не по свойству самого пользователя. Можно ли написать следующую строку, заменив email на campaign_users.created_at или что-то подобное?

has_many :users, -> { order(email: :desc) }, :through => :campaign_users 

Ответы [ 3 ]

0 голосов
/ 16 ноября 2018

Хитрость в том, что @kevcha уже указал порядок вызовов со строкой нужного вам столбца.

Но вместо добавления предложения порядка непосредственно в ассоциацию вы можете использовать расширение ассоциации :

class Campaign < ApplicationRecord
  has_many :campaign_users
  has_many :users, through: :campaign_users do
    def order_by_join_date
      order('campaign_users.created_at DESC')
    end
  end
end

Это позволяет вам вызывать campaign.users.order_by_join_date, чтобы явно получить записи в определенном порядке.Он избегает некоторых из тех же ловушек, которые окружают область по умолчанию .

0 голосов
/ 17 ноября 2018

@ kevcha Когда я попробовал ваш ответ в точности так, как вы предлагали, я получил следующую ошибку:

синтаксическая ошибка, неожиданный '\ n', ожидание => ... mpaign_users.created_at ASC ')}

Но, когда я добавляю область сразу после has_many :users, она отлично работает:

has_many :users, -> { order('campaign_users.created_at DESC') }, through: :campaign_users

Также стоит отметить, что created_at кажется идентичным дляобъекты, созданные из прибора.Я не знал об этом.Я должен был явно установить create_at в своих приборах, чтобы мои тесты проходили.

0 голосов
/ 15 ноября 2018

РЕДАКТИРОВАТЬ: Благодаря @AdColvin я изменил блок кода, чтобы он работал;)

Вы пробовали что-то вроде

has_many :users, -> { order('campaign_users.created_at DESC') }, through: campaign_users

Вы можете сделать это, потому что ActiveRecord сгенерирует JOIN в результирующем SQL, тогда вы можете упорядочить любую объединенную таблицу.

Кроме того, campaign_users в операторе заказа должно быть именем таблицы, а не именем модели или отношения

...