简体   繁体   中英

Displaying associated records in rails

I have a User , List , and Task models.

A task belongs_to user and list , a list has_many tasks and belongs_to user , and a user has_many list and has_many tasks .

I have part of what I want to display working in my index view, with just one snafu that I am getting hung up on.

I'm able to display the first created task in the index view of all the lists. The problem is, the first task created is displayed for all of the lists, even if the list is NOT associated with the task.

In the list index view I want the first task created to display only if it is associated with the list.

Task model:

class Task < ActiveRecord::Base
  attr_accessible :completed, :description, :list_id, :user_id

  belongs_to :list
  belongs_to :user

  scope :completed, where(:completed => true)
  scope :incomplete, where(:completed => false)

  def self.most_recent
    first(:order => 'id ASC' ) # or whatever query you need to get the most recent
  end

end

List Index View-

<div class="span12 offset2"> 
 <% @lists.each do |list| %> 
  <div class="well row span4">
    <div class="span3">
    </div>  
    <div class="span4">   
      <span class="lead">
        <%= link_to "#{list.name}", list_url(list) %>
      </span>
      <p>
        <%= list.description %>
      </p><hr>
      <div class="pull-right" id="gage-<%= list.id %>" style="width:170px; height:100px;"></div>
      <br>  
      <span class="offset1">
        <% if Task.most_recent %>
          <span class="pull-left"> <%= image_tag Task.most_recent.user.gravatar_url, :class => "gravatar_index" %></span>
        <% end %>  
      </span>
    </div>
  <% end %>
</div>

I'm still new to rails but I know I'm very close. What am I overlooking here? emphasized text

===========

EDIT

I've tested @Baldrick's solution and now seem to be getting another error

My view with described solution-

<% if Task.most_recent(list) %>
      <span class="pull-left"> <%= image_tag Task.most_recent.user.gravatar_url, :class => "gravatar_index" %></span>
<% end %>

I am now getting the error-

SQLite3::SQLException: no such column: tasks.list: SELECT  "tasks".* FROM "tasks"  WHERE "tasks"."list" = 4 ORDER BY id ASC LIMIT 1

I must not be understanding correctly because I have such a created column when I created the Task model

class CreateTasks < ActiveRecord::Migration
  def change
    create_table :tasks do |t|
      t.string :description
      t.boolean :completed, :default => false
      t.integer :list_id

      t.timestamps
    end
  end
end

Is this a case where I need to add an index to be able to make my query?

The method most_recent gives you the last create task of all tasks. What you wnat is the most recent task of a given list.

You should give a parameter to the list

def self.most_recent(list)
  where(list_id: list.id).order('id ASC').first # or whatever query you need to get the most recent
end

Your most_recent method returns the first task of Task. There is nothing in this method tying the task to any list. You'd need to pass the list_id to this method to get the first task for this list, eg

def self.most_recent(list_id)
    first(:order => 'id ASC', :list_id => list_id) 
end

Edit: other solution didn't work.

Based on your description, it does not sound like you want, for each list, to show the most recent task for that list. Rather, it seems you want to have the overall most recent task to appear multiple times, once for each list that happens to contain it. To achieve this you want to replace if Task.most_recent with if list.tasks.include? Task.most_recent if list.tasks.include? Task.most_recent .

---EDIT---

Okay, if you actually want to show, for each list, that list's most recent task, then you should be going about this fairly differently. In your List class you should have the following method:

def most_recent_task
    tasks.first(:order => 'id ASC') # or whatever
end

Then in your view you'll replace both occurrences of Task.most_recent with list.most_recent_task . And if your lists will always have at least one task, then you can get rid of the guard clause (ie the if ) altogether.

As a further refactor you may want to take some computation out of the view, and create "presenters" for your lists index, which would just be an array of presenters for each individual list. An individual presenter should be a plain object with the information you need about the list, precomputed:

  • name
  • url
  • description
  • most recent task's user's gravatar url

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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