Rails 使用直通 table 排序 has_many 关系

Rails order a has_many relation using a through table

我的 rails 应用程序中有一个用户模型和一个广告系列模型。一个活动 has_many 用户和一个用户 has_one 活动。

我想按照添加到活动中的日期对活动中的用户进行排序。

为此,我创建了一个名为 CampaignUser 的 table。我认为我可以通过 table 中的 created_at 列进行排序,但我看不到一种简单的方法。请参阅下面的 classes:

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

理想情况下,我想在我的广告系列中写这样一行 class:

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

其中 created_at 指的是 campaign_users 而不是 users。有没有办法做到这一点?

我可以自己在 Campaign 上编写一个方法来手动对用户进行排序,但是我必须确保在所有地方都调用该方法。看来应该有更简单的方法。

编辑:

给用户添加范围,as suggested in other answers在这种情况下问题更大。我希望通过 table 的 属性 对用户进行排序,而不是用户本身的 属性。有没有办法写下一行,用 campaign_users.created_at 或类似的东西替换 email

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

编辑:感谢@AdColvin,我更改了代码块以使其工作;)

你试过

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

您可以这样做,因为 ActiveRecord 会在生成的 SQL 中生成一个 JOIN,然后您可以对任何已连接的 table 进行排序。

此外,订单声明中的campaign_users应该是table的名称,而不是模型或关系的名称

诀窍是@kevcha 已经指出用你想要的列的字符串调用 order。

但是您可能想要使用 association extension:

而不是直接将 order 子句添加到关联
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 以明确获取特定顺序的记录。它避免了一些相同的 pitfalls that surround default scope.

@kevcha 当我完全按照您的建议尝试回答时,出现以下错误:

syntax error, unexpected '\n', expecting => ...mpaign_users.created_at ASC') }

但是,当我在 has_many :users 之后添加范围时,它工作正常:

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

另外值得注意的是 created_at 对于从固定装置创建的对象似乎是相同的。我不知道这一点。我必须在我的固定装置中明确设置 created_at 才能通过我的测试。