Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #11404: named_scope.patch

File named_scope.patch, 26.7 kB (added by nkallen, 4 months ago)
  • a/activerecord/lib/active_record.rb

    old new  
    3737end 
    3838 
    3939require 'active_record/base' 
     40require 'active_record/named_scope' 
    4041require 'active_record/observer' 
    4142require 'active_record/query_cache' 
    4243require 'active_record/validations' 
     
    6465  include ActiveRecord::Observing 
    6566  include ActiveRecord::Timestamp 
    6667  include ActiveRecord::Associations 
     68  include ActiveRecord::NamedScope 
    6769  include ActiveRecord::AssociationPreload 
    6870  include ActiveRecord::Aggregations 
    6971  include ActiveRecord::Transactions 
  • a/activerecord/lib/active_record/associations.rb

    old new  
    11071107            end 
    11081108          end 
    11091109        end 
    1110  
     1110         
    11111111        def add_multiple_associated_save_callbacks(association_name) 
    11121112          method_name = "validate_associated_records_for_#{association_name}".to_sym 
    11131113          ivar = "@#{association_name}" 
  • a/activerecord/lib/active_record/associations/association_collection.rb

    old new  
    4141        delete(@target) 
    4242        reset_target! 
    4343      end 
    44  
     44       
    4545      # Calculate sum using SQL, not Enumerable 
    4646      def sum(*args) 
    4747        if block_given? 
     
    168168            else 
    169169              super 
    170170            end 
    171           else 
    172             @reflection.klass.send(:with_scope, construct_scope) do 
     171          elsif @reflection.klass.scopes.include?(method) 
     172            @reflection.klass.scopes[method].call(self, *args) 
     173          else           
     174            with_scope(construct_scope) do 
    173175              if block_given? 
    174176                @reflection.klass.send(method, *args) { |*block_args| yield(*block_args) } 
    175177              else 
  • a/activerecord/lib/active_record/associations/association_proxy.rb

    old new  
    119119          ) 
    120120        end 
    121121 
     122        def with_scope(*args, &block) 
     123          @reflection.klass.send :with_scope, *args, &block 
     124        end 
     125           
    122126      private 
    123127        def method_missing(method, *args) 
    124128          if load_target 
  • a/activerecord/lib/active_record/associations/has_many_association.rb

    old new  
    167167        def construct_scope 
    168168          create_scoping = {} 
    169169          set_belongs_to_association_for(create_scoping) 
    170           { :find => { :conditions => @finder_sql, :readonly => false, :order => @reflection.options[:order], :limit => @reflection.options[:limit] }, :create => create_scoping } 
     170          { 
     171            :find => { :conditions => @finder_sql, :readonly => false, :order => @reflection.options[:order], :limit => @reflection.options[:limit] }, 
     172            :create => create_scoping 
     173          } 
    171174        end 
    172175    end 
    173176  end 
  • a/activerecord/lib/active_record/associations/has_many_through_association.rb

    old new  
    139139            else 
    140140              super 
    141141            end 
     142          elsif @reflection.klass.scopes.include?(method) 
     143            @reflection.klass.scopes[method].call(self, *args) 
    142144          else 
    143             @reflection.klass.send(:with_scope, construct_scope) do 
     145            with_scope construct_scope do 
    144146              if block_given? 
    145147                @reflection.klass.send(method, *args) { |*block_args| yield(*block_args) } 
    146148              else 
  • /dev/null

    old new  
     1module ActiveRecord 
     2  module NamedScope 
     3    # All subclasses of ActiveRecord::Base have two named_scopes: 
     4    # * <tt>all</tt>, which is similar to a <tt>find(:all)</tt> query, and 
     5    # * <tt>scoped</tt>, which allows for the creation of anonymous scopes, on the fly: 
     6    # 
     7    #   Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions) 
     8    # 
     9    # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing 
     10    # intermediate values (scopes) around as first-class objects is convenient. 
     11    def self.included(base) 
     12      base.class_eval do 
     13        extend ClassMethods 
     14        named_scope :all 
     15        named_scope :scoped, lambda { |scope| scope } 
     16      end 
     17    end 
     18 
     19    module ClassMethods 
     20      def scopes 
     21        read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {}) 
     22      end 
     23 
     24      # Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query, 
     25      # such as <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>. 
     26      # 
     27      #   class Shirt < ActiveRecord::Base 
     28      #     named_scope :red, :conditions => {:color => 'red'} 
     29      #     named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true] 
     30      #   end 
     31      #  
     32      # The above calls to <tt>named_scope</tt> define class methods <tt>Shirt.red</tt> and <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>,  
     33      # in effect, represents the query <tt>Shirt.find(:all, :conditions => {:color => 'red'})</tt>. 
     34      # 
     35      # Unlike Shirt.find(...), however, the object returned by <tt>Shirt.red</tt> is not an Array; it resembles the association object 
     36      # constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.find(:first)</tt>, <tt>Shirt.red.count</tt>, 
     37      # <tt>Shirt.red.find(:all, :conditions => {:size => 'small'})</tt>. Also, just 
     38      # as with the association objects, name scopes acts like an Array, implementing Enumerable; <tt>Shirt.red.each(&block)</tt>, 
     39      # <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if Shirt.red really were an Array. 
     40      # 
     41      # These named scopes are composable. For instance, <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are both red and dry clean only. 
     42      # Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments 
     43      # for which these criteria obtain. Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>. 
     44      # 
     45      # All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to 
     46      # <tt>has_many</tt> associations. If, 
     47      # 
     48      #   class Person < ActiveRecord::Base 
     49      #     has_many :shirts 
     50      #   end 
     51      # 
     52      # then <tt>elton.shirts.red.dry_clean_only</tt> will return all of Elton's red, dry clean 
     53      # only shirts. 
     54      # 
     55      # Named scopes can also be procedural. 
     56      # 
     57      #   class Shirt < ActiveRecord::Base 
     58      #     named_scope :colored, lambda { |color| 
     59      #       { :conditions => { :color => color } } 
     60      #     } 
     61      #   end 
     62      # 
     63      # In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts. 
     64      # 
     65      # Named scopes can also have extensions, just as with <tt>has_many</tt> declarations: 
     66      # 
     67      #   class Shirt < ActiveRecord::Base 
     68      #     named_scope :red, :conditions => {:color => 'red'} do 
     69      #       def dom_id 
     70      #         'red_shirts' 
     71      #       end 
     72      #     end 
     73      #   end 
     74      # 
     75      def named_scope(name, options = {}, &block) 
     76        scopes[name] = lambda do |parent_scope, *args| 
     77          Scope.new(parent_scope, case options 
     78            when Hash 
     79              options 
     80            when Proc 
     81              options.call(*args) 
     82          end, &block) 
     83        end 
     84        (class << self; self end).instance_eval do 
     85          define_method name do |*args| 
     86            scopes[name].call(self, *args) 
     87          end 
     88        end 
     89      end 
     90    end 
     91     
     92    class Scope 
     93      attr_reader :proxy_scope, :proxy_options 
     94      [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ } 
     95      delegate :scopes, :with_scope, :to => :proxy_scope 
     96 
     97      def initialize(proxy_scope, options, &block) 
     98        [options[:extend]].flatten.each { |extension| extend extension } if options[:extend] 
     99        extend Module.new(&block) if block_given? 
     100        @proxy_scope, @proxy_options = proxy_scope, options.except(:extend) 
     101      end 
     102 
     103      def reload 
     104        load_found; self 
     105      end 
     106 
     107      protected 
     108      def proxy_found 
     109        @found || load_found 
     110      end 
     111 
     112      private 
     113      def method_missing(method, *args, &block) 
     114        if scopes.include?(method) 
     115          scopes[method].call(self, *args) 
     116        else 
     117          with_scope :find => proxy_options do 
     118            proxy_scope.send(method, *args, &block) 
     119          end 
     120        end 
     121      end 
     122 
     123      def load_found 
     124        @found = find(:all) 
     125      end 
     126    end 
     127  end 
     128end 
  • a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb

    old new  
    6161 
    6262  def test_eager_association_loading_with_has_many_sti 
    6363    topics = Topic.find(:all, :include => :replies, :order => 'topics.id') 
    64     assert_equal topics(:first, :second), topics 
     64    first, second, = topics(:first).replies.size, topics(:second).replies.size 
    6565    assert_no_queries do 
    66       assert_equal 1, topics[0].replies.size 
    67       assert_equal 0, topics[1].replies.size 
     66      assert_equal first, topics[0].replies.size 
     67      assert_equal second, topics[1].replies.size 
    6868    end 
    6969  end 
    7070 
    7171  def test_eager_association_loading_with_belongs_to_sti 
    7272    replies = Reply.find(:all, :include => :topic, :order => 'topics.id') 
    73     assert_equal [topics(:second)], replies 
     73    assert replies.include?(topics(:second)) 
     74    assert !replies.include?(topics(:first)) 
    7475    assert_equal topics(:first), assert_no_queries { replies.first.topic } 
    7576  end 
    7677 
  • a/activerecord/test/cases/base_test.rb

    old new  
    477477 
    478478  def test_load 
    479479    topics = Topic.find(:all, :order => 'id') 
    480     assert_equal(2, topics.size) 
     480    assert_equal(4, topics.size) 
    481481    assert_equal(topics(:first).title, topics.first.title) 
    482482  end 
    483483 
     
    549549  end 
    550550 
    551551  def test_destroy_all 
    552     assert_equal 2, Topic.count 
    553  
    554     Topic.destroy_all "author_name = 'Mary'" 
    555     assert_equal 1, Topic.count 
     552    original_count = Topic.count 
     553    topics_by_mary = Topic.count(:conditions => mary = "author_name = 'Mary'") 
     554     
     555    Topic.destroy_all mary 
     556    assert_equal original_count - topics_by_mary, Topic.count 
    556557  end 
    557558 
    558559  def test_destroy_many 
     
    562563  end 
    563564 
    564565  def test_delete_many 
    565     Topic.delete([1, 2]) 
    566     assert_equal 0, Topic.count 
     566    original_count = Topic.count 
     567    Topic.delete(deleting = [1, 2]) 
     568    assert_equal original_count - deleting.size, Topic.count 
    567569  end 
    568570 
    569571  def test_boolean_attributes 
     
    588590  end 
    589591 
    590592  def test_update_all 
    591     assert_equal 2, Topic.update_all("content = 'bulk updated!'") 
     593    assert_equal Topic.count, Topic.update_all("content = 'bulk updated!'") 
    592594    assert_equal "bulk updated!", Topic.find(1).content 
    593595    assert_equal "bulk updated!", Topic.find(2).content 
    594596 
    595     assert_equal 2, Topic.update_all(['content = ?', 'bulk updated again!']) 
     597    assert_equal Topic.count, Topic.update_all(['content = ?', 'bulk updated again!']) 
    596598    assert_equal "bulk updated again!", Topic.find(1).content 
    597599    assert_equal "bulk updated again!", Topic.find(2).content 
    598600 
    599     assert_equal 2, Topic.update_all(['content = ?', nil]) 
     601    assert_equal Topic.count, Topic.update_all(['content = ?', nil]) 
    600602    assert_nil Topic.find(1).content 
    601603  end 
    602604 
    603605  def test_update_all_with_hash 
    604606    assert_not_nil Topic.find(1).last_read 
    605     assert_equal 2, Topic.update_all(:content => 'bulk updated with hash!', :last_read => nil) 
     607    assert_equal Topic.count, Topic.update_all(:content => 'bulk updated with hash!', :last_read => nil) 
    606608    assert_equal "bulk updated with hash!", Topic.find(1).content 
    607609    assert_equal "bulk updated with hash!", Topic.find(2).content 
    608610    assert_nil Topic.find(1).last_read 
     
    637639  end 
    638640 
    639641  def test_delete_all 
    640     assert_equal 2, Topic.delete_all 
     642    assert Topic.count > 0 
     643     
     644    assert_equal Topic.count, Topic.delete_all 
    641645  end 
    642646 
    643647  def test_update_by_condition 
     
    804808 
    805809  def test_update_attributes! 
    806810    reply = Reply.find(2) 
    807     assert_equal "The Second Topic's of the day", reply.title 
     811    assert_equal "The Second Topic of the day", reply.title 
    808812    assert_equal "Have a nice day", reply.content 
    809813 
    810     reply.update_attributes!("title" => "The Second Topic's of the day updated", "content" => "Have a nice evening") 
     814    reply.update_attributes!("title" => "The Second Topic of the day updated", "content" => "Have a nice evening") 
    811815    reply.reload 
    812     assert_equal "The Second Topic's of the day updated", reply.title 
     816    assert_equal "The Second Topic of the day updated", reply.title 
    813817    assert_equal "Have a nice evening", reply.content 
    814818 
    815     reply.update_attributes!(:title => "The Second Topic's of the day", :content => "Have a nice day") 
     819    reply.update_attributes!(:title => "The Second Topic of the day", :content => "Have a nice day") 
    816820    reply.reload 
    817     assert_equal "The Second Topic's of the day", reply.title 
     821    assert_equal "The Second Topic of the day", reply.title 
    818822    assert_equal "Have a nice day", reply.content 
    819823 
    820824    assert_raise(ActiveRecord::RecordInvalid) { reply.update_attributes!(:title => nil, :content => "Have a nice evening") } 
     
    17701774    xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :include => :replies, :except => :replies_count) 
    17711775    assert_equal "<topic>", xml.first(7) 
    17721776    assert xml.include?(%(<replies type="array"><reply>)) 
    1773     assert xml.include?(%(<title>The Second Topic's of the day</title>)) 
     1777    assert xml.include?(%(<title>The Second Topic of the day</title>)) 
    17741778  end 
    17751779 
    17761780  def test_array_to_xml_including_has_many_association 
  • a/activerecord/test/cases/finder_test.rb

    old new  
    542542  end 
    543543 
    544544  def test_find_all_by_array_attribute 
    545     assert_equal 2, Topic.find_all_by_title(["The First Topic", "The Second Topic's of the day"]).size 
     545    assert_equal 2, Topic.find_all_by_title(["The First Topic", "The Second Topic of the day"]).size 
    546546  end 
    547547 
    548548  def test_find_all_by_boolean_attribute 
     
    551551    assert topics.include?(topics(:first)) 
    552552 
    553553    topics = Topic.find_all_by_approved(true) 
    554     assert_equal 1, topics.size 
     554    assert_equal 3, topics.size 
    555555    assert topics.include?(topics(:second)) 
    556556  end 
    557557 
     
    563563 
    564564  def test_find_all_by_nil_attribute 
    565565    topics = Topic.find_all_by_last_read nil 
    566     assert_equal 1, topics.size 
    567     assert_nil topics[0].last_read 
     566    assert_equal 3, topics.size 
     567    assert topics.collect(&:last_read).all?(&:nil?) 
    568568  end 
    569569 
    570570  def test_find_by_nil_and_not_nil_attributes 
  • a/activerecord/test/cases/fixtures_test.rb

    old new  
    123123  end 
    124124 
    125125  def test_complete_instantiation 
    126     assert_equal 2, @topics.size 
     126    assert_equal 4, @topics.size 
    127127    assert_equal "The First Topic", @first.title 
    128128  end 
    129129 
  • a/activerecord/test/cases/lifecycle_test.rb

    old new  
    6868  fixtures :topics, :developers 
    6969 
    7070  def test_before_destroy 
    71     assert_equal 2, Topic.count 
    72     Topic.find(1).destroy 
    73     assert_equal 0, Topic.count 
     71    original_count = Topic.count 
     72    (topic_to_be_destroyed = Topic.find(1)).destroy 
     73    assert_equal original_count - (1 + topic_to_be_destroyed.replies.size), Topic.count 
    7474  end 
    7575 
    7676  def test_after_save 
  • /dev/null

    old new  
     1require "cases/helper" 
     2require 'models/post' 
     3require 'models/topic' 
     4require 'models/comment' 
     5require 'models/reply' 
     6require 'models/author' 
     7 
     8class NamedScopeTest < ActiveRecord::TestCase 
     9  fixtures :posts, :authors, :topics 
     10   
     11  def test_implements_enumerable 
     12    assert !Topic.find(:all).empty? 
     13     
     14    assert_equal Topic.find(:all),   Topic.all 
     15    assert_equal Topic.find(:all),   Topic.all.collect 
     16    assert_equal Topic.find(:first), Topic.all.first 
     17    assert_equal Topic.find(:all),   Topic.all.each { |i| i } 
     18  end 
     19   
     20  def test_found_items_are_cached 
     21    Topic.columns 
     22    all_posts = Topic.all 
     23     
     24    assert_queries(1) do 
     25      all_posts.collect 
     26      all_posts.collect 
     27    end 
     28  end 
     29   
     30  def test_reload_expires_cache_of_found_items 
     31    all_posts = Topic.all 
     32    all_posts.inspect 
     33     
     34    new_post = Topic.create! 
     35    assert !all_posts.include?(new_post) 
     36    assert all_posts.reload.include?(new_post) 
     37  end 
     38   
     39  def test_delegates_finds_and_calculations_to_the_base_class 
     40    assert !Topic.find(:all).empty? 
     41     
     42    assert_equal Topic.find(:all),               Topic.all.find(:all) 
     43    assert_equal Topic.find(:first),             Topic.all.find(:first) 
     44    assert_equal Topic.count,                    Topic.all.count 
     45    assert_equal Topic.average(:replies_count), Topic.all.average(:replies_count) 
     46  end 
     47   
     48  def test_subclasses_inherit_scopes 
     49    assert Topic.scopes.include?(:all) 
     50     
     51    assert Reply.scopes.include?(:all) 
     52    assert_equal Reply.find(:all), Reply.all 
     53  end 
     54   
     55  def test_scopes_with_options_limit_finds_to_those_matching_the_criteria_specified 
     56    assert !Topic.find(:all, :conditions => {:approved => true}).empty? 
     57     
     58    assert_equal Topic.find(:all, :conditions => {:approved => true}), Topic.approved 
     59    assert_equal Topic.count(:conditions => {:approved => true}), Topic.approved.count 
     60  end 
     61   
     62  def test_scopes_are_composable 
     63    assert_equal (approved = Topic.find(:all, :conditions => {:approved => true})), Topic.approved 
     64    assert_equal (replied = Topic.find(:all, :conditions => 'replies_count > 0')), Topic.replied 
     65    assert !(approved == replied)     
     66    assert !(approved & replied).empty? 
     67     
     68    assert_equal approved & replied, Topic.approved.replied 
     69  end 
     70 
     71  def test_procedural_scopes 
     72    topics_written_before_the_third = Topic.find(:all, :conditions => ['written_on < ?', topics(:third).written_on]) 
     73    topics_written_before_the_second = Topic.find(:all, :conditions => ['written_on < ?', topics(:second).written_on]) 
     74    assert_not_equal topics_written_before_the_second, topics_written_before_the_third 
     75     
     76    assert_equal topics_written_before_the_third, Topic.written_before(topics(:third).written_on) 
     77    assert_equal topics_written_before_the_second, Topic.written_before(topics(:second).written_on) 
     78  end 
     79   
     80  def test_extensions 
     81    assert_equal 1, Topic.anonymous_extension.one 
     82    assert_equal 2, Topic.named_extension.two 
     83  end 
     84   
     85  def test_multiple_extensions 
     86    assert_equal 2, Topic.multiple_extensions.extension_two 
     87    assert_equal 1, Topic.multiple_extensions.extension_one     
     88  end 
     89   
     90  def test_has_many_associations_have_access_to_named_scopes 
     91    assert_not_equal Post.containing_the_letter_a, authors(:david).posts 
     92    assert !Post.containing_the_letter_a.empty? 
     93         
     94    assert_equal authors(:david).posts & Post.containing_the_letter_a, authors(:david).posts.containing_the_letter_a 
     95  end 
     96   
     97  def test_has_many_through_associations_have_access_to_named_scopes 
     98    assert_not_equal Comment.containing_the_letter_e, authors(:david).posts 
     99    assert !Comment.containing_the_letter_e.empty? 
     100         
     101    assert_equal authors(:david).comments & Comment.containing_the_letter_e, authors(:david).comments.containing_the_letter_e 
     102  end 
     103   
     104  def test_active_records_have_scope_named__all__ 
     105    assert !Topic.find(:all).empty? 
     106         
     107    assert_equal Topic.find(:all), Topic.all 
     108  end 
     109   
     110  def test_active_records_have_scope_named__scoped__ 
     111    assert !Topic.find(:all, scope = {:conditions => "content LIKE '%Have%'"}).empty? 
     112     
     113    assert_equal Topic.find(:all, scope), Topic.scoped(scope) 
     114  end 
     115     
     116end 
  • a/activerecord/test/cases/validations_test.rb

    old new  
    428428    assert_nil t2.errors.on(:title) 
    429429    assert t2.errors.on(:parent_id) 
    430430 
    431     t2.parent_id = 3 
     431    t2.parent_id = 4 
    432432    assert t2.save, "Should now save t2 as unique" 
    433433 
    434434    t2.parent_id = nil 
  • a/activerecord/test/fixtures/topics.yml

    old new  
    1212 
    1313second: 
    1414  id: 2 
    15   title: The Second Topic's of the day 
     15  title: The Second Topic of the day 
    1616  author_name: Mary 
    17   written_on: 2003-07-15t15:28:00.0099+01:00 
     17  written_on: 2004-07-15t15:28:00.0099+01:00 
    1818  content: Have a nice day 
    1919  approved: true 
    2020  replies_count: 0 
    2121  parent_id: 1 
    2222  type: Reply 
     23 
     24third: 
     25  id: 3 
     26  title: The Third Topic of the day 
     27  author_name: Nick 
     28  written_on: 2005-07-15t15:28:00.0099+01:00 
     29  content: I'm a troll 
     30  approved: true 
     31  replies_count: 1 
     32 
     33fourth: 
     34  id: 4 
     35  title: The Fourth Topic of the day 
     36  author_name: Carl 
     37  written_on: 2006-07-15t15:28:00.0099+01:00 
     38  content: Why not? 
     39  approved: true 
     40  type: Reply 
     41  parent_id: 3 
     42 
  • a/activerecord/test/models/author.rb

    old new  
    33  has_many :posts_with_comments, :include => :comments, :class_name => "Post" 
    44  has_many :posts_with_categories, :include => :categories, :class_name => "Post" 
    55  has_many :posts_with_comments_and_categories, :include => [ :comments, :categories ], :order => "posts.id", :class_name => "Post" 
     6  has_many :posts_containing_the_letter_a, :class_name => "Post" 
    67  has_many :posts_with_extension, :class_name => "Post" do #, :extend => ProxyTestExtension 
    78    def testing_proxy_owner 
    89      proxy_owner 
     
    1516    end 
    1617  end 
    1718  has_many :comments, :through => :posts 
     19  has_many :comments_containing_the_letter_e, :through => :posts, :source => :comments 
    1820  has_many :comments_desc, :through => :posts, :source => :comments, :order => 'comments.id DESC' 
    1921  has_many :limited_comments, :through => :posts, :source => :comments, :limit => 1 
    2022  has_many :funky_comments, :through => :posts, :source => :comments 
  • a/activerecord/test/models/comment.rb

    old new  
    11class Comment < ActiveRecord::Base 
     2  named_scope :containing_the_letter_e, :conditions => "comments.body LIKE '%e%'" 
     3   
    24  belongs_to :post, :counter_cache => true 
    35 
    46  def self.what_are_you 
  • a/activerecord/test/models/post.rb

    old new  
    11class Post < ActiveRecord::Base 
     2  named_scope :containing_the_letter_a, :conditions => "body LIKE '%a%'" 
     3   
    24  belongs_to :author do 
    35    def greeting 
    46      "hello" 
  • a/activerecord/test/models/topic.rb

    old new  
    11class Topic < ActiveRecord::Base 
     2  named_scope :written_before, lambda { |time| 
     3    { :conditions => ['written_on < ?', time] } 
     4  } 
     5  named_scope :approved, :conditions => {:approved => true} 
     6  named_scope :replied, :conditions => ['replies_count > 0'] 
     7  named_scope :anonymous_extension do 
     8    def one 
     9      1 
     10    end 
     11  end 
     12  module NamedExtension 
     13    def two 
     14      2 
     15    end 
     16  end 
     17  module MultipleExtensionOne 
     18    def extension_one 
     19      1 
     20    end 
     21  end 
     22  module MultipleExtensionTwo 
     23    def extension_two 
     24      2 
     25    end 
     26  end 
     27  named_scope :named_extension, :extend => NamedExtension 
     28  named_scope :multiple_extensions, :extend => [MultipleExtensionTwo, MultipleExtensionOne] 
     29   
    230  has_many :replies, :dependent => :destroy, :foreign_key => "parent_id" 
    331  serialize :content 
    432