简体   繁体   English

Rails使用直通表订购has_many关系

[英]Rails order a has_many relation using a through table

I have a User and a Campaign model in my rails app. 我的Rails应用程序中有一个用户和一个Campaign模型。 A campaign has_many users and a user has_one campaign. 一个广告系列有has_many用户和一个用户has_one广告系列。

I want to order the users in the campaign by the date that they were added to it. 我想在广告系列中的用户添加日期之前对其进行排序。

To do that, I created a through table called CampaignUser. 为此,我创建了一个名为CampaignUser的穿透表。 I thought that I'd be able to order by the created_at column in that table, but I couldn't see an easy way to do it. 我以为可以通过该表中的created_at列进行排序,但是我看不到一种简单的方法。 See the classes below: 请参阅以下课程:

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

Ideally, I'd like to write a line like this in my Campaign class: 理想情况下,我想在Campaign类中编写如下代码:

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

Where created_at refers to campaign_users and not to users . 其中created_at是指campaign_users而不是users Is there a way to do that? 有没有办法做到这一点?

I could just write a method on Campaign myself to order the users manually, but then I'd have to make sure I call that method everywhere instead. 我可以自己在Campaign上编写一个方法来手动订购用户,但随后必须确保在所有地方调用该方法。 It seems like there should be an easier way. 似乎应该有一个更简单的方法。

Edit: 编辑:

Adding a scope to the user, as suggested in other answers is more problematic in this case. 在其他情况下, 如其他答案中所建议的那样 ,向用户添加范围会更成问题。 I'm looking to order users by a property of the through table, not a property of the user itself. 我正在按贯通表的属性而不是用户本身的属性对用户排序。 Is there a way to write the following line, replacing email with campaign_users.created_at , or something similar? 有没有办法写下面的行,用campaign_users.created_at或类似的东西代替email

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

EDIT : Thanks to @AdColvin I changed the code block to make it work ;) 编辑:感谢@AdColvin,我更改了代码块以使其工作;)

Have you tried something like 你尝试过类似的东西吗

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

You can do that because ActiveRecord will generate a JOIN in the resulting SQL, then you can order on any table that is joined. 您可以这样做,因为ActiveRecord会在结果SQL中生成一个JOIN,因此您可以在任何已联接的表上进行排序。

Also, the campaign_users in the order statement should be the name of the table, not the name of the model or the relation 另外,order语句中的campaign_users应该是表的名称,而不是模型或关系的名称

The trick is as @kevcha has already pointed out calling order with a string of the column you want. 诀窍是因为@kevcha已经指出了带有所需列字符串的调用顺序。

But instead of adding the order clause directly to the association you may want to use a 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

This lets you call campaign.users.order_by_join_date to explicitly get the records in a specific order. 这使您可以调用campaign.users.order_by_join_date以明确地按特定顺序获取记录。 It avoids some of the same pitfalls that surround default scope . 它避免了默认范围周围的一些陷阱

@kevcha When I tried your answer exactly as you suggested, I got the following error: @kevcha当我完全按照您的建议尝试回答时,出现以下错误:

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

But, when I add the scope just after has_many :users , it works fine: 但是,当我在has_many :users之后添加范围时,它可以正常工作:

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

Also worth noting is that created_at seems to be identical for objects created from a fixture. 另外值得注意的是, created_at对于从灯具创建的对象似乎是相同的。 I wasn't aware of that. 我没有意识到。 I had to explicitly set created_at in my fixtures for my tests around this to pass. 我必须在夹具中显式设置created_at,以便我的测试通过。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM