Search code examples
ruby-on-railsloopsmodel

Display objects from a nested model in a loop


I have a model in my app called Tracker with a nested model underneath called Email. I want to create a view page where I can see each of my Trackers with all of the related Emails underneath.

I'm creating a loop to show all my trackers, and then adding a loop in between to show the emails, however it's showing me all the emails rather than just the ones related to that tracker.

Here is the code for my view page where I think I'm going wrong:

<div class="card">
  <% @trackers.each do |tracker| %>
  <b><%= tracker.title %> <%= tracker.emails.count %></b>
      <ol><% for emails in @tracker %>
        <li>I'd like the email subject to appear here!</li>
      <% end %><ol>
    <% end %>
</div>

And here is the controller for my view page:

class PagesController < ApplicationController

  def inbox
    @emails = Email.order('date_sent ASC')
    @email = Email.order('date_sent ASC')
    @trackers = Tracker.all
    @tracker = Tracker.all
  end

Thanks for your help!


Solution

  • I consider relationship between table (tracker has_many emails)

    here is the code

      <div class="card">
        <% @trackers.each do |tracker| %>
        <b><%= tracker.title %> <%= tracker.emails.count %></b>
            <ol>
              <% tracker.emails.each do |email| %>
                <li><%= email.subject %></li>
              <% end %>
            <ol>
          <% end %>
      </div>
    

    edit 2:

      <div class="card">
        <% @trackers.each do |tracker| %>
        <b><%= tracker.title %> <%= tracker.emails.count %></b>
            <ol>
              <% email = tracker.emails.order('date_sent DESC').last %>
              <li><%= email.subject if email.present? %></li>
            <ol>
          <% end %>
      </div>
    

    note:

    • if you want to show emails that related with tracker then you have to write tracker.emails instead query An Email model
    • if you want last email then you have to order with DESC instead of ASC
    • if you want only one record then you write last instead of limit(1) but the meaning still same

    additional tips (may be you want to learn more)

    @trackers = Tracker.all.includes(:emails)

    if you load Tracker and related email with Tracker.all it will create n+1 query, which is not efficient with additional command includes(:emails) it will execute 1 query which is faster.

    (What is an n+1 query? An n+1 query occurs when we are loading a collection of records from a database, and also one related record for each record in that collection. The first query loads the collection of records from the database, and then one additional query is executed for each n record)

    if I wanted to only show the latest email from each tracker - which I have a date_sent object for. Count I do something like @email = Email.order('date_sent ASC').limit(1) in the controller or <% tracker.emails.order('date_sent ASC').limit(1) do |email| %> in the loop? At the moment it doesn't show my any emails but doesn't give me an error.