Rails使用通过表订购has_many关系

时间:2018-11-15 11:51:00

标签: ruby-on-rails activerecord has-many-through

我的Rails应用中有一个用户和一个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上编写一个方法来手动订购用户,但随后必须确保在所有地方调用该方法。似乎应该有一种更简单的方法。

编辑:

as suggested in other answers中向用户添加范围在这种情况下更成问题。我正在按贯通表的属性而不是用户本身的属性对用户排序。是否可以编写以下行,将email替换为campaign_users.created_at或类似内容?

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

3 个答案:

答案 0 :(得分:2)

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

您尝试过类似

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

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

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

答案 1 :(得分:0)

窍门是因为@kevcha已经指出了调用顺序以及所需列的字符串。

但是您可能不想使用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

答案 2 :(得分:0)

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

  

语法错误,意外的'\ n',期望=> ... mpaign_users.created_at   ASC')}

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

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

还值得注意的是,created_at对于从灯具创建的对象似乎是相同的。我没有意识到。我必须在夹具中显式设置created_at,以便我的测试通过。