Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scope vs Class Method in Rails 3

Based on the Rails 3 API, the difference between a scope and a class method is almost non-existent.

class Shipment < ActiveRecord::Base
  def self.unshipped
    where(:shipped => false)
  end
end

is the same as

scope :unshipped, where(:shipped => false)

However, I'm finding that I'm sometimes getting different results using them.

While they both generate the same, correct SQL query, the scope doesn't always seem to return the correct values when called. It looks like this problem only occurs when its called the same way twice, albeit on a different shipment, in the method. The second time it's called, when using scope it returns the same thing it did the first time. Whereas if I use the class method it works correctly.

Is there some sort of query caching that occurs when using scope?

Edit:

order.line_items.unshipped

The line above is how the scope is being called. Orders have many line_items.

The generate_multiple_shipments method is being called twice because the test creates an order and generates the shipments to see how many there are. It then makes a change to the order and regenerates the shipments. However, group_by_ship_date returns the same results it did from the first iteration of the order.

def generate_multiple_shipments(order)
  line_items_by_date = group_by_ship_date(order.line_items.unshipped)

  line_items_by_date.keys.sort.map do |date|
    shipment = clone_from_order(order)
    shipment.ship_date = date
    line_items_by_date[date].each { |line_item| shipment.line_items << line_item }
    shipment
  end
end

def group_by_ship_date(line_items)    
  hash = {}
  line_items.each do |line_item|
    hash[line_item.ship_date] ||= []
    hash[line_item.ship_date] << line_item
  end
  hash
end
like image 480
blim8183 Avatar asked Jan 25 '12 19:01

blim8183


People also ask

What is the difference between scope and class method Rails?

Scopes are just class methods. Internally Active Record converts a scope into a class method. "There is no difference between them" or “it is a matter of taste”.

What are scopes in Rails?

Scopes are custom queries that you define inside your Rails models with the scope method. Every scope takes two arguments: A name, which you use to call this scope in your code. A lambda, which implements the query. Example: scope :active_users, -> { where(active: true) }

Why do we use scope in Rails?

Scopes are used to assign complex ActiveRecord queries into customized methods using Ruby on Rails. Inside your models, you can define a scope as a new method that returns a lambda function for calling queries you're probably used to using inside your controllers.

What is class methods in Rails?

Class Methods are the methods that are defined inside the class, public class methods can be accessed with the help of objects. The method is marked as private by default, when a method is defined outside of the class definition. By default, methods are marked as public which is defined in the class definition.


2 Answers

I think your invocation is incorrect. You should add so-called query method to execute the scope, such as all, first, last, i.e.:

order.line_items.unshipped.all

I've observed some inconsistencies, especially in rspec, that are avoided by adding the query method.

You didn't post your test code, so it's hard to say precisely, but my exeprience has been that after you modify associated records, you have to force a reload, as the query cache isn't always smart enough to detect a change. By passing true to the association, you can force the association to reload and the query to re-run:

order.line_items(true).unshipped.all
like image 90
Wolfram Arnold Avatar answered Sep 18 '22 18:09

Wolfram Arnold


Assuming that you are referencing Rails 3.1, a scope can be affected by the default scope that may be defined on your model whereas a class method will not be.

like image 28
Sasha Avatar answered Sep 20 '22 18:09

Sasha