How can I join only one record on a has_many with criteria in Rails?











up vote
0
down vote

favorite












If I have the following models how can I return all reports a user has created, but only the "highest graded" report per player?



class Player < ApplicationRecord
has_many :reports
end

class Report < ApplicationRecord
belongs_to :author
belongs_to :grade
belongs_to :player
end

class Grade < ApplciationRecord
has_many :reports
end

class Author < ApplicationRecord
has_many :reports
end


Example Data:



/Player/    -    /Author/   -    /Report Grade/
John Smith - David - 5
John Smith - David - 4
Thomas Li - David - 5
Mike Lee - Sean - 9
Mike Lee - Sean - 2
Arnold Jackson - Sean - 5
Cathleen Miller - Sean - 7


Result I would like:



/Player/    -    /Author/   -    /Report Grade/
John Smith - David - 5
Thomas Li - David - 5
Mike Lee - Sean - 9
Arnold Jackson - Sean - 5
Cathleen Miller - Sean - 7


Currently I'm using the following:



Report.joins(:player).where(type: %w(spring fall))


I'm unsure how to filter out the "lower graded" records. If I need to include more information please let me know.










share|improve this question






















  • Do you really need a separate table for Grade? It would a lot simpler if you just used an integer on reports.
    – max
    Nov 21 at 20:07










  • @max, yes the grade values are more complex than shown here. I just simplified it for the illustration.
    – daveomcd
    Nov 21 at 20:16















up vote
0
down vote

favorite












If I have the following models how can I return all reports a user has created, but only the "highest graded" report per player?



class Player < ApplicationRecord
has_many :reports
end

class Report < ApplicationRecord
belongs_to :author
belongs_to :grade
belongs_to :player
end

class Grade < ApplciationRecord
has_many :reports
end

class Author < ApplicationRecord
has_many :reports
end


Example Data:



/Player/    -    /Author/   -    /Report Grade/
John Smith - David - 5
John Smith - David - 4
Thomas Li - David - 5
Mike Lee - Sean - 9
Mike Lee - Sean - 2
Arnold Jackson - Sean - 5
Cathleen Miller - Sean - 7


Result I would like:



/Player/    -    /Author/   -    /Report Grade/
John Smith - David - 5
Thomas Li - David - 5
Mike Lee - Sean - 9
Arnold Jackson - Sean - 5
Cathleen Miller - Sean - 7


Currently I'm using the following:



Report.joins(:player).where(type: %w(spring fall))


I'm unsure how to filter out the "lower graded" records. If I need to include more information please let me know.










share|improve this question






















  • Do you really need a separate table for Grade? It would a lot simpler if you just used an integer on reports.
    – max
    Nov 21 at 20:07










  • @max, yes the grade values are more complex than shown here. I just simplified it for the illustration.
    – daveomcd
    Nov 21 at 20:16













up vote
0
down vote

favorite









up vote
0
down vote

favorite











If I have the following models how can I return all reports a user has created, but only the "highest graded" report per player?



class Player < ApplicationRecord
has_many :reports
end

class Report < ApplicationRecord
belongs_to :author
belongs_to :grade
belongs_to :player
end

class Grade < ApplciationRecord
has_many :reports
end

class Author < ApplicationRecord
has_many :reports
end


Example Data:



/Player/    -    /Author/   -    /Report Grade/
John Smith - David - 5
John Smith - David - 4
Thomas Li - David - 5
Mike Lee - Sean - 9
Mike Lee - Sean - 2
Arnold Jackson - Sean - 5
Cathleen Miller - Sean - 7


Result I would like:



/Player/    -    /Author/   -    /Report Grade/
John Smith - David - 5
Thomas Li - David - 5
Mike Lee - Sean - 9
Arnold Jackson - Sean - 5
Cathleen Miller - Sean - 7


Currently I'm using the following:



Report.joins(:player).where(type: %w(spring fall))


I'm unsure how to filter out the "lower graded" records. If I need to include more information please let me know.










share|improve this question













If I have the following models how can I return all reports a user has created, but only the "highest graded" report per player?



class Player < ApplicationRecord
has_many :reports
end

class Report < ApplicationRecord
belongs_to :author
belongs_to :grade
belongs_to :player
end

class Grade < ApplciationRecord
has_many :reports
end

class Author < ApplicationRecord
has_many :reports
end


Example Data:



