2017-07-09 13:41:28 -04:00
# frozen_string_literal: true
2011-06-06 14:17:44 -04:00
require " cases/helper "
2016-08-06 12:26:20 -04:00
require " models/computer "
require " models/developer "
require " models/project "
require " models/company "
require " models/categorization "
require " models/category "
require " models/post "
require " models/author "
2021-01-20 15:27:11 -05:00
require " models/book "
2016-08-06 12:26:20 -04:00
require " models/comment "
require " models/tag "
require " models/tagging "
require " models/person "
require " models/reader "
require " models/ship_part "
require " models/ship "
require " models/liquid "
require " models/molecule "
require " models/electron "
2020-08-13 18:11:28 -04:00
require " models/human "
2016-08-06 12:26:20 -04:00
require " models/interest "
2019-03-14 15:57:14 -04:00
require " models/pirate "
require " models/parrot "
require " models/bird "
require " models/treasure "
require " models/price_estimate "
2021-03-05 08:22:08 -05:00
require " models/invoice "
require " models/discount "
require " models/line_item "
require " models/shipping_line "
2004-11-23 20:04:44 -05:00
2008-01-21 12:20:51 -05:00
class AssociationsTest < ActiveRecord :: TestCase
2005-06-10 09:54:58 -04:00
fixtures :accounts , :companies , :developers , :projects , :developers_projects ,
2021-02-19 04:57:45 -05:00
:computers , :people , :readers , :authors , :author_addresses , :author_favorites ,
:comments , :posts
2005-09-27 23:52:57 -04:00
2010-07-26 15:12:36 -04:00
def test_eager_loading_should_not_change_count_of_children
2016-08-06 13:37:57 -04:00
liquid = Liquid . create ( name : " salty " )
molecule = liquid . molecules . create ( name : " molecule_1 " )
molecule . electrons . create ( name : " electron_1 " )
molecule . electrons . create ( name : " electron_2 " )
2010-07-26 15:12:36 -04:00
2016-08-06 13:37:57 -04:00
liquids = Liquid . includes ( molecules : :electrons ) . references ( :molecules ) . where ( " molecules.id is not null " )
2010-07-26 15:12:36 -04:00
assert_equal 1 , liquids [ 0 ] . molecules . length
end
2014-09-04 17:40:10 -04:00
def test_subselect
author = authors :david
favs = author . author_favorites
2016-08-06 13:37:57 -04:00
fav2 = author . author_favorites . where ( author : Author . where ( id : author . id ) ) . to_a
2014-09-04 17:40:10 -04:00
assert_equal favs , fav2
end
2010-07-14 23:13:56 -04:00
def test_loading_the_association_target_should_keep_child_records_marked_for_destruction
2016-08-06 13:37:57 -04:00
ship = Ship . create! ( name : " The good ship Dollypop " )
part = ship . parts . create! ( name : " Mast " )
2010-07-14 23:13:56 -04:00
part . mark_for_destruction
2018-01-25 18:14:09 -05:00
assert_predicate ship . parts [ 0 ] , :marked_for_destruction?
2010-07-14 23:13:56 -04:00
end
def test_loading_the_association_target_should_load_most_recent_attributes_for_child_records_marked_for_destruction
2016-08-06 13:37:57 -04:00
ship = Ship . create! ( name : " The good ship Dollypop " )
part = ship . parts . create! ( name : " Mast " )
2010-07-14 23:13:56 -04:00
part . mark_for_destruction
2016-08-06 12:26:20 -04:00
ShipPart . find ( part . id ) . update_columns ( name : " Deck " )
assert_equal " Deck " , ship . parts [ 0 ] . name
2010-07-14 23:13:56 -04:00
end
2010-08-14 01:13:00 -04:00
2008-01-18 23:19:53 -05:00
def test_include_with_order_works
2016-08-16 03:30:11 -04:00
assert_nothing_raised { Account . all . merge! ( order : " id " , includes : :firm ) . first }
assert_nothing_raised { Account . all . merge! ( order : :id , includes : :firm ) . first }
2008-01-18 23:19:53 -05:00
end
2006-09-25 01:58:38 -04:00
def test_bad_collection_keys
2016-08-06 12:26:20 -04:00
assert_raise ( ArgumentError , " ActiveRecord should have barked on bad collection keys " ) do
2016-08-06 13:37:57 -04:00
Class . new ( ActiveRecord :: Base ) . has_many ( :wheels , name : " wheels " )
2006-09-25 01:58:38 -04:00
end
end
2008-01-18 02:30:42 -05:00
2007-10-16 03:24:23 -04:00
def test_should_construct_new_finder_sql_after_create
2016-08-06 13:37:57 -04:00
person = Person . new first_name : " clark "
2012-07-27 12:55:43 -04:00
assert_equal [ ] , person . readers . to_a
2007-10-16 03:24:23 -04:00
person . save!
2016-08-06 13:37:57 -04:00
reader = Reader . create! person : person , post : Post . new ( title : " foo " , body : " bar " )
2008-08-26 05:38:48 -04:00
assert person . readers . find ( reader . id )
2007-10-16 03:24:23 -04:00
end
2006-09-25 01:58:38 -04:00
2004-11-23 20:04:44 -05:00
def test_force_reload
2005-01-15 12:45:16 -05:00
firm = Firm . new ( " name " = > " A New Firm, Inc " )
2004-11-23 20:04:44 -05:00
firm . save
2018-09-25 13:18:20 -04:00
firm . clients . each { } # forcing to load all clients
2004-11-23 20:04:44 -05:00
assert firm . clients . empty? , " New firm shouldn't have client objects "
assert_equal 0 , firm . clients . size , " New firm should have 0 clients "
2005-01-15 12:45:16 -05:00
client = Client . new ( " name " = > " TheClient.com " , " firm_id " = > firm . id )
2004-11-23 20:04:44 -05:00
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 "
2016-12-28 23:18:42 -05:00
firm . clients . reload
2018-05-12 22:26:10 -04:00
assert_not firm . clients . empty? , " New firm should have reloaded client objects "
2016-12-28 23:18:42 -05:00
assert_equal 1 , firm . clients . size , " New firm should have reloaded clients count "
2004-11-23 20:04:44 -05:00
end
2010-08-14 01:13:00 -04:00
2010-07-07 15:47:57 -04:00
def test_using_limitable_reflections_helper
2012-07-27 12:27:47 -04:00
using_limitable_reflections = lambda { | reflections | Tagging . all . send :using_limitable_reflections? , reflections }
2010-07-07 15:47:57 -04:00
belongs_to_reflections = [ Tagging . reflect_on_association ( :tag ) , Tagging . reflect_on_association ( :super_tag ) ]
has_many_reflections = [ Tag . reflect_on_association ( :taggings ) , Developer . reflect_on_association ( :projects ) ]
mixed_reflections = ( belongs_to_reflections + has_many_reflections ) . uniq
assert using_limitable_reflections . call ( belongs_to_reflections ) , " Belong to associations are limitable "
2018-05-12 22:26:10 -04:00
assert_not using_limitable_reflections . call ( has_many_reflections ) , " All has many style associations are not limitable "
assert_not using_limitable_reflections . call ( mixed_reflections ) , " No collection associations (has many style) should pass "
2010-07-07 15:47:57 -04:00
end
2010-08-14 01:13:00 -04:00
2012-01-16 16:14:34 -05:00
def test_association_with_references
firm = companies ( :first_firm )
2020-08-24 00:30:41 -04:00
assert_equal [ :foo ] , firm . association_with_references . references_values
2012-01-16 16:14:34 -05:00
end
2004-11-23 20:04:44 -05:00
end
2008-01-18 02:30:42 -05:00
2008-01-21 12:20:51 -05:00
class AssociationProxyTest < ActiveRecord :: TestCase
2017-04-27 02:44:25 -04:00
fixtures :authors , :author_addresses , :posts , :categorizations , :categories , :developers , :projects , :developers_projects
2008-01-18 02:30:42 -05:00
2007-04-25 20:18:38 -04:00
def test_push_does_not_load_target
david = authors ( :david )
2007-06-11 03:15:59 -04:00
2016-08-06 13:37:57 -04:00
david . posts << ( post = Post . new ( title : " New on Edge " , body : " More cool stuff! " ) )
2018-01-25 18:14:09 -05:00
assert_not_predicate david . posts , :loaded?
2016-09-16 12:44:05 -04:00
assert_includes david . posts , post
2007-12-28 13:01:22 -05:00
end
def test_push_has_many_through_does_not_load_target
david = authors ( :david )
2007-04-25 20:18:38 -04:00
david . categories << categories ( :technology )
2018-01-25 18:14:09 -05:00
assert_not_predicate david . categories , :loaded?
2016-09-16 12:44:05 -04:00
assert_includes david . categories , categories ( :technology )
2007-04-25 20:18:38 -04:00
end
2008-01-18 02:30:42 -05:00
2007-12-28 13:01:22 -05:00
def test_push_followed_by_save_does_not_load_target
david = authors ( :david )
2016-08-06 13:37:57 -04:00
david . posts << ( post = Post . new ( title : " New on Edge " , body : " More cool stuff! " ) )
2018-01-25 18:14:09 -05:00
assert_not_predicate david . posts , :loaded?
2007-12-28 13:01:22 -05:00
david . save
2018-01-25 18:14:09 -05:00
assert_not_predicate david . posts , :loaded?
2016-09-16 12:44:05 -04:00
assert_includes david . posts , post
2007-12-28 13:01:22 -05:00
end
2007-06-11 03:15:59 -04:00
2007-10-27 23:39:18 -04:00
def test_push_does_not_lose_additions_to_new_record
2016-08-06 13:37:57 -04:00
josh = Author . new ( name : " Josh " )
josh . posts << Post . new ( title : " New on Edge " , body : " More cool stuff! " )
2018-01-25 18:14:09 -05:00
assert_predicate josh . posts , :loaded?
2007-10-27 23:39:18 -04:00
assert_equal 1 , josh . posts . size
end
2013-03-01 09:30:22 -05:00
def test_append_behaves_like_push
2016-08-06 13:37:57 -04:00
josh = Author . new ( name : " Josh " )
josh . posts . append Post . new ( title : " New on Edge " , body : " More cool stuff! " )
2018-01-25 18:14:09 -05:00
assert_predicate josh . posts , :loaded?
2013-03-01 09:30:22 -05:00
assert_equal 1 , josh . posts . size
end
def test_prepend_is_not_defined
2016-08-06 13:37:57 -04:00
josh = Author . new ( name : " Josh " )
2013-03-01 09:30:22 -05:00
assert_raises ( NoMethodError ) { josh . posts . prepend Post . new }
end
2007-06-21 16:47:26 -04:00
def test_save_on_parent_does_not_load_target
david = developers ( :david )
2018-01-25 18:14:09 -05:00
assert_not_predicate david . projects , :loaded?
2012-07-24 19:20:03 -04:00
david . update_columns ( created_at : Time . now )
2018-01-25 18:14:09 -05:00
assert_not_predicate david . projects , :loaded?
2007-06-21 16:47:26 -04:00
end
2016-07-24 11:00:38 -04:00
def test_load_does_load_target
david = developers ( :david )
2018-01-25 18:14:09 -05:00
assert_not_predicate david . projects , :loaded?
2016-07-24 11:00:38 -04:00
david . projects . load
2018-01-25 18:14:09 -05:00
assert_predicate david . projects , :loaded?
2016-07-24 11:00:38 -04:00
end
2008-05-08 01:04:53 -04:00
def test_inspect_does_not_reload_a_not_yet_loaded_target
2016-08-06 13:37:57 -04:00
andreas = Developer . new name : " Andreas " , log : " new developer added "
2018-01-25 18:14:09 -05:00
assert_not_predicate andreas . audit_logs , :loaded?
2008-05-08 01:04:53 -04:00
assert_match ( / message: "new developer added" / , andreas . audit_logs . inspect )
2020-10-22 05:25:34 -04:00
assert_predicate andreas . audit_logs , :loaded?
2008-05-08 01:04:53 -04:00
end
2007-10-10 02:45:13 -04:00
def test_save_on_parent_saves_children
2016-08-06 13:37:57 -04:00
developer = Developer . create name : " Bryan " , salary : 50_000
2007-10-10 02:45:13 -04:00
assert_equal 1 , developer . reload . audit_logs . size
end
2007-11-28 21:19:10 -05:00
2008-05-23 16:51:56 -04:00
def test_create_via_association_with_block
2016-08-16 03:30:11 -04:00
post = authors ( :david ) . posts . create ( title : " New on Edge " ) { | p | p . body = " More cool stuff! " }
2008-05-23 17:57:11 -04:00
assert_equal post . title , " New on Edge "
assert_equal post . body , " More cool stuff! "
end
def test_create_with_bang_via_association_with_block
2016-08-16 03:30:11 -04:00
post = authors ( :david ) . posts . create! ( title : " New on Edge " ) { | p | p . body = " More cool stuff! " }
2008-05-23 17:57:11 -04:00
assert_equal post . title , " New on Edge "
assert_equal post . body , " More cool stuff! "
2008-05-23 16:51:56 -04:00
end
2013-05-20 01:05:43 -04:00
def test_reload_returns_association
2007-12-09 20:07:04 -05:00
david = developers ( :david )
assert_nothing_raised do
assert_equal david . projects , david . projects . reload . reload
end
end
2011-07-27 07:36:00 -04:00
def test_proxy_association_accessor
david = developers ( :david )
assert_equal david . association ( :projects ) , david . projects . proxy_association
end
2012-04-27 06:52:34 -04:00
def test_scoped_allows_conditions
2016-08-06 12:26:20 -04:00
assert developers ( :david ) . projects . merge ( where : " foo " ) . to_sql . include? ( " foo " )
2012-04-27 06:52:34 -04:00
end
2012-08-01 18:14:29 -04:00
test " getting a scope from an association " do
david = developers ( :david )
assert david . projects . scope . is_a? ( ActiveRecord :: Relation )
assert_equal david . projects , david . projects . scope
end
2013-03-15 09:46:39 -04:00
2017-05-16 11:40:26 -04:00
test " proxy object is cached " do
david = developers ( :david )
assert_same david . projects , david . projects
end
2017-05-30 04:47:20 -04:00
test " proxy object can be stubbed " do
david = developers ( :david )
david . projects . define_singleton_method ( :extra_method ) { 42 }
assert_equal 42 , david . projects . extra_method
end
2013-04-25 16:37:44 -04:00
test " inverses get set of subsets of the association " do
2020-08-13 18:11:28 -04:00
human = Human . create
human . interests . create
2013-04-25 16:37:44 -04:00
2020-08-13 18:11:28 -04:00
human = Human . find ( human . id )
2013-04-25 16:37:44 -04:00
assert_queries ( 1 ) do
2020-08-13 18:11:28 -04:00
assert_equal human , human . interests . where ( " 1=1 " ) . first . human
2013-04-25 16:37:44 -04:00
end
end
2014-01-21 21:19:51 -05:00
2014-12-29 13:55:50 -05:00
test " first! works on loaded associations " do
david = authors ( :david )
2017-08-26 04:21:22 -04:00
assert_equal david . first_posts . first , david . first_posts . reload . first!
2018-01-25 18:14:09 -05:00
assert_predicate david . first_posts , :loaded?
2017-08-26 04:21:22 -04:00
assert_no_queries { david . first_posts . first! }
2014-12-29 13:55:50 -05:00
end
2016-07-28 10:31:09 -04:00
def test_pluck_uses_loaded_target
david = authors ( :david )
2017-08-26 04:21:22 -04:00
assert_equal david . first_posts . pluck ( :title ) , david . first_posts . load . pluck ( :title )
2018-01-25 18:14:09 -05:00
assert_predicate david . first_posts , :loaded?
2017-08-26 04:21:22 -04:00
assert_no_queries { david . first_posts . pluck ( :title ) }
2016-07-28 10:31:09 -04:00
end
2020-03-17 18:28:39 -04:00
def test_pick_uses_loaded_target
david = authors ( :david )
assert_equal david . first_posts . pick ( :title ) , david . first_posts . load . pick ( :title )
assert_predicate david . first_posts , :loaded?
assert_no_queries { david . first_posts . pick ( :title ) }
end
2014-01-21 21:19:51 -05:00
def test_reset_unloads_target
david = authors ( :david )
david . posts . reload
2018-01-25 18:14:09 -05:00
assert_predicate david . posts , :loaded?
2020-05-20 09:12:02 -04:00
assert_predicate david . posts , :loaded
2014-01-21 21:19:51 -05:00
david . posts . reset
2018-01-25 18:14:09 -05:00
assert_not_predicate david . posts , :loaded?
2020-05-20 09:12:02 -04:00
assert_not_predicate david . posts , :loaded
2014-01-21 21:19:51 -05:00
end
2006-05-28 17:33:34 -04:00
end
2008-01-21 12:20:51 -05:00
class OverridingAssociationsTest < ActiveRecord :: TestCase
2007-10-27 16:31:09 -04:00
class DifferentPerson < ActiveRecord :: Base ; end
class PeopleList < ActiveRecord :: Base
2016-08-06 13:37:57 -04:00
has_and_belongs_to_many :has_and_belongs_to_many , before_add : :enlist
has_many :has_many , before_add : :enlist
2007-10-27 16:31:09 -04:00
belongs_to :belongs_to
has_one :has_one
end
class DifferentPeopleList < PeopleList
# Different association with the same name, callbacks should be omitted here.
2016-08-06 13:37:57 -04:00
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 "
2007-10-27 16:31:09 -04:00
end
def test_habtm_association_redefinition_callbacks_should_differ_and_not_inherited
# redeclared association on AR descendant should not inherit callbacks from superclass
2010-11-19 12:29:33 -05:00
callbacks = PeopleList . before_add_for_has_and_belongs_to_many
2013-07-31 21:19:36 -04:00
assert_equal ( 1 , callbacks . length )
2010-11-19 12:29:33 -05:00
callbacks = DifferentPeopleList . before_add_for_has_and_belongs_to_many
2007-10-27 16:31:09 -04:00
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
2010-11-19 12:29:33 -05:00
callbacks = PeopleList . before_add_for_has_many
2013-07-31 21:19:36 -04:00
assert_equal ( 1 , callbacks . length )
2010-11-19 12:29:33 -05:00
callbacks = DifferentPeopleList . before_add_for_has_many
2007-10-27 16:31:09 -04:00
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
2012-11-28 15:43:09 -05:00
def test_requires_symbol_argument
2013-03-01 09:30:22 -05:00
assert_raises ArgumentError do
2012-11-28 15:43:09 -05:00
Class . new ( Post ) do
belongs_to " author "
end
end
end
2007-10-27 16:31:09 -04:00
end
2011-11-15 01:57:15 -05:00
2020-08-06 16:47:32 -04:00
class PreloaderTest < ActiveRecord :: TestCase
2021-03-16 14:54:19 -04:00
fixtures :posts , :comments , :books , :authors , :tags , :taggings
2020-08-06 16:47:32 -04:00
def test_preload_with_scope
post = posts ( :welcome )
2020-12-04 11:15:12 -05:00
preloader = ActiveRecord :: Associations :: Preloader . new ( records : [ post ] , associations : :comments , scope : Comment . where ( body : " Thank you for the welcome " ) )
preloader . call
assert_predicate post . comments , :loaded?
assert_equal [ comments ( :greetings ) ] , post . comments
end
def test_legacy_preload_with_scope
post = posts ( :welcome )
assert_deprecated do
preloader = ActiveRecord :: Associations :: Preloader . new
preloader . preload ( [ post ] , :comments , Comment . where ( body : " Thank you for the welcome " ) )
end
2020-08-06 16:47:32 -04:00
assert_predicate post . comments , :loaded?
assert_equal [ comments ( :greetings ) ] , post . comments
end
2021-01-19 16:04:52 -05:00
def test_preload_makes_correct_number_of_queries_on_array
post = posts ( :welcome )
assert_queries ( 1 ) do
preloader = ActiveRecord :: Associations :: Preloader . new ( records : [ post ] , associations : :comments )
preloader . call
end
end
def test_preload_makes_correct_number_of_queries_on_relation
post = posts ( :welcome )
relation = Post . where ( id : post . id )
assert_queries ( 2 ) do
preloader = ActiveRecord :: Associations :: Preloader . new ( records : relation , associations : :comments )
preloader . call
end
end
2021-01-20 15:27:11 -05:00
def test_preload_groups_queries_with_same_scope
book = books ( :awdr )
post = posts ( :welcome )
assert_queries ( 1 ) do
preloader = ActiveRecord :: Associations :: Preloader . new ( records : [ book , post ] , associations : :author )
preloader . call
2021-02-19 04:57:45 -05:00
end
2021-01-20 15:27:11 -05:00
2021-02-19 04:57:45 -05:00
assert_no_queries do
2021-01-20 15:27:11 -05:00
book . author
post . author
end
end
2021-02-22 14:51:49 -05:00
def test_preload_grouped_queries_of_middle_records
comments = [
comments ( :eager_sti_on_associations_s_comment1 ) ,
comments ( :eager_sti_on_associations_s_comment2 ) ,
]
assert_queries ( 2 ) do
ActiveRecord :: Associations :: Preloader . new ( records : comments , associations : [ :author , :ordinary_post ] ) . call
end
end
def test_preload_grouped_queries_of_through_records
author = authors ( :david )
assert_queries ( 3 ) do
ActiveRecord :: Associations :: Preloader . new ( records : [ author ] , associations : [ :hello_post_comments , :comments ] ) . call
end
end
2021-03-05 08:22:08 -05:00
def test_some_already_loaded_associations
item_discount = Discount . create ( amount : 5 )
shipping_discount = Discount . create ( amount : 20 )
invoice = Invoice . new
line_item = LineItem . new ( amount : 20 )
line_item . discount_applications << LineItemDiscountApplication . new ( discount : item_discount )
invoice . line_items << line_item
shipping_line = ShippingLine . new ( amount : 50 )
shipping_line . discount_applications << ShippingLineDiscountApplication . new ( discount : shipping_discount )
invoice . shipping_lines << shipping_line
invoice . save!
invoice . reload
# SELECT "line_items".* FROM "line_items" WHERE "line_items"."invoice_id" = ?
# SELECT "shipping_lines".* FROM shipping_lines WHERE "shipping_lines"."invoice_id" = ?
# SELECT "line_item_discount_applications".* FROM "line_item_discount_applications" WHERE "line_item_discount_applications"."line_item_id" = ?
# SELECT "shipping_line_discount_applications".* FROM "shipping_line_discount_applications" WHERE "shipping_line_discount_applications"."shipping_line_id" = ?
# SELECT "discounts".* FROM "discounts" WHERE "discounts"."id" IN (?, ?).
assert_queries ( 5 ) do
preloader = ActiveRecord :: Associations :: Preloader . new ( records : [ invoice ] , associations : [
line_items : { discount_applications : :discount } ,
shipping_lines : { discount_applications : :discount } ,
] )
preloader . call
end
assert_no_queries do
assert_not_nil invoice . line_items . first . discount_applications . first . discount
assert_not_nil invoice . shipping_lines . first . discount_applications . first . discount
end
invoice . reload
invoice . line_items . map { | i | i . discount_applications . to_a }
# `line_items` and `line_item_discount_applications` are already preloaded, so we expect:
# SELECT "shipping_lines".* FROM shipping_lines WHERE "shipping_lines"."invoice_id" = ?
# SELECT "shipping_line_discount_applications".* FROM "shipping_line_discount_applications" WHERE "shipping_line_discount_applications"."shipping_line_id" = ?
# SELECT "discounts".* FROM "discounts" WHERE "discounts"."id" = ?.
assert_queries ( 3 ) do
preloader = ActiveRecord :: Associations :: Preloader . new ( records : [ invoice ] , associations : [
line_items : { discount_applications : :discount } ,
shipping_lines : { discount_applications : :discount } ,
] )
preloader . call
end
assert_no_queries do
assert_not_nil invoice . line_items . first . discount_applications . first . discount
assert_not_nil invoice . shipping_lines . first . discount_applications . first . discount
end
end
2021-02-19 04:57:45 -05:00
def test_preload_through
comments = [
comments ( :eager_sti_on_associations_s_comment1 ) ,
comments ( :eager_sti_on_associations_s_comment2 ) ,
]
assert_queries ( 2 ) do
preloader = ActiveRecord :: Associations :: Preloader . new ( records : comments , associations : [ :author , :post ] )
preloader . call
end
assert_no_queries do
comments . each ( & :author )
end
end
2021-02-19 15:20:14 -05:00
def test_preload_groups_queries_with_same_scope_at_second_level
author = nil
# Expected
# SELECT FROM authors ...
# SELECT FROM posts ... (thinking)
# SELECT FROM posts ... (welcome)
# SELECT FROM comments ... (comments for both welcome and thinking)
assert_queries ( 4 ) do
author = Author
. where ( name : " David " )
. includes ( thinking_posts : :comments , welcome_posts : :comments )
. first
end
assert_no_queries do
author . thinking_posts . map ( & :comments )
author . welcome_posts . map ( & :comments )
end
end
2021-03-22 17:51:18 -04:00
def test_preload_groups_queries_with_same_sql_at_second_level
author = nil
# Expected
# SELECT FROM authors ...
# SELECT FROM posts ... (thinking)
# SELECT FROM posts ... (welcome)
# SELECT FROM comments ... (comments for both welcome and thinking)
assert_queries ( 4 ) do
author = Author
. where ( name : " David " )
. includes ( thinking_posts : :comments , welcome_posts : :comments_with_extending )
. first
end
assert_no_queries do
author . thinking_posts . map ( & :comments )
author . welcome_posts . map ( & :comments_with_extending )
end
end
2021-01-20 15:27:11 -05:00
def test_preload_with_grouping_sets_inverse_association
mary = authors ( :mary )
bob = authors ( :bob )
AuthorFavorite . create! ( author : mary , favorite_author : bob )
favorites = AuthorFavorite . all . load
assert_queries ( 1 ) do
preloader = ActiveRecord :: Associations :: Preloader . new ( records : favorites , associations : [ :author , :favorite_author ] )
preloader . call
2021-02-19 04:57:45 -05:00
end
2021-01-20 15:27:11 -05:00
2021-02-19 04:57:45 -05:00
assert_no_queries do
2021-01-20 15:27:11 -05:00
favorites . first . author
favorites . first . favorite_author
end
end
2021-03-16 14:54:19 -04:00
def test_preload_can_group_separate_levels
mary = authors ( :mary )
bob = authors ( :bob )
AuthorFavorite . create! ( author : mary , favorite_author : bob )
assert_queries ( 3 ) do
preloader = ActiveRecord :: Associations :: Preloader . new ( records : [ mary ] , associations : [ :posts , favorite_authors : :posts ] )
preloader . call
end
assert_no_queries do
mary . posts
mary . favorite_authors . map ( & :posts )
end
end
def test_preload_can_group_multi_level_ping_pong_through
mary = authors ( :mary )
bob = authors ( :bob )
AuthorFavorite . create! ( author : mary , favorite_author : bob )
assert_queries ( 9 ) do
preloader = ActiveRecord :: Associations :: Preloader . new ( records : [ mary ] , associations : { similar_posts : :comments , favorite_authors : { similar_posts : :comments } } )
preloader . call
end
assert_no_queries do
mary . similar_posts . map ( & :comments ) . each ( & :to_a )
mary . favorite_authors . flat_map ( & :similar_posts ) . map ( & :comments ) . each ( & :to_a )
end
end
2021-01-20 15:27:11 -05:00
def test_preload_does_not_group_same_class_different_scope
post = posts ( :welcome )
postesque = Postesque . create ( author : Author . last )
postesque . reload
# When the scopes differ in the generated SQL:
# SELECT "authors".* FROM "authors" WHERE (name LIKE '%a%') AND "authors"."id" = ?
# SELECT "authors".* FROM "authors" WHERE "authors"."id" = ?.
assert_queries ( 2 ) do
preloader = ActiveRecord :: Associations :: Preloader . new ( records : [ post , postesque ] , associations : :author_with_the_letter_a )
preloader . call
2021-02-19 04:57:45 -05:00
end
2021-01-20 15:27:11 -05:00
2021-02-19 04:57:45 -05:00
assert_no_queries do
2021-01-20 15:27:11 -05:00
post . author_with_the_letter_a
postesque . author_with_the_letter_a
end
post . reload
postesque . reload
# When the generated SQL is identical, but one scope has preload values.
assert_queries ( 3 ) do
preloader = ActiveRecord :: Associations :: Preloader . new ( records : [ post , postesque ] , associations : :author_with_address )
preloader . call
2021-02-19 04:57:45 -05:00
end
2021-01-20 15:27:11 -05:00
2021-02-19 04:57:45 -05:00
assert_no_queries do
2021-01-20 15:27:11 -05:00
post . author_with_address
postesque . author_with_address
end
end
def test_preload_does_not_group_same_scope_different_key_name
post = posts ( :welcome )
postesque = Postesque . create ( author : Author . last )
postesque . reload
assert_queries ( 2 ) do
preloader = ActiveRecord :: Associations :: Preloader . new ( records : [ post , postesque ] , associations : :author )
preloader . call
2021-02-19 04:57:45 -05:00
end
2021-01-20 15:27:11 -05:00
2021-02-19 04:57:45 -05:00
assert_no_queries do
2021-01-20 15:27:11 -05:00
post . author
postesque . author
end
end
2020-08-06 16:47:32 -04:00
end
2011-11-15 01:57:15 -05:00
class GeneratedMethodsTest < ActiveRecord :: TestCase
2011-11-16 02:30:25 -05:00
fixtures :developers , :computers , :posts , :comments
2020-08-06 16:47:32 -04:00
2011-11-15 01:57:15 -05:00
def test_association_methods_override_attribute_methods_of_same_name
assert_equal ( developers ( :david ) , computers ( :workstation ) . developer )
# this next line will fail if the attribute methods module is generated lazily
# after the association methods module is generated
assert_equal ( developers ( :david ) , computers ( :workstation ) . developer )
assert_equal ( developers ( :david ) . id , computers ( :workstation ) [ :developer ] )
end
2011-11-16 02:30:25 -05:00
def test_model_method_overrides_association_method
assert_equal ( comments ( :greetings ) . body , posts ( :welcome ) . first_comment )
end
2014-09-09 03:44:48 -04:00
module MyModule
def comments ; :none end
end
class MyArticle < ActiveRecord :: Base
self . table_name = " articles "
include MyModule
has_many :comments , inverse_of : false
end
def test_included_module_overwrites_association_methods
assert_equal :none , MyArticle . new . comments
end
2011-11-16 02:30:25 -05:00
end
2019-03-14 15:57:14 -04:00
class WithAnnotationsTest < ActiveRecord :: TestCase
fixtures :pirates , :parrots
def test_belongs_to_with_annotation_includes_a_query_comment
pirate = SpacePirate . where . not ( parrot_id : nil ) . first
assert pirate , " should have a Pirate record "
log = capture_sql do
pirate . parrot
end
assert_not_predicate log , :empty?
assert_predicate log . select { | query | query . match? ( %r{ / \ * } ) } , :empty?
assert_sql ( %r{ / \ * that tells jokes \ */ } ) do
pirate . parrot_with_annotation
end
end
def test_has_and_belongs_to_many_with_annotation_includes_a_query_comment
pirate = SpacePirate . first
assert pirate , " should have a Pirate record "
log = capture_sql do
pirate . parrots . first
end
assert_not_predicate log , :empty?
assert_predicate log . select { | query | query . match? ( %r{ / \ * } ) } , :empty?
assert_sql ( %r{ / \ * that are very colorful \ */ } ) do
pirate . parrots_with_annotation . first
end
end
def test_has_one_with_annotation_includes_a_query_comment
pirate = SpacePirate . first
assert pirate , " should have a Pirate record "
log = capture_sql do
pirate . ship
end
assert_not_predicate log , :empty?
assert_predicate log . select { | query | query . match? ( %r{ / \ * } ) } , :empty?
assert_sql ( %r{ / \ * that is a rocket \ */ } ) do
pirate . ship_with_annotation
end
end
def test_has_many_with_annotation_includes_a_query_comment
pirate = SpacePirate . first
assert pirate , " should have a Pirate record "
log = capture_sql do
pirate . birds . first
end
assert_not_predicate log , :empty?
assert_predicate log . select { | query | query . match? ( %r{ / \ * } ) } , :empty?
assert_sql ( %r{ / \ * that are also parrots \ */ } ) do
pirate . birds_with_annotation . first
end
end
def test_has_many_through_with_annotation_includes_a_query_comment
pirate = SpacePirate . first
assert pirate , " should have a Pirate record "
log = capture_sql do
pirate . treasure_estimates . first
end
assert_not_predicate log , :empty?
assert_predicate log . select { | query | query . match? ( %r{ / \ * } ) } , :empty?
assert_sql ( %r{ / \ * yarrr \ */ } ) do
pirate . treasure_estimates_with_annotation . first
end
end
def test_has_many_through_with_annotation_includes_a_query_comment_when_eager_loading
pirate = SpacePirate . first
assert pirate , " should have a Pirate record "
log = capture_sql do
pirate . treasure_estimates . first
end
assert_not_predicate log , :empty?
assert_predicate log . select { | query | query . match? ( %r{ / \ * } ) } , :empty?
assert_sql ( %r{ / \ * yarrr \ */ } ) do
SpacePirate . includes ( :treasure_estimates_with_annotation , :treasures ) . first
end
end
end