Rails order a has_many relation using a through table
I have a User and a Campaign model in my rails app. A campaign has_many
users and a user has_one
campaign.
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. 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. 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:
has_many :users, through: campaign_users, -> { order(created_at: :desc) }
Where created_at
refers to campaign_users
and not to 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. 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?
has_many :users, -> { order(email: :desc) }, :through => :campaign_users
ruby-on-rails activerecord has-many-through
add a comment |
I have a User and a Campaign model in my rails app. A campaign has_many
users and a user has_one
campaign.
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. 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. 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:
has_many :users, through: campaign_users, -> { order(created_at: :desc) }
Where created_at
refers to campaign_users
and not to 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. 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?
has_many :users, -> { order(email: :desc) }, :through => :campaign_users
ruby-on-rails activerecord has-many-through
Possible duplicate of How do I order a has_many through association in Ruby on Rails?
– mrzasa
Nov 15 '18 at 13:11
@mrzasa This case is slightly different as I'm trying to order based on the through table and not the user itself. See my edit for details.
– AdColvin
Nov 15 '18 at 14:29
I'd advise to removethrough
and implement it as two separatehas_many :campaign_users
associations in both classes
– mrzasa
Nov 15 '18 at 14:31
add a comment |
I have a User and a Campaign model in my rails app. A campaign has_many
users and a user has_one
campaign.
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. 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. 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:
has_many :users, through: campaign_users, -> { order(created_at: :desc) }
Where created_at
refers to campaign_users
and not to 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. 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?
has_many :users, -> { order(email: :desc) }, :through => :campaign_users
ruby-on-rails activerecord has-many-through
I have a User and a Campaign model in my rails app. A campaign has_many
users and a user has_one
campaign.
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. 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. 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:
has_many :users, through: campaign_users, -> { order(created_at: :desc) }
Where created_at
refers to campaign_users
and not to 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. 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?
has_many :users, -> { order(email: :desc) }, :through => :campaign_users
ruby-on-rails activerecord has-many-through
ruby-on-rails activerecord has-many-through
edited Nov 15 '18 at 14:27
AdColvin
asked Nov 15 '18 at 11:50
AdColvinAdColvin
3111212
3111212
Possible duplicate of How do I order a has_many through association in Ruby on Rails?
– mrzasa
Nov 15 '18 at 13:11
@mrzasa This case is slightly different as I'm trying to order based on the through table and not the user itself. See my edit for details.
– AdColvin
Nov 15 '18 at 14:29
I'd advise to removethrough
and implement it as two separatehas_many :campaign_users
associations in both classes
– mrzasa
Nov 15 '18 at 14:31
add a comment |
Possible duplicate of How do I order a has_many through association in Ruby on Rails?
– mrzasa
Nov 15 '18 at 13:11
@mrzasa This case is slightly different as I'm trying to order based on the through table and not the user itself. See my edit for details.
– AdColvin
Nov 15 '18 at 14:29
I'd advise to removethrough
and implement it as two separatehas_many :campaign_users
associations in both classes
– mrzasa
Nov 15 '18 at 14:31
Possible duplicate of How do I order a has_many through association in Ruby on Rails?
– mrzasa
Nov 15 '18 at 13:11
Possible duplicate of How do I order a has_many through association in Ruby on Rails?
– mrzasa
Nov 15 '18 at 13:11
@mrzasa This case is slightly different as I'm trying to order based on the through table and not the user itself. See my edit for details.
– AdColvin
Nov 15 '18 at 14:29
@mrzasa This case is slightly different as I'm trying to order based on the through table and not the user itself. See my edit for details.
– AdColvin
Nov 15 '18 at 14:29
I'd advise to remove
through
and implement it as two separate has_many :campaign_users
associations in both classes– mrzasa
Nov 15 '18 at 14:31
I'd advise to remove
through
and implement it as two separate has_many :campaign_users
associations in both classes– mrzasa
Nov 15 '18 at 14:31
add a comment |
3 Answers
3
active
oldest
votes
EDIT : Thanks to @AdColvin I changed the code block to make it work ;)
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.
Also, the campaign_users
in the order statement should be the name of the table, not the name of the model or the relation
1
This worked for me, with a slight modification. See my answer below.
– AdColvin
Nov 17 '18 at 13:40
add a comment |
The trick is as @kevcha has already pointed out calling order with a string of the column you want.
But instead of adding the order clause directly to the association you may want to use a association extension:
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. It avoids some of the same pitfalls that surround default scope.
add a comment |
@kevcha When I tried your answer exactly as you suggested, I got the following error:
syntax error, unexpected 'n', expecting => ...mpaign_users.created_at
ASC') }
But, when I add the scope just after has_many :users
, it works fine:
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. I wasn't aware of that. I had to explicitly set created_at in my fixtures for my tests around this to pass.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53318872%2frails-order-a-has-many-relation-using-a-through-table%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
EDIT : Thanks to @AdColvin I changed the code block to make it work ;)
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.
Also, the campaign_users
in the order statement should be the name of the table, not the name of the model or the relation
1
This worked for me, with a slight modification. See my answer below.
– AdColvin
Nov 17 '18 at 13:40
add a comment |
EDIT : Thanks to @AdColvin I changed the code block to make it work ;)
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.
Also, the campaign_users
in the order statement should be the name of the table, not the name of the model or the relation
1
This worked for me, with a slight modification. See my answer below.
– AdColvin
Nov 17 '18 at 13:40
add a comment |
EDIT : Thanks to @AdColvin I changed the code block to make it work ;)
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.
Also, the campaign_users
in the order statement should be the name of the table, not the name of the model or the relation
EDIT : Thanks to @AdColvin I changed the code block to make it work ;)
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.
Also, the campaign_users
in the order statement should be the name of the table, not the name of the model or the relation
edited Nov 18 '18 at 17:13
answered Nov 15 '18 at 15:37
kevchakevcha
580513
580513
1
This worked for me, with a slight modification. See my answer below.
– AdColvin
Nov 17 '18 at 13:40
add a comment |
1
This worked for me, with a slight modification. See my answer below.
– AdColvin
Nov 17 '18 at 13:40
1
1
This worked for me, with a slight modification. See my answer below.
– AdColvin
Nov 17 '18 at 13:40
This worked for me, with a slight modification. See my answer below.
– AdColvin
Nov 17 '18 at 13:40
add a comment |
The trick is as @kevcha has already pointed out calling order with a string of the column you want.
But instead of adding the order clause directly to the association you may want to use a association extension:
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. It avoids some of the same pitfalls that surround default scope.
add a comment |
The trick is as @kevcha has already pointed out calling order with a string of the column you want.
But instead of adding the order clause directly to the association you may want to use a association extension:
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. It avoids some of the same pitfalls that surround default scope.
add a comment |
The trick is as @kevcha has already pointed out calling order with a string of the column you want.
But instead of adding the order clause directly to the association you may want to use a association extension:
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. It avoids some of the same pitfalls that surround default scope.
The trick is as @kevcha has already pointed out calling order with a string of the column you want.
But instead of adding the order clause directly to the association you may want to use a association extension:
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. It avoids some of the same pitfalls that surround default scope.
answered Nov 16 '18 at 18:34
maxmax
46.2k1060104
46.2k1060104
add a comment |
add a comment |
@kevcha When I tried your answer exactly as you suggested, I got the following error:
syntax error, unexpected 'n', expecting => ...mpaign_users.created_at
ASC') }
But, when I add the scope just after has_many :users
, it works fine:
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. I wasn't aware of that. I had to explicitly set created_at in my fixtures for my tests around this to pass.
add a comment |
@kevcha When I tried your answer exactly as you suggested, I got the following error:
syntax error, unexpected 'n', expecting => ...mpaign_users.created_at
ASC') }
But, when I add the scope just after has_many :users
, it works fine:
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. I wasn't aware of that. I had to explicitly set created_at in my fixtures for my tests around this to pass.
add a comment |
@kevcha When I tried your answer exactly as you suggested, I got the following error:
syntax error, unexpected 'n', expecting => ...mpaign_users.created_at
ASC') }
But, when I add the scope just after has_many :users
, it works fine:
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. I wasn't aware of that. I had to explicitly set created_at in my fixtures for my tests around this to pass.
@kevcha When I tried your answer exactly as you suggested, I got the following error:
syntax error, unexpected 'n', expecting => ...mpaign_users.created_at
ASC') }
But, when I add the scope just after has_many :users
, it works fine:
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. I wasn't aware of that. I had to explicitly set created_at in my fixtures for my tests around this to pass.
answered Nov 17 '18 at 13:38
AdColvinAdColvin
3111212
3111212
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53318872%2frails-order-a-has-many-relation-using-a-through-table%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Possible duplicate of How do I order a has_many through association in Ruby on Rails?
– mrzasa
Nov 15 '18 at 13:11
@mrzasa This case is slightly different as I'm trying to order based on the through table and not the user itself. See my edit for details.
– AdColvin
Nov 15 '18 at 14:29
I'd advise to remove
through
and implement it as two separatehas_many :campaign_users
associations in both classes– mrzasa
Nov 15 '18 at 14:31