/Player/    -    /Author/   -    /Report Grade/
John Smith - David - 5
John Smith - David - 4
Thomas Li - David - 5
Mike Lee - Sean - 9
Mike Lee - Sean - 2
Arnold Jackson - Sean - 5
Cathleen Miller - Sean - 7


Result I would like:



/Player/    -    /Author/   -    /Report Grade/
John Smith - David - 5
Thomas Li - David - 5
Mike Lee - Sean - 9
Arnold Jackson - Sean - 5
Cathleen Miller - Sean - 7


Currently I'm using the following:



Report.joins(:player).where(type: %w(spring fall))


I'm unsure how to filter out the "lower graded" records. If I need to include more information please let me know.







ruby-on-rails activerecord ruby-on-rails-5






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 21 at 19:07









daveomcd

2,8721065106




2,8721065106












  • Do you really need a separate table for Grade? It would a lot simpler if you just used an integer on reports.
    – max
    Nov 21 at 20:07










  • @max, yes the grade values are more complex than shown here. I just simplified it for the illustration.
    – daveomcd
    Nov 21 at 20:16


















  • Do you really need a separate table for Grade? It would a lot simpler if you just used an integer on reports.
    – max
    Nov 21 at 20:07










  • @max, yes the grade values are more complex than shown here. I just simplified it for the illustration.
    – daveomcd
    Nov 21 at 20:16
















Do you really need a separate table for Grade? It would a lot simpler if you just used an integer on reports.
– max
Nov 21 at 20:07




Do you really need a separate table for Grade? It would a lot simpler if you just used an integer on reports.
– max
Nov 21 at 20:07












@max, yes the grade values are more complex than shown here. I just simplified it for the illustration.
– daveomcd
Nov 21 at 20:16




@max, yes the grade values are more complex than shown here. I just simplified it for the illustration.
– daveomcd
Nov 21 at 20:16












1 Answer
1






active

oldest

votes

















up vote
1
down vote



accepted










On Postgres you can use DISTINCT ON:



class Report < ApplicationRecord
belongs_to :player
belongs_to :grade
belongs_to :author

def self.highest_graded
Report.select(%q{
DISTINCT ON(reports.player_id, reports.author_id)
grades.grade AS max_grade,
players.name AS player_name,
authors.name AS author_name,
reports.*
}).joins(:player, :grade, :author)
.order('reports.player_id, reports.author_id, grades.grade DESC')
end
end




<table>
<thead>
<tr>
<th>id</th>
<th>Player</th>
<th>Author</th>
<th>Grade</th>
</tr>
</thead>
<tbody>
<% Report.highest_grade.each do |report| %>
<tr>
<td><%= report.id %></td>
<td><%= report.player_name %></td>
<td><%= report.author_name %></td>
<td><%= report.max_grade %></td>
</tr>
<% end %>
</tbody>
</table>




id  Player          Author  Grade
1 John Smith David 5
3 Thomas Li David 5
4 Mike Lee Sean 9
6 Arnold Jackson Sean 5
7 Cathleen Miller Sean 7





