aboutsummaryrefslogblamecommitdiffstats
path: root/activerecord/test/cases/identity_map_test.rb
blob: d4be6980822957935564df91e0893f4e58790742 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

















                           


                       






                                                                  



                                               
                                        

                                                     










































                                                                   











                                                                          




                                                                                            














                                                                                                        















                                                                            

































































































                                                                                                                                                                        
                                

















                                                                                                                                                                                                                   





                                                                                 













                                                            
   
require "cases/helper"
require 'models/developer'
require 'models/project'
require 'models/company'
require 'models/topic'
require 'models/reply'
require 'models/computer'
require 'models/customer'
require 'models/order'
require 'models/post'
require 'models/author'
require 'models/tag'
require 'models/tagging'
require 'models/comment'
require 'models/sponsor'
require 'models/member'
require 'models/essay'
require 'models/subscriber'
require "models/pirate"
require "models/bird"
require "models/parrot"

class IdentityMapTest < ActiveRecord::TestCase
  fixtures :accounts, :companies, :developers, :projects, :topics,
    :developers_projects, :computers, :authors, :author_addresses,
    :posts, :tags, :taggings, :comments, :subscribers

  def test_find_id
    assert_same(Client.find(3), Client.find(3))
  end

  def test_find_id_without_identity_map
    ActiveRecord::IdentityMap.without do
      assert_not_same(Client.find(3), Client.find(3))
    end
  end

  def test_find_pkey
    assert_same(
      Subscriber.find('swistak'),
      Subscriber.find('swistak')
    )
  end

  def test_find_by_id
    assert_same(
      Client.find_by_id(3),
      Client.find_by_id(3)
    )
  end

  def test_find_by_pkey
    assert_same(
      Subscriber.find_by_nick('swistak'),
      Subscriber.find_by_nick('swistak')
    )
  end

  def test_find_first_id
    assert_same(
      Client.find(:first, :conditions => {:id => 1}),
      Client.find(:first, :conditions => {:id => 1})
    )
  end

  def test_find_first_pkey
    assert_same(
      Subscriber.find(:first, :conditions => {:nick => 'swistak'}),
      Subscriber.find(:first, :conditions => {:nick => 'swistak'})
    )
  end

  def test_creation
    t1 = Topic.create("title" => "t1")
    t2 = Topic.find(t1.id)
    assert_same(t1, t2)
  end

  def test_loading_new_instance_should_not_update_dirty_attributes
    swistak = Subscriber.find(:first, :conditions => {:nick => 'swistak'})
    swistak.name = "Swistak Sreberkowiec"
    assert_equal(["name"], swistak.changed)

    s = Subscriber.find('swistak')

    assert swistak.name_changed?
    assert_equal("Swistak Sreberkowiec", swistak.name)
  end

  def test_loading_new_instance_should_remove_dirt
    swistak = Subscriber.find(:first, :conditions => {:nick => 'swistak'})
    swistak.name = "Swistak Sreberkowiec"

    assert_equal({'name' => ["Marcin Raczkowski", "Swistak Sreberkowiec"]}, swistak.changes)
    assert_equal("Swistak Sreberkowiec", swistak.name)
  end

  def test_has_many_associations
    pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
    pirate.birds.create!(:name => 'Posideons Killer')
    pirate.birds.create!(:name => 'Killer bandita Dionne')

    posideons, killer = pirate.birds

    pirate.reload

    pirate.birds_attributes = [{ :id => posideons.id, :name => 'Grace OMalley' }]
    assert_equal 'Grace OMalley', pirate.birds.send(:load_target).find { |r| r.id == posideons.id }.name
  end

