aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases/modules_test.rb
blob: 87455e4fcb3840f9f7437505bea29f2e85cd87eb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# frozen_string_literal: true

require "cases/helper"
require "models/company_in_module"
require "models/shop"
require "models/developer"
require "models/computer"

class ModulesTest < ActiveRecord::TestCase
  fixtures :accounts, :companies, :projects, :developers, :collections, :products, :variants

  def setup
    # need to make sure Object::Firm and Object::Client are not defined,
    # so that constantize will not be able to cheat when having to load namespaced classes
    @undefined_consts = {}

    [:Firm, :Client].each do |const|
      @undefined_consts.merge! const => Object.send(:remove_const, const) if Object.const_defined?(const)
    end

    ActiveRecord::Base.store_full_sti_class = false
  end

  teardown do
    # reinstate the constants that we undefined in the setup
    @undefined_consts.each do |constant, value|
      Object.send :const_set, constant, value unless value.nil?
    end

    ActiveRecord::Base.store_full_sti_class = true
  end

  def test_module_spanning_associations
    firm = MyApplication::Business::Firm.first
    assert_not firm.clients.empty?, "Firm should have clients"
    assert_nil firm.class.table_name.match("::"), "Firm shouldn't have the module appear in its table name"
  end

  def test_module_spanning_has_and_belongs_to_many_associations
    project = MyApplication::Business::Project.first
    project.developers << MyApplication::Business::Developer.create("name" => "John")
    assert_equal "John", project.developers.last.name
  end

  def test_associations_spanning_cross_modules
    account = MyApplication::Billing::Account.all.merge!(order: "id").first
    assert_kind_of MyApplication::Business::Firm, account.firm
    assert_kind_of MyApplication::Billing::Firm, account.qualified_billing_firm
    assert_kind_of MyApplication::Billing::Firm, account.unqualified_billing_firm
    assert_kind_of MyApplication::Billing::Nested::Firm, account.nested_qualified_billing_firm
    assert_kind_of MyApplication::Billing::Nested::Firm, account.nested_unqualified_billing_firm
  end

  def test_find_account_and_include_company
    account = MyApplication::Billing::Account.all.merge!(includes: :firm).find(1)
    assert_kind_of MyApplication::Business::Firm, account.firm
  end

  def test_table_name
    assert_equal "accounts", MyApplication::Billing::Account.table_name, "table_name for ActiveRecord model in module"
    assert_equal "companies", MyApplication::Business::Client.table_name, "table_name for ActiveRecord model subclass"
    assert_equal "company_contacts", MyApplication::Business::Client::Contact.table_name, "table_name for ActiveRecord model enclosed by another ActiveRecord model"
  end

  def test_assign_ids
    firm = MyApplication::Business::Firm.first

    assert_nothing_raised do
      firm.client_ids = [MyApplication::Business::Client.first.id]
    end
  end

  # An eager loading condition to force the eager loading model into the old join model.
  def test_eager_loading_in_modules
    clients = []

    assert_nothing_raised do
      clients << MyApplication::Business::Client.references(:accounts).merge!(includes: { firm: :account }, where: "accounts.id IS NOT NULL").find(3)
      clients << MyApplication::Business::Client.includes(firm: :account).find(3)
    end

    clients.each do |client|
      assert_no_queries do
        assert_not_nil(client.firm.account)
      end
    end
  end

  def test_module_table_name_prefix
    assert_equal "prefixed_companies", MyApplication::Business::Prefixed::Company.table_name, "inferred table_name for ActiveRecord model in module with table_name_prefix"
    assert_equal "prefixed_companies", MyApplication::Business::Prefixed::Nested::Company.table_name, "table_name for ActiveRecord model in nested module with a parent table_name_prefix"
    assert_equal "companies", MyApplication::Business::Prefixed::Firm.table_name, "explicit table_name for ActiveRecord model in module with table_name_prefix should not be prefixed"
  end

  def test_module_table_name_prefix_with_global_prefix
    classes = [ MyApplication::Business::Company,
                MyApplication::Business::Firm,
                MyApplication::Business::Client,
                MyApplication::Business::Client::Contact,
                MyApplication::Business::Developer,
                MyApplication::Business::Project,
                MyApplication::Business::Prefixed::Company,
                MyApplication::Business::Prefixed::Nested::Company,
                MyApplication::Billing::Account ]

    ActiveRecord::Base.table_name_prefix = "global_"
    classes.each(&:reset_table_name)
    assert_equal "global_companies", MyApplication::Business::Company.table_name, "inferred table_name for ActiveRecord model in module without table_name_prefix"
    assert_equal "prefixed_companies", MyApplication::Business::Prefixed::Company.table_name, "inferred table_name for ActiveRecord model in module with table_name_prefix"
    assert_equal "prefixed_companies", MyApplication::Business::Prefixed::Nested::Company.table_name, "table_name for ActiveRecord model in nested module with a parent table_name_prefix"
    assert_equal "companies", MyApplication::Business::Prefixed::Firm.table_name, "explicit table_name for ActiveRecord model in module with table_name_prefix should not be prefixed"
  ensure
    ActiveRecord::Base.table_name_prefix = ""
    classes.each(&:reset_table_name)
  end

  def test_module_table_name_suffix
    assert_equal "companies_suffixed", MyApplication::Business::Suffixed::Company.table_name, "inferred table_name for ActiveRecord model in module with table_name_suffix"
    assert_equal "companies_suffixed", MyApplication::Business::Suffixed::Nested::Company.table_name, "table_name for ActiveRecord model in nested module with a parent table_name_suffix"
    assert_equal "companies", MyApplication::Business::Suffixed::Firm.table_name, "explicit table_name for ActiveRecord model in module with table_name_suffix should not be suffixed"
  end

  def test_module_table_name_suffix_with_global_suffix
    classes = [ MyApplication::Business::Company,
                MyApplication::Business::Firm,
                MyApplication::Business::Client,
                MyApplication::Business::Client::Contact,
                MyApplication::Business::Developer,
                MyApplication::Business::Project,
                MyApplication::Business::Suffixed::Company,
                MyApplication::Business::Suffixed::Nested::Company,
                MyApplication::Billing::Account ]

    ActiveRecord::Base.table_name_suffix = "_global"
    classes.each(&:reset_table_name)
    assert_equal "companies_global", MyApplication::Business::Company.table_name, "inferred table_name for ActiveRecord model in module without table_name_suffix"
    assert_equal "companies_suffixed", MyApplication::Business::Suffixed::Company.table_name, "inferred table_name for ActiveRecord model in module with table_name_suffix"
    assert_equal "companies_suffixed", MyApplication::Business::Suffixed::Nested::Company.table_name, "table_name for ActiveRecord model in nested module with a parent table_name_suffix"
    assert_equal "companies", MyApplication::Business::Suffixed::Firm.table_name, "explicit table_name for ActiveRecord model in module with table_name_suffix should not be suffixed"
  ensure
    ActiveRecord::Base.table_name_suffix = ""
    classes.each(&:reset_table_name)
  end

  def test_compute_type_can_infer_class_name_of_sibling_inside_module
    old = ActiveRecord::Base.store_full_sti_class
    ActiveRecord::Base.store_full_sti_class = true
    assert_equal MyApplication::Business::Firm, MyApplication::Business::Client.send(:compute_type, "Firm")
  ensure
    ActiveRecord::Base.store_full_sti_class = old
  end

  def test_nested_models_should_not_raise_exception_when_using_delete_all_dependency_on_association
    old = ActiveRecord::Base.store_full_sti_class
    ActiveRecord::Base.store_full_sti_class = true

    collection = Shop::Collection.first
    assert_not collection.products.empty?, "Collection should have products"
    assert_nothing_raised { collection.destroy }
  ensure
    ActiveRecord::Base.store_full_sti_class = old
  end

  def test_nested_models_should_not_raise_exception_when_using_nullify_dependency_on_association
    old = ActiveRecord::Base.store_full_sti_class
    ActiveRecord::Base.store_full_sti_class = true

    product = Shop::Product.first
    assert_not product.variants.empty?, "Product should have variants"
    assert_nothing_raised { product.destroy }
  ensure
    ActiveRecord::Base.store_full_sti_class = old
  end
end