Zed
Zed

Reputation: 5931

Simple scopes and association

So I'm new to scopes, and don't really understand them well.Let's say I have 2 models, Project and Ticket:

class Project < ActiveRecord::Base
 has_many :tickets
end

class Ticket < ActiveRecord::Base
 belongs_to :project
end

I'm used to code like this to access associated data from tickets:

Project.find(1).tickets.each do |ticket|
 puts ticket.name
end

I created new scope:

scope :default, -> { where(default: true) }

And now when I use Project.default I get back ActiveRecord::Relation and don't have a clue how to access associated tickets ?

Upvotes: 1

Views: 39

Answers (3)

apneadiving
apneadiving

Reputation: 115511

Project.default will indeed return an ActiveRecord::Relation, which is a 'to be triggered' query. The query will be triggered once you start looping etc, this is sort of transparent to you.

If you want to get tickets from the projects, first I recommend you include them in your query to avoid N+1. Do it this way:

projects = Project.default.includes(:tickets)

Then to access tickets of a particular project:

project = projects.first
project.tickets 

If you want a method to always return a single object:

class Project < ActiveRecord::Base
  has_many :tickets

  def self.get_default_with_tickets
    Project.where(default: true).includes(:tickets).first
  end
end

then:

Project.get_default_with_tickets #=> your_project

Be sure to handle the cases:

  • when there is more than one match
  • when there is no match

Upvotes: 2

Max Williams
Max Williams

Reputation: 32933

Use all or first to complete the query.

#get all default projects
Project.default.all 

#get the first default project
Project.default.first

Upvotes: 0

Richard Peck
Richard Peck

Reputation: 76774

A scope is basically just a class method (one which fires on a non-intialized model):

class Project < ActiveRecord::Base
 has_many :tickets
 scope :defaults, -> { where(default: true) }
end

This means if you do this:

@defaults = Project.defaults

... you get all the project objects back which have the attribute default as true

This is the same as this:

class Project < ActiveRecord::Base
 has_many :tickets
 def self.defaults
      where(default: true)
 end
end

Error

The reason you're getting a relation is because when you use where, you're basically getting back an "array" of data (as opposed to just a single record). If you .each through the data or just return .first, you'll get an actual object which you can output:

@defaults = Project.defaults
@defaults.each do |project|
    project.tickets #-> associated tickets
end

Upvotes: 0

Related Questions