# Currently AR is not allowing changing primary key (see Persistence#update)
# So we ignore it. If this changes, this test needs to be uncommented.
#  def test_updating_of_pkey
#    assert client = Client.find(3),
#    client.update_attribute(:id, 666)
#
#    assert Client.find(666)
#    assert_same(client, Client.find(666))
#
#    s = Subscriber.find_by_nick('swistak')
#    assert s.update_attribute(:nick, 'swistakTheJester')
#    assert_equal('swistakTheJester', s.nick)
#
#    assert stj = Subscriber.find_by_nick('swistakTheJester')
#    assert_same(s, stj)
#  end

  def test_changing_associations
    t1 = Topic.create("title" => "t1")
    t2 = Topic.create("title" => "t2")
    r1 = Reply.new("title" => "r1", "content" => "r1")

    r1.topic = t1
    assert r1.save

    assert_same(t1.replies.first, r1)

    r1.topic = t2
    assert r1.save

    assert_same(t2.replies.first, r1)
    assert_equal(0, t1.replies.size)
  end

  def test_im_with_polymorphic_has_many_going_through_join_model_with_custom_select_and_joins
    tag = posts(:welcome).tags.first
    tag_with_joins_and_select = posts(:welcome).tags.add_joins_and_select.first
    assert_same(tag, tag_with_joins_and_select)
    assert_nothing_raised(NoMethodError, "Joins/select was not loaded") { tag.author_id }
  end

  def test_find_with_preloaded_associations
    assert_queries(2) do
      posts = Post.preload(:comments)
      assert posts.first.comments.first
    end

    # With IM we'll retrieve post object from previous query, it'll have comments
    # already preloaded from first call
    assert_queries(1) do
      posts = Post.preload(:comments).to_a
      assert posts.first.comments.first
    end

    assert_queries(2) do
      posts = Post.preload(:author)
      assert posts.first.author
    end

    # With IM we'll retrieve post object from previous query, it'll have comments
    # already preloaded from first call
    assert_queries(1) do
      posts = Post.preload(:author).to_a
      assert posts.first.author
    end

    assert_queries(1) do
      posts = Post.preload(:author, :comments).to_a
      assert posts.first.author
      assert posts.first.comments.first
    end
  end

  def test_find_with_included_associations
    assert_queries(2) do
      posts = Post.includes(:comments)
      assert posts.first.comments.first
    end

    assert_queries(1) do
      posts = Post.scoped.includes(:comments)
      assert posts.first.comments.first
    end

    assert_queries(2) do
      posts = Post.includes(:author)
      assert posts.first.author
    end

    assert_queries(1) do
      posts = Post.includes(:author, :comments).to_a
      assert posts.first.author
      assert posts.first.comments.first
    end
  end

  def test_eager_loading_with_conditions_on_joined_table_preloads
    posts = assert_queries(2) do
      Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
    end
    assert_equal [posts(:welcome)], posts
    assert_equal authors(:david), assert_no_queries { posts[0].author}

    posts = assert_queries(1) do
      Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
    end
    assert_equal [posts(:welcome)], posts
    assert_equal authors(:david), assert_no_queries { posts[0].author}

    posts = assert_queries(1) do
      Post.find(:all, :include => :author, :joins => {:taggings => :tag}, :conditions => "tags.name = 'General'", :order => 'posts.id')
    end
    assert_equal posts(:welcome, :thinking), posts

    posts = assert_queries(1) do
      Post.find(:all, :include => :author, :joins => {:taggings => {:tag => :taggings}}, :conditions => "taggings_tags.super_tag_id=2", :order => 'posts.id')
    end
    assert_equal posts(:welcome, :thinking), posts
  end

  def test_eager_loading_with_conditions_on_string_joined_table_preloads
    posts = assert_queries(2) do
      Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => "INNER JOIN comments on comments.post_id = posts.id", :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
    end
    assert_equal [posts(:welcome)], posts
    assert_equal authors(:david), assert_no_queries { posts[0].author}

    posts = assert_queries(1) do
      Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => ["INNER JOIN comments on comments.post_id = posts.id"], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
    end
    assert_equal [posts(:welcome)], posts
    assert_equal authors(:david), assert_no_queries { posts[0].author}
  end

  # Second search should not change read only status for collection
  def test_find_with_joins_option_implies_readonly
    Developer.joins(', projects').each { |d| assert d.readonly? }
    Developer.joins(', projects').readonly(false).each { |d| assert d.readonly? }
  end

  def test_reload_object_if_save_failed
    developer = Developer.first
    developer.salary = 0

    assert !developer.save

    same_developer = Developer.first

    assert_not_same  developer, same_developer
    assert_not_equal 0, same_developer.salary
    assert_not_equal developer.salary, same_developer.salary
  end

end