share|improve this answer





















    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',
    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
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53418977%2fhow-can-i-join-only-one-record-on-a-has-many-with-criteria-in-rails%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    1
    down vote



    accepted










    On Postgres you can use DISTINCT ON:



    class Report < ApplicationRecord
    belongs_to :player
    belongs_to :grade
    belongs_to :author

    def self.highest_graded
    Report.select(%q{
    DISTINCT ON(reports.player_id, reports.author_id)
    grades.grade AS max_grade,
    players.name AS player_name,
    authors.name AS author_name,
    reports.*
    }).joins(:player, :grade, :author)
    .order('reports.player_id, reports.author_id, grades.grade DESC')
    end
    end




    <table>
    <thead>
    <tr>
    <th>id</th>
    <th>Player</th>
    <th>Author</th>
    <th>Grade</th>
    </tr>
    </thead>
    <tbody>
    <% Report.highest_grade.each do |report| %>
    <tr>
    <td><%= report.id %></td>
    <td><%= report.player_name %></td>
    <td><%= report.author_name %></td>
    <td><%= report.max_grade %></td>
    </tr>
    <% end %>
    </tbody>
    </table>




    id  Player          Author  Grade
    1 John Smith David 5
    3 Thomas Li David 5
    4 Mike Lee Sean 9
    6 Arnold Jackson Sean 5
    7 Cathleen Miller Sean 7





    share|improve this answer

























      up vote
      1
      down vote



      accepted










      On Postgres you can use DISTINCT ON:



      class Report < ApplicationRecord
      belongs_to :player
      belongs_to :grade
      belongs_to :author

      def self.highest_graded
      Report.select(%q{
      DISTINCT ON(reports.player_id, reports.author_id)
      grades.grade AS max_grade,
      players.name AS player_name,
      authors.name AS author_name,
      reports.*
      }).joins(:player, :grade, :author)
      .order('reports.player_id, reports.author_id, grades.grade DESC')
      end
      end




      <table>
      <thead>
      <tr>
      <th>id</th>
      <th>Player</th>
      <th>Author</th>
      <th>Grade</th>
      </tr>
      </thead>
      <tbody>
      <% Report.highest_grade.each do |report| %>
      <tr>
      <td><%= report.id %></td>
      <td><%= report.player_name %></td>
      <td><%= report.author_name %></td>
      <td><%= report.max_grade %></td>
      </tr>
      <% end %>
      </tbody>
      </table>




      id  Player          Author  Grade
      1 John Smith David 5
      3 Thomas Li David 5
      4 Mike Lee Sean 9
      6 Arnold Jackson Sean 5
      7 Cathleen Miller Sean 7





      share|improve this answer























        up vote
        1
        down vote



        accepted







        up vote
        1
        down vote



        accepted






        On Postgres you can use DISTINCT ON:



        class Report < ApplicationRecord
        belongs_to :player
        belongs_to :grade
        belongs_to :author

        def self.highest_graded
        Report.select(%q{
        DISTINCT ON(reports.player_id, reports.author_id)
        grades.grade AS max_grade,
        players.name AS player_name,
        authors.name AS author_name,
        reports.*
        }).joins(:player, :grade, :author)
        .order('reports.player_id, reports.author_id, grades.grade DESC')
        end
        end




        <table>
        <thead>
        <tr>
        <th>id</th>
        <th>Player</th>
        <th>Author</th>
        <th>Grade</th>
        </tr>
        </thead>
        <tbody>
        <% Report.highest_grade.each do |report| %>
        <tr>
        <td><%= report.id %></td>
        <td><%= report.player_name %></td>
        <td><%= report.author_name %></td>
        <td><%= report.max_grade %></td>
        </tr>
        <% end %>
        </tbody>
        </table>




        id  Player          Author  Grade
        1 John Smith David 5
        3 Thomas Li David 5
        4 Mike Lee Sean 9
        6 Arnold Jackson Sean 5
        7 Cathleen Miller Sean 7





        share|improve this answer












        On Postgres you can use DISTINCT ON:



        class Report < ApplicationRecord
        belongs_to :player
        belongs_to :grade
        belongs_to :author

        def self.highest_graded
        Report.select(%q{
        DISTINCT ON(reports.player_id, reports.author_id)
        grades.grade AS max_grade,
        players.name AS player_name,
        authors.name AS author_name,
        reports.*
        }).joins(:player, :grade, :author)
        .order('reports.player_id, reports.author_id, grades.grade DESC')
        end
        end




        <table>
        <thead>
        <tr>
        <th>id</th>
        <th>Player</th>
        <th>Author</th>
        <th>Grade</th>
        </tr>
        </thead>
        <tbody>
        <% Report.highest_grade.each do |report| %>
        <tr>
        <td><%= report.id %></td>
        <td><%= report.player_name %></td>
        <td><%= report.author_name %></td>
        <td><%= report.max_grade %></td>
        </tr>
        <% end %>
        </tbody>
        </table>




        id  Player          Author  Grade
        1 John Smith David 5
        3 Thomas Li David 5
        4 Mike Lee Sean 9
        6 Arnold Jackson Sean 5
        7 Cathleen Miller Sean 7






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 21 at 21:25









        max

        44.1k856103




        44.1k856103






























            draft saved

            draft discarded




















































            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.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • 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.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53418977%2fhow-can-i-join-only-one-record-on-a-has-many-with-criteria-in-rails%23new-answer', 'question_page');
            }
            );

            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







            Popular posts from this blog

            A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

            Calculate evaluation metrics using cross_val_predict sklearn

            Insert data from modal to MySQL (multiple modal on website)