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/categorization' require 'models/category' require 'models/post' require 'models/author' require 'models/comment' require 'models/tag' require 'models/tagging' require 'models/person' require 'models/reader' require 'models/parrot' require 'models/pirate' require 'models/treasure' require 'models/price_estimate' require 'models/club' require 'models/member' require 'models/membership' require 'models/sponsor' class AssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :developers_projects, :computers def test_include_with_order_works assert_nothing_raised {Account.find(:first, :order => 'id', :include => :firm)} assert_nothing_raised {Account.find(:first, :order => :id, :include => :firm)} end def test_bad_collection_keys assert_raise(ArgumentError, 'ActiveRecord should have barked on bad collection keys') do Class.new(ActiveRecord::Base).has_many(:wheels, :name => 'wheels') end end def test_should_construct_new_finder_sql_after_create person = Person.new :first_name => 'clark' assert_equal [], person.readers.find(:all) person.save! reader = Reader.create! :person => person, :post => Post.new(:title => "foo", :body => "bar") assert_equal [reader], person.readers.find(:all) end def test_force_reload firm = Firm.new("name" => "A New Firm, Inc") firm.save firm.clients.each {|c|} # forcing to load all clients assert firm.clients.empty?, "New firm shouldn't have client objects" assert_equal 0, firm.clients.size, "New firm should have 0 clients" client = Client.new("name" => "TheClient.com", "firm_id" => firm.id) client.save assert firm.clients.empty?, "New firm should have cached no client objects" assert_equal 0, firm.clients.size, "New firm should have cached 0 clients count" assert !firm.clients(true).empty?, "New firm should have reloaded client objects" assert_equal 1, firm.clients(true).size, "New firm should have reloaded clients count" end def test_storing_in_pstore require "tmpdir" store_filename = File.join(Dir.tmpdir, "ar-pstore-association-test") File.delete(store_filename) if File.exist?(store_filename) require "pstore" apple = Firm.create("name" => "Apple") natural = Client.new("name" => "Natural Company") apple.clients << natural db = PStore.new(store_filename) db.transaction do db["apple"] = apple end db = PStore.new(store_filename) db.transaction do assert_equal "Natural Company", db["apple"].clients.first.name end end end class AssociationProxyTest < ActiveRecord::TestCase fixtures :authors, :posts, :categorizations, :categories, :developers, :projects, :developers_projects def test_proxy_accessors welcome = posts(:welcome) assert_equal welcome, welcome.author.proxy_owner assert_equal welcome.class.reflect_on_association(:author), welcome.author.proxy_reflection welcome.author.class # force load target assert_equal welcome.author, welcome.author.proxy_target david = authors(:david) assert_equal david, david.posts.proxy_owner assert_equal david.class.reflect_on_association(:posts), david.posts.proxy_reflection david.posts.class # force load target assert_equal david.posts, david.posts.proxy_target assert_equal david, david.posts_with_extension.testing_proxy_owner assert_equal david.class.reflect_on_association(:posts_with_extension), david.posts_with_extension.testing_proxy_reflection david.posts_with_extension.class # force load target assert_equal david.posts_with_extension, david.posts_with_extension.testing_proxy_target end def test_push_does_not_load_target david = authors(:david) david.posts << (post = Post.new(:title => "New on Edge", :body => "More cool stuff!")) assert !david.posts.loaded? assert david.posts.include?(post) end def test_push_has_many_through_does_not_load_target david = authors(:david) david.categories << categories(:technology) assert !david.categories.loaded? assert david.categories.include?(categories(:technology)) end def test_push_followed_by_save_does_not_load_target david = authors(:david) david.posts << (post = Post.new(:title => "New on Edge", :body => "More cool stuff!")) assert !david.posts.loaded? david.save assert !david.posts.loaded? assert david.posts.include?(post) end def test_push_does_not_lose_additions_to_new_record josh = Author.new(:name => "Josh") josh.posts << Post.new(:title => "New on Edge", :body => "More cool stuff!") assert josh.posts.loaded? assert_equal 1, josh.posts.size end def test_save_on_parent_does_not_load_target david = developers(:david) assert !david.projects.loaded? david.update_attribute(:created_at, Time.now) assert !david.projects.loaded? end def test_inspect_does_not_reload_a_not_yet_loaded_target andreas = Developer.new :name => 'Andreas', :log => 'new developer added' assert !andreas.audit_logs.loaded? assert_match(/message: "new developer added"/, andreas.audit_logs.inspect) end def test_save_on_parent_saves_children developer = Developer.create :name => "Bryan", :salary => 50_000 assert_equal 1, developer.reload.audit_logs.size end def test_create_via_association_with_block post = authors(:david).posts.create(:title => "New on Edge") {|p| p.body = "More cool stuff!"} assert_equal post.title, "New on Edge" assert_equal post.body, "More cool stuff!" end def test_create_with_bang_via_association_with_block post = authors(:david).posts.create!(:title => "New on Edge") {|p| p.body = "More cool stuff!"} assert_equal post.title, "New on Edge" assert_equal post.body, "More cool stuff!" end def test_failed_reload_returns_nil p = setup_dangling_association assert_nil p.author.reload end def test_failed_reset_returns_nil p = setup_dangling_association assert_nil p.author.reset end def test_reload_returns_assocition david = developers(:david) assert_nothing_raised do assert_equal david.projects, david.projects.reload.reload end end def test_belongs_to_mass_assignment post_attributes = { :title => 'Associations', :body => 'Are They Accessible?' } author_attributes = { :name => 'David Dollar' } assert_no_difference 'Author.count' do assert_raise(ActiveRecord::AssociationTypeMismatch) do Post.create(post_attributes.merge({:author => author_attributes})) end end assert_difference 'Author.count' do post = Post.create(post_attributes.merge({:creatable_author => author_attributes})) assert_equal post.creatable_author.name, author_attributes[:name] end end def test_has_one_mass_assignment post_attributes = { :title => 'Associations', :body => 'Are They Accessible?' } comment_attributes = { :body => 'Setter Takes Hash' } assert_no_difference 'Comment.count' do assert_raise(ActiveRecord::AssociationTypeMismatch) do Post.create(post_attributes.merge({:uncreatable_comment => comment_attributes})) end end assert_difference 'Comment.count' do post = Post.create(post_attributes.merge({:creatable_comment => comment_attributes})) assert_equal post.creatable_comment.body, comment_attributes[:body] end end def test_has_many_mass_assignment post = posts(:welcome) post_attributes = { :title => 'Associations', :body => 'Are They Accessible?' } comment_attributes = { :body => 'Setter Takes Hash' } assert_no_difference 'Comment.count' do assert_raise(ActiveRecord::AssociationTypeMismatch) do Post.create(post_attributes.merge({:comments => [comment_attributes]})) end assert_raise(ActiveRecord::AssociationTypeMismatch) do post.comments << comment_attributes end end assert_difference 'Comment.count' do post = Post.create(post_attributes.merge({:creatable_comments => [comment_attributes]})) assert_equal post.creatable_comments.last.body, comment_attributes[:body] end assert_difference 'Comment.count' do post.creatable_comments << comment_attributes assert_equal post.comments.last.body, comment_attributes[:body] end post.creatable_comments = [comment_attributes, comment_attributes] assert_equal post.creatable_comments.count, 2 end def test_has_and_belongs_to_many_mass_assignment post = posts(:welcome) post_attributes = { :title => 'Associations', :body => 'Are They Accessible?' } category_attributes = { :name => 'Accessible Association', :type => 'Category' } assert_no_difference 'Category.count' do assert_raise(ActiveRecord::AssociationTypeMismatch) do Post.create(post_attributes.merge({:categories => [category_attributes]})) end assert_raise(ActiveRecord::AssociationTypeMismatch) do post.categories << category_attributes end end assert_difference 'Category.count' do post = Post.create(post_attributes.merge({:creatable_categories => [category_attributes]})) assert_equal post.creatable_categories.last.name, category_attributes[:name] end assert_difference 'Category.count' do post.creatable_categories << category_attributes assert_equal post.creatable_categories.last.name, category_attributes[:name] end post.creatable_categories = [category_attributes, category_attributes] assert_equal post.creatable_categories.count, 2 end def test_association_proxy_setter_can_take_hash special_comment_attributes = { :body => 'Setter Takes Hash' } post = posts(:welcome) post.creatable_comment = { :body => 'Setter Takes Hash' } assert_equal post.creatable_comment.body, special_comment_attributes[:body] end def test_association_collection_can_take_hash post_attributes = { :title => 'Setter Takes', :body => 'Hash' } david = authors(:david) post = (david.posts << post_attributes).last assert_equal post.title, post_attributes[:title] david.posts = [post_attributes, post_attributes] assert_equal david.posts.count, 2 end def setup_dangling_association josh = Author.create(:name => "Josh") p = Post.create(:title => "New on Edge", :body => "More cool stuff!", :author => josh) josh.destroy p end end class OverridingAssociationsTest < ActiveRecord::TestCase class Person < ActiveRecord::Base; end class DifferentPerson < ActiveRecord::Base; end class PeopleList < ActiveRecord::Base has_and_belongs_to_many :has_and_belongs_to_many, :before_add => :enlist has_many :has_many, :before_add => :enlist belongs_to :belongs_to has_one :has_one end class DifferentPeopleList < PeopleList # Different association with the same name, callbacks should be omitted here. has_and_belongs_to_many :has_and_belongs_to_many, :class_name => 'DifferentPerson' has_many :has_many, :class_name => 'DifferentPerson' belongs_to :belongs_to, :class_name => 'DifferentPerson' has_one :has_one, :class_name => 'DifferentPerson' end def test_habtm_association_redefinition_callbacks_should_differ_and_not_inherited # redeclared association on AR descendant should not inherit callbacks from superclass callbacks = PeopleList.read_inheritable_attribute(:before_add_for_has_and_belongs_to_many) assert_equal([:enlist], callbacks) callbacks = DifferentPeopleList.read_inheritable_attribute(:before_add_for_has_and_belongs_to_many) assert_equal([], callbacks) end def test_has_many_association_redefinition_callbacks_should_differ_and_not_inherited # redeclared association on AR descendant should not inherit callbacks from superclass callbacks = PeopleList.read_inheritable_attribute(:before_add_for_has_many) assert_equal([:enlist], callbacks) callbacks = DifferentPeopleList.read_inheritable_attribute(:before_add_for_has_many) assert_equal([], callbacks) end def test_habtm_association_redefinition_reflections_should_differ_and_not_inherited assert_not_equal( PeopleList.reflect_on_association(:has_and_belongs_to_many), DifferentPeopleList.reflect_on_association(:has_and_belongs_to_many) ) end def test_has_many_association_redefinition_reflections_should_differ_and_not_inherited assert_not_equal( PeopleList.reflect_on_association(:has_many), DifferentPeopleList.reflect_on_association(:has_many) ) end def test_belongs_to_association_redefinition_reflections_should_differ_and_not_inherited assert_not_equal( PeopleList.reflect_on_association(:belongs_to), DifferentPeopleList.reflect_on_association(:belongs_to) ) end def test_has_one_association_redefinition_reflections_should_differ_and_not_inherited assert_not_equal( PeopleList.reflect_on_association(:has_one), DifferentPeopleList.reflect_on_association(:has_one) ) end end