relations_test.rb 63.5 KB
Newer Older
1 2
# frozen_string_literal: true

3
require "cases/helper"
4 5 6 7 8 9 10 11
require "models/tag"
require "models/tagging"
require "models/post"
require "models/topic"
require "models/comment"
require "models/author"
require "models/entrant"
require "models/developer"
D
Darwin D Wu 已提交
12
require "models/project"
13
require "models/person"
14 15 16
require "models/computer"
require "models/reply"
require "models/company"
17
require "models/contract"
18 19 20 21 22
require "models/bird"
require "models/car"
require "models/engine"
require "models/tyre"
require "models/minivan"
23
require "models/possession"
24
require "models/reader"
25
require "models/category"
26
require "models/categorization"
27
require "models/edge"
28
require "models/subscriber"
29

E
Emilio Tagua 已提交
30
class RelationTest < ActiveRecord::TestCase
31
  fixtures :authors, :author_addresses, :topics, :entrants, :developers, :people, :companies, :developers_projects, :accounts, :categories, :categorizations, :categories_posts, :posts, :comments, :tags, :taggings, :cars, :minivans
32 33 34 35

  def test_do_not_double_quote_string_id
    van = Minivan.last
    assert van
36
    assert_equal van.id, Minivan.where(minivan_id: van).to_a.first.minivan_id
37
  end
38

39 40 41
  def test_do_not_double_quote_string_id_with_array
    van = Minivan.last
    assert van
42
    assert_equal van, Minivan.where(minivan_id: [van]).to_a.first
43 44
  end

45
  def test_two_scopes_with_includes_should_not_drop_any_include
46 47 48 49 50
    # heat habtm cache
    car = Car.incl_engines.incl_tyres.first
    car.tyres.length
    car.engines.length

51
    car = Car.incl_engines.incl_tyres.first
52 53
    assert_no_queries { car.tyres.length }
    assert_no_queries { car.engines.length }
54
  end
55

56
  def test_dynamic_finder
57
    x = Post.where("author_id = ?", 1)
D
Daniel Colson 已提交
58
    assert_respond_to x.klass, :find_by_id
59 60
  end

61
  def test_multivalue_where
62
    posts = Post.where("author_id = ? AND id = ?", 1, 1)
63 64 65
    assert_equal 1, posts.to_a.size
  end

66
  def test_scoped
67
    topics = Topic.all
68
    assert_kind_of ActiveRecord::Relation, topics
69
    assert_equal 5, topics.size
70 71
  end

72
  def test_to_json
73 74
    assert_nothing_raised  { Bird.all.to_json }
    assert_nothing_raised  { Bird.all.to_a.to_json }
75 76 77
  end

  def test_to_yaml
78 79
    assert_nothing_raised  { Bird.all.to_yaml }
    assert_nothing_raised  { Bird.all.to_a.to_yaml }
80 81
  end

82
  def test_to_xml
83 84
    assert_nothing_raised  { Bird.all.to_xml }
    assert_nothing_raised  { Bird.all.to_a.to_xml }
85 86
  end

87
  def test_scoped_all
88
    topics = Topic.all.to_a
89
    assert_kind_of Array, topics
90
    assert_no_queries { assert_equal 5, topics.size }
91 92
  end

P
Pratik Naik 已提交
93
  def test_loaded_all
94
    topics = Topic.all
P
Pratik Naik 已提交
95 96

    assert_queries(1) do
97
      2.times { assert_equal 5, topics.to_a.size }
P
Pratik Naik 已提交
98 99
    end

100
    assert_predicate topics, :loaded?
P
Pratik Naik 已提交
101 102 103
  end

  def test_scoped_first
104
    topics = Topic.all.order("id ASC")
P
Pratik Naik 已提交
105 106 107 108 109

    assert_queries(1) do
      2.times { assert_equal "The First Topic", topics.first.title }
    end

D
Daniel Colson 已提交
110
    assert_not_predicate topics, :loaded?
P
Pratik Naik 已提交
111 112 113
  end

  def test_loaded_first
114
    topics = Topic.all.order("id ASC")
115
    topics.load # force load
P
Pratik Naik 已提交
116

117 118 119 120
    assert_no_queries do
      assert_equal "The First Topic", topics.first.title
    end

121
    assert_predicate topics, :loaded?
122 123 124
  end

  def test_loaded_first_with_limit
125
    topics = Topic.all.order("id ASC")
126
    topics.load # force load
127 128

    assert_no_queries do
129 130
      assert_equal ["The First Topic",
                    "The Second Topic of the day"], topics.first(2).map(&:title)
P
Pratik Naik 已提交
131 132
    end

133
    assert_predicate topics, :loaded?
P
Pratik Naik 已提交
134 135
  end

136
  def test_first_get_more_than_available
137
    topics = Topic.all.order("id ASC")
138
    unloaded_first = topics.first(10)
139
    topics.load # force load
140 141 142 143 144 145 146

    assert_no_queries do
      loaded_first = topics.first(10)
      assert_equal unloaded_first, loaded_first
    end
  end

147
  def test_reload
148
    topics = Topic.all
149 150 151 152 153

    assert_queries(1) do
      2.times { topics.to_a }
    end

154
    assert_predicate topics, :loaded?
155

156
    original_size = topics.to_a.size
157
    Topic.create! title: "fake"
158

159 160
    assert_queries(1) { topics.reload }
    assert_equal original_size + 1, topics.size
161
    assert_predicate topics, :loaded?
162 163
  end

I
Ivan Kukobko 已提交
164
  def test_finding_with_subquery
165
    relation = Topic.where(approved: true)
166 167 168
    assert_equal relation.to_a, Topic.select("*").from(relation).to_a
    assert_equal relation.to_a, Topic.select("subquery.*").from(relation).to_a
    assert_equal relation.to_a, Topic.select("a.*").from(relation, :a).to_a
169 170
  end

171 172
  def test_finding_with_subquery_with_binds
    relation = Post.first.comments
173 174 175
    assert_equal relation.to_a, Comment.select("*").from(relation).to_a
    assert_equal relation.to_a, Comment.select("subquery.*").from(relation).to_a
    assert_equal relation.to_a, Comment.select("a.*").from(relation, :a).to_a
176 177
  end

178 179 180 181 182
  def test_finding_with_subquery_without_select_does_not_change_the_select
    relation = Topic.where(approved: true)
    assert_raises(ActiveRecord::StatementInvalid) do
      Topic.from(relation).to_a
    end
C
Cody Cutrer 已提交
183 184
  end

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
  def test_select_with_original_table_name_in_from
    relation = Comment.joins(:post).select(:id).order(:id)
    subquery = Comment.from(Comment.table_name).joins(:post).select(:id).order(:id)
    assert_equal relation.map(&:id), subquery.map(&:id)
  end

  def test_pluck_with_original_table_name_in_from
    relation = Comment.joins(:post).order(:id)
    subquery = Comment.from(Comment.table_name).joins(:post).order(:id)
    assert_equal relation.pluck(:id), subquery.pluck(:id)
  end

  def test_select_with_quoted_original_table_name_in_from
    relation = Comment.joins(:post).select(:id).order(:id)
    subquery = Comment.from(Comment.quoted_table_name).joins(:post).select(:id).order(:id)
    assert_equal relation.map(&:id), subquery.map(&:id)
  end

  def test_pluck_with_quoted_original_table_name_in_from
    relation = Comment.joins(:post).order(:id)
    subquery = Comment.from(Comment.quoted_table_name).joins(:post).order(:id)
    assert_equal relation.pluck(:id), subquery.pluck(:id)
  end

  def test_select_with_subquery_in_from_uses_original_table_name
210 211 212
    if current_adapter?(:SQLite3Adapter) && ENV["TRAVIS"]
      skip "https://travis-ci.org/rails/rails/jobs/496726410#L1198-L1208"
    end
213 214 215 216 217 218 219 220 221 222 223
    relation = Comment.joins(:post).select(:id).order(:id)
    subquery = Comment.from(Comment.all, Comment.quoted_table_name).joins(:post).select(:id).order(:id)
    assert_equal relation.map(&:id), subquery.map(&:id)
  end

  def test_pluck_with_subquery_in_from_uses_original_table_name
    relation = Comment.joins(:post).order(:id)
    subquery = Comment.from(Comment.all, Comment.quoted_table_name).joins(:post).order(:id)
    assert_equal relation.pluck(:id), subquery.pluck(:id)
  end

224
  def test_select_with_subquery_in_from_does_not_use_original_table_name
225
    relation = Comment.group(:type).select("COUNT(post_id) AS post_count, type")
226 227
    subquery = Comment.from(relation).select("type", "post_count")
    assert_equal(relation.map(&:post_count).sort, subquery.map(&:post_count).sort)
228 229 230
  end

  def test_group_with_subquery_in_from_does_not_use_original_table_name
231 232
    relation = Comment.group(:type).select("COUNT(post_id) AS post_count,type")
    subquery = Comment.from(relation).group("type").average("post_count")
233
    assert_equal(relation.map(&:post_count).sort, subquery.values.sort)
234
  end
235

236 237 238 239 240 241 242 243 244
  def test_finding_with_subquery_with_eager_loading_in_from
    relation = Comment.includes(:post).where("posts.type": "Post")
    assert_equal relation.to_a, Comment.select("*").from(relation).to_a
    assert_equal relation.to_a, Comment.select("subquery.*").from(relation).to_a
    assert_equal relation.to_a, Comment.select("a.*").from(relation, :a).to_a
  end

  def test_finding_with_subquery_with_eager_loading_in_where
    relation = Comment.includes(:post).where("posts.type": "Post")
245
    assert_equal relation.sort_by(&:id), Comment.where(id: relation).sort_by(&:id)
246 247
  end

248
  def test_finding_with_conditions
249
    assert_equal ["David"], Author.where(name: "David").map(&:name)
250 251
    assert_equal ["Mary"],  Author.where(["name = ?", "Mary"]).map(&:name)
    assert_equal ["Mary"],  Author.where("name = ?", "Mary").map(&:name)
252 253 254
  end

  def test_finding_with_order
255
    topics = Topic.order("id")
256
    assert_equal 5, topics.to_a.size
257 258 259
    assert_equal topics(:first).title, topics.first.title
  end

260 261
  def test_finding_with_arel_order
    topics = Topic.order(Topic.arel_table[:id].asc)
262
    assert_equal 5, topics.to_a.size
263 264
    assert_equal topics(:first).title, topics.first.title
  end
265

266
  def test_finding_with_assoc_order
267
    topics = Topic.order(id: :desc)
268 269
    assert_equal 5, topics.to_a.size
    assert_equal topics(:fifth).title, topics.first.title
270
  end
271

272 273 274 275 276 277 278
  def test_finding_with_arel_assoc_order
    topics = Topic.order(Arel.sql("id") => :desc)
    assert_equal 5, topics.to_a.size
    assert_equal topics(:fifth).title, topics.first.title
  end

  def test_finding_with_reversed_assoc_order
279
    topics = Topic.order(id: :asc).reverse_order
280 281
    assert_equal 5, topics.to_a.size
    assert_equal topics(:fifth).title, topics.first.title
282
  end
283

284 285 286 287 288 289
  def test_finding_with_reversed_arel_assoc_order
    topics = Topic.order(Arel.sql("id") => :asc).reverse_order
    assert_equal 5, topics.to_a.size
    assert_equal topics(:fifth).title, topics.first.title
  end

290
  def test_reverse_order_with_function
291
    topics = Topic.order(Arel.sql("length(title)")).reverse_order
292 293 294
    assert_equal topics(:second).title, topics.first.title
  end

295 296 297 298 299
  def test_reverse_arel_assoc_order_with_function
    topics = Topic.order(Arel.sql("length(title)") => :asc).reverse_order
    assert_equal topics(:second).title, topics.first.title
  end

300
  def test_reverse_order_with_function_other_predicates
301
    topics = Topic.order(Arel.sql("author_name, length(title), id")).reverse_order
302
    assert_equal topics(:second).title, topics.first.title
303
    topics = Topic.order(Arel.sql("length(author_name), id, length(title)")).reverse_order
304 305 306 307 308
    assert_equal topics(:fifth).title, topics.first.title
  end

  def test_reverse_order_with_multiargument_function
    assert_raises(ActiveRecord::IrreversibleOrderError) do
309
      Topic.order(Arel.sql("concat(author_name, title)")).reverse_order
310
    end
311
    assert_raises(ActiveRecord::IrreversibleOrderError) do
312
      Topic.order(Arel.sql("concat(lower(author_name), title)")).reverse_order
313 314
    end
    assert_raises(ActiveRecord::IrreversibleOrderError) do
315
      Topic.order(Arel.sql("concat(author_name, lower(title))")).reverse_order
316 317
    end
    assert_raises(ActiveRecord::IrreversibleOrderError) do
318
      Topic.order(Arel.sql("concat(lower(author_name), title, length(title)")).reverse_order
319
    end
320 321
  end

322 323 324 325 326 327
  def test_reverse_arel_assoc_order_with_multiargument_function
    assert_nothing_raised do
      Topic.order(Arel.sql("REPLACE(title, '', '')") => :asc).reverse_order
    end
  end

328 329
  def test_reverse_order_with_nulls_first_or_last
    assert_raises(ActiveRecord::IrreversibleOrderError) do
330
      Topic.order(Arel.sql("title NULLS FIRST")).reverse_order
331
    end
332 333 334
    assert_raises(ActiveRecord::IrreversibleOrderError) do
      Topic.order(Arel.sql("title  NULLS  FIRST")).reverse_order
    end
335
    assert_raises(ActiveRecord::IrreversibleOrderError) do
336
      Topic.order(Arel.sql("title nulls last")).reverse_order
337
    end
338 339 340 341 342 343
    assert_raises(ActiveRecord::IrreversibleOrderError) do
      Topic.order(Arel.sql("title NULLS FIRST, author_name")).reverse_order
    end
    assert_raises(ActiveRecord::IrreversibleOrderError) do
      Topic.order(Arel.sql("author_name, title nulls last")).reverse_order
    end
344 345 346 347 348 349 350 351
  end

  def test_default_reverse_order_on_table_without_primary_key
    assert_raises(ActiveRecord::IrreversibleOrderError) do
      Edge.all.reverse_order
    end
  end

Y
Yves Senn 已提交
352
  def test_order_with_hash_and_symbol_generates_the_same_sql
353
    assert_equal Topic.order(:id).to_sql, Topic.order(id: :asc).to_sql
Y
Yves Senn 已提交
354 355
  end

356 357 358 359 360 361 362
  def test_finding_with_desc_order_with_string
    topics = Topic.order(id: "desc")
    assert_equal 5, topics.to_a.size
    assert_equal [topics(:fifth), topics(:fourth), topics(:third), topics(:second), topics(:first)], topics.to_a
  end

  def test_finding_with_asc_order_with_string
363
    topics = Topic.order(id: "asc")
364 365 366 367
    assert_equal 5, topics.to_a.size
    assert_equal [topics(:first), topics(:second), topics(:third), topics(:fourth), topics(:fifth)], topics.to_a
  end

368 369 370 371 372
  def test_support_upper_and_lower_case_directions
    assert_includes Topic.order(id: "ASC").to_sql, "ASC"
    assert_includes Topic.order(id: "asc").to_sql, "ASC"
    assert_includes Topic.order(id: :ASC).to_sql, "ASC"
    assert_includes Topic.order(id: :asc).to_sql, "ASC"
373

374 375 376
    assert_includes Topic.order(id: "DESC").to_sql, "DESC"
    assert_includes Topic.order(id: "desc").to_sql, "DESC"
    assert_includes Topic.order(id: :DESC).to_sql, "DESC"
377
    assert_includes Topic.order(id: :desc).to_sql, "DESC"
378 379
  end

380
  def test_raising_exception_on_invalid_hash_params
381 382
    e = assert_raise(ArgumentError) { Topic.order(:name, "id DESC", id: :asfsdf) }
    assert_equal 'Direction "asfsdf" is invalid. Valid directions are: [:asc, :desc, :ASC, :DESC, "asc", "desc", "ASC", "DESC"]', e.message
383
  end
384 385 386

  def test_finding_last_with_arel_order
    topics = Topic.order(Topic.arel_table[:id].asc)
387
    assert_equal topics(:fifth).title, topics.last.title
388 389
  end

390
  def test_finding_with_order_concatenated
391
    topics = Topic.order("author_name").order("title")
392
    assert_equal 5, topics.to_a.size
393 394 395
    assert_equal topics(:fourth).title, topics.first.title
  end

396 397 398 399 400 401 402 403 404 405 406 407
  def test_finding_with_order_by_aliased_attributes
    topics = Topic.order(:heading)
    assert_equal 5, topics.to_a.size
    assert_equal topics(:fifth).title, topics.first.title
  end

  def test_finding_with_assoc_order_by_aliased_attributes
    topics = Topic.order(heading: :desc)
    assert_equal 5, topics.to_a.size
    assert_equal topics(:third).title, topics.first.title
  end

S
Sebastian Martinez 已提交
408
  def test_finding_with_reorder
409
    topics = Topic.order("author_name").order("title").reorder("id").to_a
410
    topics_titles = topics.map(&:title)
411
    assert_equal ["The First Topic", "The Second Topic of the day", "The Third Topic of the day", "The Fourth Topic of the day", "The Fifth Topic of the day"], topics_titles
S
Sebastian Martinez 已提交
412
  end
413

414
  def test_finding_with_reorder_by_aliased_attributes
415
    topics = Topic.order("author_name").reorder(:heading)
416 417 418 419 420
    assert_equal 5, topics.to_a.size
    assert_equal topics(:fifth).title, topics.first.title
  end

  def test_finding_with_assoc_reorder_by_aliased_attributes
421
    topics = Topic.order("author_name").reorder(heading: :desc)
422 423
    assert_equal 5, topics.to_a.size
    assert_equal topics(:third).title, topics.first.title
S
Sebastian Martinez 已提交
424
  end
425

426
  def test_finding_with_order_and_take
427
    entrants = Entrant.order("id ASC").limit(2).to_a
428

P
Pratik Naik 已提交
429 430
    assert_equal 2, entrants.size
    assert_equal entrants(:first).name, entrants.first.name
431 432
  end

433
  def test_finding_with_cross_table_order_and_limit
434
    tags = Tag.includes(:taggings).
B
Ben Toews 已提交
435
              order("tags.name asc", "taggings.taggable_id asc", Arel.sql("REPLACE('abc', taggings.taggable_type, taggings.taggable_type)")).
436
              limit(1).to_a
437 438 439
    assert_equal 1, tags.length
  end

440
  def test_finding_with_complex_order_and_limit
441
    tags = Tag.includes(:taggings).references(:taggings).order(Arel.sql("REPLACE('abc', taggings.taggable_type, taggings.taggable_type)")).limit(1).to_a
442 443 444 445
    assert_equal 1, tags.length
  end

  def test_finding_with_complex_order
446
    tags = Tag.includes(:taggings).references(:taggings).order(Arel.sql("REPLACE('abc', taggings.taggable_type, taggings.taggable_type)")).to_a
447
    assert_equal 3, tags.length
448 449
  end

450
  def test_finding_with_sanitized_order
B
Ben Toews 已提交
451
    query = Tag.order([Arel.sql("field(id, ?)"), [1, 3, 2]]).to_sql
452
    assert_match(/field\(id, 1,3,2\)/, query)
453

B
Ben Toews 已提交
454
    query = Tag.order([Arel.sql("field(id, ?)"), []]).to_sql
455 456
    assert_match(/field\(id, NULL\)/, query)

B
Ben Toews 已提交
457
    query = Tag.order([Arel.sql("field(id, ?)"), nil]).to_sql
458
    assert_match(/field\(id, NULL\)/, query)
459 460
  end

461
  def test_finding_with_order_limit_and_offset
462
    entrants = Entrant.order("id ASC").limit(2).offset(1)
463

464
    assert_equal 2, entrants.to_a.size
P
Pratik Naik 已提交
465
    assert_equal entrants(:second).name, entrants.first.name
466

467
    entrants = Entrant.order("id ASC").limit(2).offset(2)
468
    assert_equal 1, entrants.to_a.size
P
Pratik Naik 已提交
469
    assert_equal entrants(:third).name, entrants.first.name
470 471 472
  end

  def test_finding_with_group
473
    developers = Developer.group("salary").select("salary").to_a
474 475 476 477
    assert_equal 4, developers.size
    assert_equal 4, developers.map(&:salary).uniq.size
  end

478
  def test_select_with_block
479
    even_ids = Developer.all.select { |d| d.id % 2 == 0 }.map(&:id)
480
    assert_equal [2, 4, 6, 8, 10], even_ids.sort
481 482
  end

483 484 485 486
  def test_joins_with_nil_argument
    assert_nothing_raised { DependentFirm.joins(nil).first }
  end

487
  def test_finding_with_hash_conditions_on_joined_table
488
    firms = DependentFirm.joins(:account).where(name: "RailsCore", accounts: { credit_limit: 55..60 }).to_a
489 490 491 492 493
    assert_equal 1, firms.size
    assert_equal companies(:rails_core), firms.first
  end

  def test_find_all_with_join
494 495
    developers_on_project_one = Developer.joins("LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id").
      where("project_id=1").to_a
496 497

    assert_equal 3, developers_on_project_one.length
498
    developer_names = developers_on_project_one.map(&:name)
499 500
    assert_includes developer_names, "David"
    assert_includes developer_names, "Jamis"
501 502 503
  end

  def test_find_on_hash_conditions
504
    assert_equal Topic.all.merge!(where: { approved: false }).to_a, Topic.where(approved: false).to_a
505 506 507
  end

  def test_joins_with_string_array
508
    person_with_reader_and_post = Post.joins([
509 510 511 512 513 514
        "INNER JOIN categorizations ON categorizations.post_id = posts.id",
        "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
      ]
    ).to_a
    assert_equal 1, person_with_reader_and_post.size
  end
515

516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
  def test_no_arguments_to_query_methods_raise_errors
    assert_raises(ArgumentError) { Topic.references() }
    assert_raises(ArgumentError) { Topic.includes() }
    assert_raises(ArgumentError) { Topic.preload() }
    assert_raises(ArgumentError) { Topic.group() }
    assert_raises(ArgumentError) { Topic.reorder() }
  end

  def test_blank_like_arguments_to_query_methods_dont_raise_errors
    assert_nothing_raised { Topic.references([]) }
    assert_nothing_raised { Topic.includes([]) }
    assert_nothing_raised { Topic.preload([]) }
    assert_nothing_raised { Topic.group([]) }
    assert_nothing_raised { Topic.reorder([]) }
  end

532
  def test_respond_to_dynamic_finders
533
    relation = Topic.all
534

535
    ["find_by_title", "find_by_title_and_author_name"].each do |method|
D
Daniel Colson 已提交
536
      assert_respond_to relation, method
537 538
    end
  end
539

540
  def test_respond_to_class_methods_and_scopes
D
Daniel Colson 已提交
541
    assert_respond_to Topic.all, :by_lifo
542 543
  end

544
  def test_find_with_readonly_option
545
    Developer.all.each { |d| assert_not d.readonly? }
546
    Developer.all.readonly.each { |d| assert d.readonly? }
547
  end
548 549

  def test_eager_association_loading_of_stis_with_multiple_references
550
    authors = Author.eager_load(posts: { special_comments: { post: [ :special_comments, :very_special_comment ] } }).
551
      order("comments.body, very_special_comments_posts.body").where("posts.id = 4").to_a
552

553 554 555 556 557 558 559
    assert_equal [authors(:david)], authors
    assert_no_queries do
      authors.first.posts.first.special_comments.first.post.special_comments
      authors.first.posts.first.special_comments.first.post.very_special_comment
    end
  end

560
  def test_find_with_preloaded_associations
561
    assert_queries(2) do
562
      posts = Post.preload(:comments).order("posts.id")
563
      assert posts.first.comments.first
564
    end
565

C
Carlos Antonio da Silva 已提交
566
    assert_queries(2) do
567
      posts = Post.preload(:comments).order("posts.id")
568
      assert posts.first.comments.first
569
    end
570

571
    assert_queries(2) do
572
      posts = Post.preload(:author).order("posts.id")
573
      assert posts.first.author
574
    end
575

C
Carlos Antonio da Silva 已提交
576
    assert_queries(2) do
577
      posts = Post.preload(:author).order("posts.id")
578 579 580
      assert posts.first.author
    end

C
Carlos Antonio da Silva 已提交
581
    assert_queries(3) do
582
      posts = Post.preload(:author, :comments).order("posts.id")
583
      assert posts.first.author
584 585 586 587
      assert posts.first.comments.first
    end
  end

588 589 590 591 592 593 594
  def test_preload_applies_to_all_chained_preloaded_scopes
    assert_queries(3) do
      post = Post.with_comments.with_tags.first
      assert post
    end
  end

595 596
  def test_find_with_included_associations
    assert_queries(2) do
597
      posts = Post.includes(:comments).order("posts.id")
598 599 600
      assert posts.first.comments.first
    end

C
Carlos Antonio da Silva 已提交
601
    assert_queries(2) do
602
      posts = Post.all.includes(:comments).order("posts.id")
603 604 605 606
      assert posts.first.comments.first
    end

    assert_queries(2) do
607
      posts = Post.includes(:author).order("posts.id")
608 609 610
      assert posts.first.author
    end

C
Carlos Antonio da Silva 已提交
611
    assert_queries(3) do
612
      posts = Post.includes(:author, :comments).order("posts.id")
613
      assert posts.first.author
614
      assert posts.first.comments.first
615 616
    end
  end
617

618
  def test_default_scoping_finder_methods
619 620
    developers = DeveloperCalledDavid.order("id").map(&:id).sort
    assert_equal Developer.where(name: "David").map(&:id).sort, developers
621 622
  end

623
  def test_includes_with_select
624
    query = Post.select("comments_count AS ranking").order("ranking").includes(:comments)
625 626
      .where(comments: { id: 1 })

627
    assert_equal ["comments_count AS ranking"], query.select_values
628 629 630
    assert_equal 1, query.to_a.size
  end

631
  def test_preloading_with_associations_and_merges
632
    post = Post.create! title: "Uhuu", body: "body"
633
    reader = Reader.create! post_id: post.id, person_id: 1
634
    comment = Comment.create! post_id: post.id, body: "body"
635

D
Daniel Colson 已提交
636
    assert_not_respond_to comment, :readers
637

638
    post_rel = Post.preload(:readers).joins(:readers).where(title: "Uhuu")
639 640 641 642 643 644 645 646
    result_comment = Comment.joins(:post).merge(post_rel).to_a.first
    assert_equal comment, result_comment

    assert_no_queries do
      assert_equal post, result_comment.post
      assert_equal [reader], result_comment.post.readers.to_a
    end

647
    post_rel = Post.includes(:readers).where(title: "Uhuu")
648 649 650 651 652 653 654 655 656
    result_comment = Comment.joins(:post).merge(post_rel).first
    assert_equal comment, result_comment

    assert_no_queries do
      assert_equal post, result_comment.post
      assert_equal [reader], result_comment.post.readers.to_a
    end
  end

657
  def test_preloading_with_associations_default_scopes_and_merges
658
    post = Post.create! title: "Uhuu", body: "body"
659 660
    reader = Reader.create! post_id: post.id, person_id: 1

661
    post_rel = PostWithPreloadDefaultScope.preload(:readers).joins(:readers).where(title: "Uhuu")
662 663 664 665 666 667
    result_post = PostWithPreloadDefaultScope.all.merge(post_rel).to_a.first

    assert_no_queries do
      assert_equal [reader], result_post.readers.to_a
    end

668
    post_rel = PostWithIncludesDefaultScope.includes(:readers).where(title: "Uhuu")
669 670 671 672 673 674 675
    result_post = PostWithIncludesDefaultScope.all.merge(post_rel).to_a.first

    assert_no_queries do
      assert_equal [reader], result_post.readers.to_a
    end
  end

676 677
  def test_loading_with_one_association
    posts = Post.preload(:comments)
678 679
    post = posts.find { |p| p.id == 1 }
    assert_equal 2, post.comments.size
680
    assert_includes post.comments, comments(:greetings)
681

682
    post = Post.where("posts.title = 'Welcome to the weblog'").preload(:comments).first
683
    assert_equal 2, post.comments.size
684
    assert_includes post.comments, comments(:greetings)
685

686
    posts = Post.preload(:last_comment)
687 688 689 690
    post = posts.find { |p| p.id == 1 }
    assert_equal Post.find(1).last_comment, post.last_comment
  end

691 692
  def test_to_sql_on_eager_join
    expected = assert_sql {
693
      Post.eager_load(:last_comment).order("comments.id DESC").to_a
694
    }.first
695
    actual = Post.eager_load(:last_comment).order("comments.id DESC").to_sql
696 697 698
    assert_equal expected, actual
  end

699 700 701 702 703 704
  def test_to_sql_on_scoped_proxy
    auth = Author.first
    Post.where("1=1").written_by(auth)
    assert_not auth.posts.to_sql.include?("1=1")
  end

705
  def test_loading_with_one_association_with_non_preload
706
    posts = Post.eager_load(:last_comment).order("comments.id DESC")
707 708 709
    post = posts.find { |p| p.id == 1 }
    assert_equal Post.find(1).last_comment, post.last_comment
  end
710 711 712 713 714 715 716

  def test_dynamic_find_by_attributes
    david = authors(:david)
    author = Author.preload(:taggings).find_by_id(david.id)
    expected_taggings = taggings(:welcome_general, :thinking_general)

    assert_no_queries do
717
      assert_equal expected_taggings, author.taggings.uniq.sort_by(&:id)
718 719
    end

720
    authors = Author.all
721 722 723 724 725
    assert_equal david, authors.find_by_id_and_name(david.id, david.name)
    assert_equal david, authors.find_by_id_and_name!(david.id, david.name)
  end

  def test_dynamic_find_by_attributes_bang
726
    author = Author.all.find_by_id!(authors(:david).id)
727 728
    assert_equal "David", author.name

729
    assert_raises(ActiveRecord::RecordNotFound) { Author.all.find_by_id_and_name!(20, "invalid") }
730 731
  end

P
Pratik Naik 已提交
732
  def test_find_id
733
    authors = Author.all
P
Pratik Naik 已提交
734 735

    david = authors.find(authors(:david).id)
736
    assert_equal "David", david.name
P
Pratik Naik 已提交
737

738
    assert_raises(ActiveRecord::RecordNotFound) { authors.where(name: "lifo").find("42") }
P
Pratik Naik 已提交
739
  end
740

P
Pratik Naik 已提交
741
  def test_find_ids
742
    authors = Author.order("id ASC")
P
Pratik Naik 已提交
743 744 745 746

    results = authors.find(authors(:david).id, authors(:mary).id)
    assert_kind_of Array, results
    assert_equal 2, results.size
747 748
    assert_equal "David", results[0].name
    assert_equal "Mary", results[1].name
P
Pratik Naik 已提交
749 750
    assert_equal results, authors.find([authors(:david).id, authors(:mary).id])

751
    assert_raises(ActiveRecord::RecordNotFound) { authors.where(name: "lifo").find(authors(:david).id, "42") }
752
    assert_raises(ActiveRecord::RecordNotFound) { authors.find(["42", 43]) }
P
Pratik Naik 已提交
753 754
  end

755
  def test_find_in_empty_array
756
    authors = Author.all.where(id: [])
757
    assert_predicate authors.to_a, :blank?
758 759
  end

760 761
  def test_where_with_ar_object
    author = Author.first
762
    authors = Author.all.where(id: author)
763
    assert_equal 1, authors.to_a.length
764 765
  end

766 767
  def test_find_with_list_of_ar
    author = Author.first
768
    authors = Author.find([author.id])
769 770 771 772 773 774 775 776 777
    assert_equal author, authors.first
  end

  def test_find_by_id_with_list_of_ar
    author = Author.first
    authors = Author.find_by_id([author])
    assert_equal author, authors
  end

778 779 780
  def test_find_all_using_where_twice_should_or_the_relation
    david = authors(:david)
    relation = Author.unscoped
781 782 783
    relation = relation.where(name: david.name)
    relation = relation.where(name: "Santiago")
    relation = relation.where(id: david.id)
784
    assert_equal [], relation.to_a
785 786
  end

A
Aaron Patterson 已提交
787 788 789
  def test_multi_where_ands_queries
    relation = Author.unscoped
    david = authors(:david)
790
    sql = relation.where(name: david.name).where(name: "Santiago").to_sql
791
    assert_match("AND", sql)
A
Aaron Patterson 已提交
792 793 794
  end

  def test_find_all_with_multiple_should_use_and
A
Aaron Patterson 已提交
795 796
    david = authors(:david)
    relation = [
797 798 799
      { name: david.name },
      { name: "Santiago" },
      { name: "tenderlove" },
A
Aaron Patterson 已提交
800 801 802
    ].inject(Author.unscoped) do |memo, param|
      memo.where(param)
    end
803
    assert_equal [], relation.to_a
A
Aaron Patterson 已提交
804
  end
A
Aaron Patterson 已提交
805

806 807 808 809 810 811 812
  def test_typecasting_where_with_array
    ids = Author.pluck(:id)
    slugs = ids.map { |id| "#{id}-as-a-slug" }

    assert_equal Author.all.to_a, Author.where(id: slugs).to_a
  end

813 814 815
  def test_find_all_using_where_with_relation
    david = authors(:david)
    assert_queries(1) {
816
      relation = Author.where(id: Author.where(id: david.id))
817
      assert_equal [david], relation.to_a
818
    }
819 820

    assert_queries(1) {
821
      relation = Author.where("id in (?)", Author.where(id: david).select(:id))
822 823
      assert_equal [david], relation.to_a
    }
824 825

    assert_queries(1) do
826
      relation = Author.where("id in (:author_ids)", author_ids: Author.where(id: david).select(:id))
827 828 829 830 831 832
      assert_equal [david], relation.to_a
    end
  end

  def test_find_all_using_where_with_relation_with_bound_values
    david = authors(:david)
833
    davids_posts = david.posts.order(:id).to_a
834 835 836

    assert_queries(1) do
      relation = Post.where(id: david.posts.select(:id))
837
      assert_equal davids_posts, relation.order(:id).to_a
838 839 840
    end

    assert_queries(1) do
841 842
      relation = Post.where("id in (?)", david.posts.select(:id))
      assert_equal davids_posts, relation.order(:id).to_a, "should process Relation as bind variables"
843 844 845
    end

    assert_queries(1) do
846 847
      relation = Post.where("id in (:post_ids)", post_ids: david.posts.select(:id))
      assert_equal davids_posts, relation.order(:id).to_a, "should process Relation as named bind variables"
848
    end
849 850
  end

851 852 853
  def test_find_all_using_where_with_relation_and_alternate_primary_key
    cool_first = minivans(:cool_first)
    assert_queries(1) {
854
      relation = Minivan.where(minivan_id: Minivan.where(name: cool_first.name))
855
      assert_equal [cool_first], relation.to_a
856 857 858
    }
  end

859 860 861
  def test_find_all_using_where_with_relation_does_not_alter_select_values
    david = authors(:david)

862
    subquery = Author.where(id: david.id)
863 864

    assert_queries(1) {
865
      relation = Author.where(id: subquery)
866
      assert_equal [david], relation.to_a
867 868 869 870 871
    }

    assert_equal 0, subquery.select_values.size
  end

872 873 874
  def test_find_all_using_where_with_relation_with_joins
    david = authors(:david)
    assert_queries(1) {
875
      relation = Author.where(id: Author.joins(:posts).where(id: david.id))
876
      assert_equal [david], relation.to_a
877 878 879 880 881 882
    }
  end

  def test_find_all_using_where_with_relation_with_select_to_build_subquery
    david = authors(:david)
    assert_queries(1) {
883
      relation = Author.where(name: Author.where(id: david.id).select(:name))
884
      assert_equal [david], relation.to_a
885
    }
A
Aaron Patterson 已提交
886 887
  end

888
  def test_last
889
    authors = Author.all
890
    assert_equal authors(:bob), authors.last
891 892
  end

893 894
  def test_select_with_aggregates
    posts = Post.select(:title, :body)
R
Rafael Mendonça França 已提交
895

896 897
    assert_equal 11, posts.count(:all)
    assert_equal 11, posts.size
898 899
    assert_predicate posts, :any?
    assert_predicate posts, :many?
900
    assert_not_empty posts
901
  end
R
Rafael Mendonça França 已提交
902

903 904 905 906 907 908 909 910
  def test_select_takes_a_variable_list_of_args
    david = developers(:david)

    developer = Developer.where(id: david.id).select(:name, :salary).first
    assert_equal david.name, developer.name
    assert_equal david.salary, developer.salary
  end

911 912 913 914 915 916 917
  def test_select_takes_an_aliased_attribute
    first = topics(:first)

    topic = Topic.where(id: first.id).select(:heading).first
    assert_equal first.heading, topic.heading
  end

918 919 920 921
  def test_select_argument_error
    assert_raises(ArgumentError) { Developer.select }
  end

P
Pratik Naik 已提交
922
  def test_count
923
    posts = Post.all
P
Pratik Naik 已提交
924

925 926 927
    assert_equal 11, posts.count
    assert_equal 11, posts.count(:all)
    assert_equal 11, posts.count(:id)
P
Pratik Naik 已提交
928

929 930
    assert_equal 3, posts.where("comments_count > 1").count
    assert_equal 6, posts.where(comments_count: 0).count
P
Pratik Naik 已提交
931 932
  end

933 934
  def test_count_with_block
    posts = Post.all
935
    assert_equal 8, posts.count { |p| p.comments_count.even? }
936 937
  end

938 939 940 941 942 943 944 945
  def test_count_on_association_relation
    author = Author.last
    another_author = Author.first
    posts = Post.where(author_id: author.id)

    assert_equal author.posts.where(author_id: author.id).size, posts.count

    assert_equal 0, author.posts.where(author_id: another_author.id).size
946
    assert_empty author.posts.where(author_id: another_author.id)
947 948
  end

P
Pratik Naik 已提交
949
  def test_count_with_distinct
950
    posts = Post.all
P
Pratik Naik 已提交
951

952
    assert_equal 4, posts.distinct(true).count(:comments_count)
953
    assert_equal 11, posts.distinct(false).count(:comments_count)
P
Pratik Naik 已提交
954

955
    assert_equal 4, posts.distinct(true).select(:comments_count).count
956
    assert_equal 11, posts.distinct(false).select(:comments_count).count
P
Pratik Naik 已提交
957 958
  end

959 960 961 962 963 964
  def test_size_with_distinct
    posts = Post.distinct.select(:author_id, :comments_count)
    assert_queries(1) { assert_equal 8, posts.size }
    assert_queries(1) { assert_equal 8, posts.load.size }
  end

965 966 967 968 969 970
  def test_size_with_eager_loading_and_custom_order
    posts = Post.includes(:comments).order("comments.id")
    assert_queries(1) { assert_equal 11, posts.size }
    assert_queries(1) { assert_equal 11, posts.load.size }
  end

971 972 973 974 975 976
  def test_size_with_eager_loading_and_custom_order_and_distinct
    posts = Post.includes(:comments).order("comments.id").distinct
    assert_queries(1) { assert_equal 11, posts.size }
    assert_queries(1) { assert_equal 11, posts.load.size }
  end

P
Pratik Naik 已提交
977
  def test_count_explicit_columns
978
    Post.update_all(comments_count: nil)
979
    posts = Post.all
P
Pratik Naik 已提交
980

981 982
    assert_equal [0], posts.select("comments_count").where("id is not null").group("id").order("id").count.values.uniq
    assert_equal 0, posts.where("id is not null").select("comments_count").count
983

984 985
    assert_equal 11, posts.select("comments_count").count("id")
    assert_equal 0, posts.select("comments_count").count
P
Pratik Naik 已提交
986
    assert_equal 0, posts.count(:comments_count)
987
    assert_equal 0, posts.count("comments_count")
P
Pratik Naik 已提交
988
  end
989

990
  def test_multiple_selects
991
    post = Post.all.select("comments_count").select("title").order("id ASC").first
992 993 994 995
    assert_equal "Welcome to the weblog", post.title
    assert_equal 2, post.comments_count
  end

996
  def test_size
997
    posts = Post.all
998

999
    assert_queries(1) { assert_equal 11, posts.size }
D
Daniel Colson 已提交
1000
    assert_not_predicate posts, :loaded?
1001

1002
    best_posts = posts.where(comments_count: 0)
1003
    best_posts.load # force load
1004
    assert_no_queries { assert_equal 6, best_posts.size }
1005 1006
  end

1007
  def test_size_with_limit
1008
    posts = Post.limit(10)
1009

1010
    assert_queries(1) { assert_equal 10, posts.size }
D
Daniel Colson 已提交
1011
    assert_not_predicate posts, :loaded?
1012

1013
    best_posts = posts.where(comments_count: 0)
1014
    best_posts.load # force load
1015
    assert_no_queries { assert_equal 6, best_posts.size }
1016 1017 1018 1019 1020 1021
  end

  def test_size_with_zero_limit
    posts = Post.limit(0)

    assert_no_queries { assert_equal 0, posts.size }
D
Daniel Colson 已提交
1022
    assert_not_predicate posts, :loaded?
1023

1024
    posts.load # force load
1025 1026 1027 1028 1029 1030 1031
    assert_no_queries { assert_equal 0, posts.size }
  end

  def test_empty_with_zero_limit
    posts = Post.limit(0)

    assert_no_queries { assert_equal true, posts.empty? }
D
Daniel Colson 已提交
1032
    assert_not_predicate posts, :loaded?
1033 1034
  end

1035
  def test_count_complex_chained_relations
1036
    posts = Post.select("comments_count").where("id is not null").group("author_id").where("comments_count > 0")
1037

1038
    expected = { 1 => 4, 2 => 1 }
1039 1040 1041
    assert_equal expected, posts.count
  end

1042
  def test_empty
1043
    posts = Post.all
1044 1045

    assert_queries(1) { assert_equal false, posts.empty? }
D
Daniel Colson 已提交
1046
    assert_not_predicate posts, :loaded?
1047

1048
    no_posts = posts.where(title: "")
1049
    assert_queries(1) { assert_equal true, no_posts.empty? }
D
Daniel Colson 已提交
1050
    assert_not_predicate no_posts, :loaded?
1051

1052
    best_posts = posts.where(comments_count: 0)
1053
    best_posts.load # force load
1054 1055 1056 1057 1058
    assert_no_queries { assert_equal false, best_posts.empty? }
  end

  def test_empty_complex_chained_relations
    posts = Post.select("comments_count").where("id is not null").group("author_id").where("comments_count > 0")
A
Andrew White 已提交
1059

1060
    assert_queries(1) { assert_equal false, posts.empty? }
D
Daniel Colson 已提交
1061
    assert_not_predicate posts, :loaded?
1062

1063
    no_posts = posts.where(title: "")
1064
    assert_queries(1) { assert_equal true, no_posts.empty? }
D
Daniel Colson 已提交
1065
    assert_not_predicate no_posts, :loaded?
1066 1067
  end

P
Pratik Naik 已提交
1068
  def test_any
1069
    posts = Post.all
P
Pratik Naik 已提交
1070

1071 1072 1073 1074 1075 1076
    # This test was failing when run on its own (as opposed to running the entire suite).
    # The second line in the assert_queries block was causing visit_Arel_Attributes_Attribute
    # in Arel::Visitors::ToSql to trigger a SHOW TABLES query. Running that line here causes
    # the SHOW TABLES result to be cached so we don't have to do it again in the block.
    #
    # This is obviously a rubbish fix but it's the best I can come up with for now...
1077
    posts.where(id: nil).any?
1078

P
Pratik Naik 已提交
1079 1080
    assert_queries(3) do
      assert posts.any? # Uses COUNT()
D
Daniel Colson 已提交
1081
      assert_not_predicate posts.where(id: nil), :any?
P
Pratik Naik 已提交
1082

1083
      assert posts.any? { |p| p.id > 0 }
1084
      assert_not posts.any? { |p| p.id <= 0 }
P
Pratik Naik 已提交
1085 1086
    end

1087
    assert_predicate posts, :loaded?
P
Pratik Naik 已提交
1088 1089 1090
  end

  def test_many
1091
    posts = Post.all
1092

P
Pratik Naik 已提交
1093 1094
    assert_queries(2) do
      assert posts.many? # Uses COUNT()
1095
      assert posts.many? { |p| p.id > 0 }
1096
      assert_not posts.many? { |p| p.id < 2 }
P
Pratik Naik 已提交
1097
    end
1098

1099
    assert_predicate posts, :loaded?
P
Pratik Naik 已提交
1100 1101
  end

1102
  def test_many_with_limits
1103
    posts = Post.all
1104

1105
    assert_predicate posts, :many?
D
Daniel Colson 已提交
1106
    assert_not_predicate posts.limit(1), :many?
1107
  end
P
Pratik Naik 已提交
1108

1109 1110 1111
  def test_none?
    posts = Post.all
    assert_queries(1) do
1112
      assert_not posts.none? # Uses COUNT()
1113 1114
    end

D
Daniel Colson 已提交
1115
    assert_not_predicate posts, :loaded?
1116 1117

    assert_queries(1) do
1118
      assert posts.none? { |p| p.id < 0 }
1119
      assert_not posts.none? { |p| p.id == 1 }
1120 1121
    end

1122
    assert_predicate posts, :loaded?
1123 1124 1125 1126 1127
  end

  def test_one
    posts = Post.all
    assert_queries(1) do
1128
      assert_not posts.one? # Uses COUNT()
1129 1130
    end

D
Daniel Colson 已提交
1131
    assert_not_predicate posts, :loaded?
1132 1133

    assert_queries(1) do
1134
      assert_not posts.one? { |p| p.id < 3 }
1135
      assert posts.one? { |p| p.id == 1 }
1136 1137
    end

1138
    assert_predicate posts, :loaded?
1139 1140
  end

1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
  def test_to_a_should_dup_target
    posts = Post.all

    original_size = posts.size
    removed = posts.to_a.pop

    assert_equal original_size, posts.size
    assert_includes posts.to_a, removed
  end

P
Pratik Naik 已提交
1151
  def test_build
1152
    posts = Post.all
P
Pratik Naik 已提交
1153 1154 1155 1156 1157 1158

    post = posts.new
    assert_kind_of Post, post
  end

  def test_scoped_build
1159
    posts = Post.where(title: "You told a lie")
P
Pratik Naik 已提交
1160 1161 1162

    post = posts.new
    assert_kind_of Post, post
1163
    assert_equal "You told a lie", post.title
P
Pratik Naik 已提交
1164 1165
  end

1166
  def test_create
1167
    birds = Bird.all
1168 1169 1170

    sparrow = birds.create
    assert_kind_of Bird, sparrow
1171
    assert_not_predicate sparrow, :persisted?
1172

1173
    hen = birds.where(name: "hen").create
1174
    assert_predicate hen, :persisted?
1175
    assert_equal "hen", hen.name
1176 1177 1178
  end

  def test_create_bang
1179
    birds = Bird.all
1180 1181 1182

    assert_raises(ActiveRecord::RecordInvalid) { birds.create! }

1183
    hen = birds.where(name: "hen").create!
1184
    assert_kind_of Bird, hen
1185
    assert_predicate hen, :persisted?
1186
    assert_equal "hen", hen.name
1187
  end
P
Pratik Naik 已提交
1188

1189 1190 1191 1192 1193 1194 1195 1196 1197
  def test_create_with_polymorphic_association
    author = authors(:david)
    post = posts(:welcome)
    comment = Comment.where(post: post, author: author).create!(body: "hello")

    assert_equal author, comment.author
    assert_equal post, comment.post
  end

1198
  def test_first_or_create
1199
    parrot = Bird.where(color: "green").first_or_create(name: "parrot")
1200
    assert_kind_of Bird, parrot
1201
    assert_predicate parrot, :persisted?
1202 1203
    assert_equal "parrot", parrot.name
    assert_equal "green", parrot.color
1204

1205
    same_parrot = Bird.where(color: "green").first_or_create(name: "parakeet")
1206
    assert_kind_of Bird, same_parrot
1207
    assert_predicate same_parrot, :persisted?
1208 1209 1210 1211
    assert_equal parrot, same_parrot
  end

  def test_first_or_create_with_no_parameters
1212
    parrot = Bird.where(color: "green").first_or_create
1213
    assert_kind_of Bird, parrot
1214
    assert_not_predicate parrot, :persisted?
1215
    assert_equal "green", parrot.color
1216 1217
  end

1218 1219
  def test_first_or_create_with_after_initialize
    Bird.create!(color: "yellow", name: "canary")
1220 1221 1222 1223 1224
    parrot = assert_deprecated do
      Bird.where(color: "green").first_or_create do |bird|
        bird.name = "parrot"
        bird.enable_count = true
      end
1225 1226 1227 1228
    end
    assert_equal 0, parrot.total_count
  end

1229
  def test_first_or_create_with_block
1230
    Bird.create!(color: "yellow", name: "canary")
1231 1232
    parrot = Bird.where(color: "green").first_or_create do |bird|
      bird.name = "parrot"
1233
      assert_deprecated { assert_equal 0, Bird.count }
1234
    end
1235
    assert_kind_of Bird, parrot
1236
    assert_predicate parrot, :persisted?
1237 1238
    assert_equal "green", parrot.color
    assert_equal "parrot", parrot.name
1239

1240
    same_parrot = Bird.where(color: "green").first_or_create { |bird| bird.name = "parakeet" }
1241 1242 1243 1244
    assert_equal parrot, same_parrot
  end

  def test_first_or_create_with_array
1245
    several_green_birds = Bird.where(color: "green").first_or_create([{ name: "parrot" }, { name: "parakeet" }])
1246 1247 1248
    assert_kind_of Array, several_green_birds
    several_green_birds.each { |bird| assert bird.persisted? }

1249
    same_parrot = Bird.where(color: "green").first_or_create([{ name: "hummingbird" }, { name: "macaw" }])
1250 1251 1252 1253 1254
    assert_kind_of Bird, same_parrot
    assert_equal several_green_birds.first, same_parrot
  end

  def test_first_or_create_bang_with_valid_options
1255
    parrot = Bird.where(color: "green").first_or_create!(name: "parrot")
1256
    assert_kind_of Bird, parrot
1257
    assert_predicate parrot, :persisted?
1258 1259
    assert_equal "parrot", parrot.name
    assert_equal "green", parrot.color
1260

1261
    same_parrot = Bird.where(color: "green").first_or_create!(name: "parakeet")
1262
    assert_kind_of Bird, same_parrot
1263
    assert_predicate same_parrot, :persisted?
1264 1265 1266 1267
    assert_equal parrot, same_parrot
  end

  def test_first_or_create_bang_with_invalid_options
1268
    assert_raises(ActiveRecord::RecordInvalid) { Bird.where(color: "green").first_or_create!(pirate_id: 1) }
1269 1270 1271
  end

  def test_first_or_create_bang_with_no_parameters
1272
    assert_raises(ActiveRecord::RecordInvalid) { Bird.where(color: "green").first_or_create! }
1273 1274
  end

1275 1276
  def test_first_or_create_bang_with_after_initialize
    Bird.create!(color: "yellow", name: "canary")
1277 1278 1279 1280 1281
    parrot = assert_deprecated do
      Bird.where(color: "green").first_or_create! do |bird|
        bird.name = "parrot"
        bird.enable_count = true
      end
1282 1283 1284 1285
    end
    assert_equal 0, parrot.total_count
  end

1286
  def test_first_or_create_bang_with_valid_block
1287
    Bird.create!(color: "yellow", name: "canary")
1288 1289
    parrot = Bird.where(color: "green").first_or_create! do |bird|
      bird.name = "parrot"
1290
      assert_deprecated { assert_equal 0, Bird.count }
1291
    end
1292
    assert_kind_of Bird, parrot
1293
    assert_predicate parrot, :persisted?
1294 1295
    assert_equal "green", parrot.color
    assert_equal "parrot", parrot.name
1296

1297
    same_parrot = Bird.where(color: "green").first_or_create! { |bird| bird.name = "parakeet" }
1298 1299 1300 1301 1302
    assert_equal parrot, same_parrot
  end

  def test_first_or_create_bang_with_invalid_block
    assert_raise(ActiveRecord::RecordInvalid) do
1303
      Bird.where(color: "green").first_or_create! { |bird| bird.pirate_id = 1 }
1304 1305 1306 1307
    end
  end

  def test_first_or_create_with_valid_array
1308
    several_green_birds = Bird.where(color: "green").first_or_create!([{ name: "parrot" }, { name: "parakeet" }])
1309 1310 1311
    assert_kind_of Array, several_green_birds
    several_green_birds.each { |bird| assert bird.persisted? }

1312
    same_parrot = Bird.where(color: "green").first_or_create!([{ name: "hummingbird" }, { name: "macaw" }])
1313 1314 1315 1316 1317
    assert_kind_of Bird, same_parrot
    assert_equal several_green_birds.first, same_parrot
  end

  def test_first_or_create_with_invalid_array
1318
    assert_raises(ActiveRecord::RecordInvalid) { Bird.where(color: "green").first_or_create!([ { name: "parrot" }, { pirate_id: 1 } ]) }
1319 1320
  end

1321
  def test_first_or_initialize
1322
    parrot = Bird.where(color: "green").first_or_initialize(name: "parrot")
1323
    assert_kind_of Bird, parrot
1324 1325 1326
    assert_not_predicate parrot, :persisted?
    assert_predicate parrot, :valid?
    assert_predicate parrot, :new_record?
1327 1328
    assert_equal "parrot", parrot.name
    assert_equal "green", parrot.color
1329 1330
  end

1331
  def test_first_or_initialize_with_no_parameters
1332
    parrot = Bird.where(color: "green").first_or_initialize
1333
    assert_kind_of Bird, parrot
1334 1335 1336
    assert_not_predicate parrot, :persisted?
    assert_not_predicate parrot, :valid?
    assert_predicate parrot, :new_record?
1337
    assert_equal "green", parrot.color
1338 1339
  end

1340 1341
  def test_first_or_initialize_with_after_initialize
    Bird.create!(color: "yellow", name: "canary")
1342 1343 1344 1345 1346
    parrot = assert_deprecated do
      Bird.where(color: "green").first_or_initialize do |bird|
        bird.name = "parrot"
        bird.enable_count = true
      end
1347 1348 1349 1350
    end
    assert_equal 0, parrot.total_count
  end

1351
  def test_first_or_initialize_with_block
1352
    Bird.create!(color: "yellow", name: "canary")
1353 1354
    parrot = Bird.where(color: "green").first_or_initialize do |bird|
      bird.name = "parrot"
1355
      assert_deprecated { assert_equal 0, Bird.count }
1356
    end
1357
    assert_kind_of Bird, parrot
1358 1359 1360
    assert_not_predicate parrot, :persisted?
    assert_predicate parrot, :valid?
    assert_predicate parrot, :new_record?
1361 1362
    assert_equal "green", parrot.color
    assert_equal "parrot", parrot.name
1363 1364
  end

1365
  def test_find_or_create_by
1366
    assert_nil Bird.find_by(name: "bob")
1367

1368
    bird = Bird.find_or_create_by(name: "bob")
1369
    assert_predicate bird, :persisted?
1370

1371
    assert_equal bird, Bird.find_or_create_by(name: "bob")
1372 1373
  end

1374
  def test_find_or_create_by_with_create_with
1375
    assert_nil Bird.find_by(name: "bob")
1376

1377
    bird = Bird.create_with(color: "green").find_or_create_by(name: "bob")
1378
    assert_predicate bird, :persisted?
1379
    assert_equal "green", bird.color
1380

1381
    assert_equal bird, Bird.create_with(color: "blue").find_or_create_by(name: "bob")
1382 1383
  end

1384
  def test_find_or_create_by!
1385
    assert_raises(ActiveRecord::RecordInvalid) { Bird.find_or_create_by!(color: "green") }
1386 1387
  end

1388 1389 1390 1391 1392 1393 1394 1395 1396
  def test_create_or_find_by
    assert_nil Subscriber.find_by(nick: "bob")

    subscriber = Subscriber.create!(nick: "bob")

    assert_equal subscriber, Subscriber.create_or_find_by(nick: "bob")
    assert_not_equal subscriber, Subscriber.create_or_find_by(nick: "cat")
  end

1397 1398 1399 1400 1401 1402 1403
  def test_create_or_find_by_should_not_raise_due_to_validation_errors
    assert_nothing_raised do
      bird = Bird.create_or_find_by(color: "green")
      assert_predicate bird, :invalid?
    end
  end

1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422
  def test_create_or_find_by_with_non_unique_attributes
    Subscriber.create!(nick: "bob", name: "the builder")

    assert_raises(ActiveRecord::RecordNotFound) do
      Subscriber.create_or_find_by(nick: "bob", name: "the cat")
    end
  end

  def test_create_or_find_by_within_transaction
    assert_nil Subscriber.find_by(nick: "bob")

    subscriber = Subscriber.create!(nick: "bob")

    Subscriber.transaction do
      assert_equal subscriber, Subscriber.create_or_find_by(nick: "bob")
      assert_not_equal subscriber, Subscriber.create_or_find_by(nick: "cat")
    end
  end

1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
  def test_create_or_find_by_with_bang
    assert_nil Subscriber.find_by(nick: "bob")

    subscriber = Subscriber.create!(nick: "bob")

    assert_equal subscriber, Subscriber.create_or_find_by!(nick: "bob")
    assert_not_equal subscriber, Subscriber.create_or_find_by!(nick: "cat")
  end

  def test_create_or_find_by_with_bang_should_raise_due_to_validation_errors
    assert_raises(ActiveRecord::RecordInvalid) { Bird.create_or_find_by!(color: "green") }
  end

  def test_create_or_find_by_with_bang_with_non_unique_attributes
    Subscriber.create!(nick: "bob", name: "the builder")

    assert_raises(ActiveRecord::RecordNotFound) do
      Subscriber.create_or_find_by!(nick: "bob", name: "the cat")
    end
  end

  def test_create_or_find_by_with_bang_within_transaction
    assert_nil Subscriber.find_by(nick: "bob")

    subscriber = Subscriber.create!(nick: "bob")

    Subscriber.transaction do
      assert_equal subscriber, Subscriber.create_or_find_by!(nick: "bob")
      assert_not_equal subscriber, Subscriber.create_or_find_by!(nick: "cat")
    end
  end

1455
  def test_find_or_initialize_by
1456
    assert_nil Bird.find_by(name: "bob")
1457

1458
    bird = Bird.find_or_initialize_by(name: "bob")
1459
    assert_predicate bird, :new_record?
1460 1461
    bird.save!

1462
    assert_equal bird, Bird.find_or_initialize_by(name: "bob")
1463 1464
  end

1465
  def test_explicit_create_with
1466
    hens = Bird.where(name: "hen")
1467
    assert_equal "hen", hens.new.name
1468

1469
    hens = hens.create_with(name: "cock")
1470
    assert_equal "cock", hens.new.name
1471 1472
  end

D
Darwin D Wu 已提交
1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
  def test_create_with_nested_attributes
    assert_difference("Project.count", 1) do
      developers = Developer.where(name: "Aaron")
      developers = developers.create_with(
        projects_attributes: [{ name: "p1" }]
      )
      developers.create!
    end
  end

P
Pratik Naik 已提交
1483
  def test_except
1484
    relation = Post.where(author_id: 1).order("id ASC").limit(1)
1485
    assert_equal [posts(:welcome)], relation.to_a
P
Pratik Naik 已提交
1486 1487

    author_posts = relation.except(:order, :limit)
1488
    assert_equal Post.where(author_id: 1).to_a, author_posts.to_a
P
Pratik Naik 已提交
1489 1490

    all_posts = relation.except(:where, :order, :limit)
J
Jon Leighton 已提交
1491
    assert_equal Post.all, all_posts
P
Pratik Naik 已提交
1492 1493
  end

E
Emilio Tagua 已提交
1494
  def test_only
1495
    relation = Post.where(author_id: 1).order("id ASC").limit(1)
1496
    assert_equal [posts(:welcome)], relation.to_a
E
Emilio Tagua 已提交
1497 1498

    author_posts = relation.only(:where)
1499
    assert_equal Post.where(author_id: 1).to_a, author_posts.to_a
E
Emilio Tagua 已提交
1500 1501

    all_posts = relation.only(:limit)
M
Matthew Draper 已提交
1502
    assert_equal Post.limit(1).to_a, all_posts.to_a
E
Emilio Tagua 已提交
1503 1504
  end

P
Pratik Naik 已提交
1505
  def test_anonymous_extension
1506
    relation = Post.where(author_id: 1).order("id ASC").extending do
P
Pratik Naik 已提交
1507
      def author
1508
        "lifo"
P
Pratik Naik 已提交
1509 1510 1511 1512 1513 1514 1515 1516
      end
    end

    assert_equal "lifo", relation.author
    assert_equal "lifo", relation.limit(1).author
  end

  def test_named_extension
1517
    relation = Post.where(author_id: 1).order("id ASC").extending(Post::NamedExtension)
P
Pratik Naik 已提交
1518 1519 1520
    assert_equal "lifo", relation.author
    assert_equal "lifo", relation.limit(1).author
  end
1521 1522

  def test_order_by_relation_attribute
1523
    assert_equal Post.order(Post.arel_table[:title]).to_a, Post.order("title").to_a
1524
  end
1525

1526
  def test_default_scope_order_with_scope_order
1527 1528
    assert_equal "zyke", CoolCar.order_using_new_style.limit(1).first.name
    assert_equal "zyke", FastCar.order_using_new_style.limit(1).first.name
1529 1530 1531
  end

  def test_order_using_scoping
1532 1533
    car1 = CoolCar.order("id DESC").scoping do
      CoolCar.all.merge!(order: "id asc").first
1534
    end
1535
    assert_equal "zyke", car1.name
1536

1537 1538
    car2 = FastCar.order("id DESC").scoping do
      FastCar.all.merge!(order: "id asc").first
1539
    end
1540
    assert_equal "zyke", car2.name
1541 1542 1543
  end

  def test_unscoped_block_style
1544 1545
    assert_equal "honda", CoolCar.unscoped { CoolCar.order_using_new_style.limit(1).first.name }
    assert_equal "honda", FastCar.unscoped { FastCar.order_using_new_style.limit(1).first.name }
1546 1547
  end

1548
  def test_intersection_with_array
1549
    relation = Author.where(name: "David")
1550
    rails_author = relation.first
1551

1552 1553 1554
    assert_equal [rails_author], [rails_author] & relation
    assert_equal [rails_author], relation & [rails_author]
  end
1555

1556
  def test_primary_key
1557
    assert_equal "id", Post.all.primary_key
1558
  end
1559

1560
  def test_ordering_with_extra_spaces
1561
    assert_equal authors(:david), Author.order("id DESC , name DESC").last
1562
  end
1563

1564
  def test_distinct
1565 1566
    tag1 = Tag.create(name: "Foo")
    tag2 = Tag.create(name: "Foo")
1567

1568
    query = Tag.select(:name).where(id: [tag1.id, tag2.id])
1569

1570
    assert_equal ["Foo", "Foo"], query.map(&:name)
1571
    assert_sql(/DISTINCT/) do
1572
      assert_equal ["Foo"], query.distinct.map(&:name)
1573 1574
    end
    assert_sql(/DISTINCT/) do
1575
      assert_equal ["Foo"], query.distinct(true).map(&:name)
1576
    end
1577
    assert_equal ["Foo", "Foo"], query.distinct(true).distinct(false).map(&:name)
1578
  end
1579

1580
  def test_doesnt_add_having_values_if_options_are_blank
1581
    scope = Post.having("")
1582
    assert_empty scope.having_clause
1583 1584

    scope = Post.having([])
1585
    assert_empty scope.having_clause
1586 1587 1588 1589
  end

  def test_having_with_binds_for_both_where_and_having
    post = Post.first
1590 1591
    having_then_where = Post.having(id: post.id).where(title: post.title).group(:id)
    where_then_having = Post.where(title: post.title).having(id: post.id).group(:id)
1592 1593 1594 1595 1596 1597 1598

    assert_equal [post], having_then_where
    assert_equal [post], where_then_having
  end

  def test_multiple_where_and_having_clauses
    post = Post.first
1599 1600
    having_then_where = Post.having(id: post.id).where(title: post.title)
      .having(id: post.id).where(title: post.title).group(:id)
1601 1602

    assert_equal [post], having_then_where
1603 1604
  end

1605 1606 1607 1608
  def test_grouping_by_column_with_reserved_name
    assert_equal [], Possession.select(:where).group(:where).to_a
  end

1609 1610
  def test_references_triggers_eager_loading
    scope = Post.includes(:comments)
1611 1612
    assert_not_predicate scope, :eager_loading?
    assert_predicate scope.references(:comments), :eager_loading?
1613 1614 1615 1616
  end

  def test_references_doesnt_trigger_eager_loading_if_reference_not_included
    scope = Post.references(:comments)
1617
    assert_not_predicate scope, :eager_loading?
1618
  end
1619

1620
  def test_automatically_added_where_references
1621
    scope = Post.where(comments: { body: "Bla" })
1622
    assert_equal ["comments"], scope.references_values
1623

1624 1625
    scope = Post.where("comments.body" => "Bla")
    assert_equal ["comments"], scope.references_values
1626
  end
1627

1628 1629
  def test_automatically_added_where_not_references
    scope = Post.where.not(comments: { body: "Bla" })
1630
    assert_equal ["comments"], scope.references_values
1631

1632 1633
    scope = Post.where.not("comments.body" => "Bla")
    assert_equal ["comments"], scope.references_values
1634 1635
  end

1636
  def test_automatically_added_having_references
1637
    scope = Post.having(comments: { body: "Bla" })
1638
    assert_equal ["comments"], scope.references_values
1639

1640 1641
    scope = Post.having("comments.body" => "Bla")
    assert_equal ["comments"], scope.references_values
1642
  end
1643 1644

  def test_automatically_added_order_references
1645 1646
    scope = Post.order("comments.body")
    assert_equal ["comments"], scope.references_values
1647

1648
    scope = Post.order(Arel.sql("#{Comment.quoted_table_name}.#{Comment.quoted_primary_key}"))
1649 1650 1651 1652 1653
    if current_adapter?(:OracleAdapter)
      assert_equal ["COMMENTS"], scope.references_values
    else
      assert_equal ["comments"], scope.references_values
    end
1654

1655 1656
    scope = Post.order("comments.body", "yaks.body")
    assert_equal ["comments", "yaks"], scope.references_values
1657 1658

    # Don't infer yaks, let's not go down that road again...
1659 1660
    scope = Post.order("comments.body, yaks.body")
    assert_equal ["comments"], scope.references_values
1661

1662 1663
    scope = Post.order("comments.body asc")
    assert_equal ["comments"], scope.references_values
1664

1665
    scope = Post.order(Arel.sql("foo(comments.body)"))
1666 1667
    assert_equal [], scope.references_values
  end
1668

1669
  def test_automatically_added_reorder_references
1670
    scope = Post.reorder("comments.body")
1671 1672
    assert_equal %w(comments), scope.references_values

1673
    scope = Post.reorder(Arel.sql("#{Comment.quoted_table_name}.#{Comment.quoted_primary_key}"))
1674 1675 1676 1677 1678
    if current_adapter?(:OracleAdapter)
      assert_equal ["COMMENTS"], scope.references_values
    else
      assert_equal ["comments"], scope.references_values
    end
1679

1680
    scope = Post.reorder("comments.body", "yaks.body")
1681 1682 1683
    assert_equal %w(comments yaks), scope.references_values

    # Don't infer yaks, let's not go down that road again...
1684
    scope = Post.reorder("comments.body, yaks.body")
1685 1686
    assert_equal %w(comments), scope.references_values

1687
    scope = Post.reorder("comments.body asc")
1688 1689
    assert_equal %w(comments), scope.references_values

1690
    scope = Post.reorder(Arel.sql("foo(comments.body)"))
1691 1692 1693
    assert_equal [], scope.references_values
  end

1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705
  def test_order_with_reorder_nil_removes_the_order
    relation = Post.order(:title).reorder(nil)

    assert_nil relation.order_values.first
  end

  def test_reverse_order_with_reorder_nil_removes_the_order
    relation = Post.order(:title).reverse_order.reorder(nil)

    assert_nil relation.order_values.first
  end

1706
  def test_presence
1707
    topics = Topic.all
1708

1709
    # the first query is triggered because there are no topics yet.
1710 1711 1712 1713 1714
    assert_queries(1) { assert topics.present? }

    # checking if there are topics is used before you actually display them,
    # thus it shouldn't invoke an extra count query.
    assert_no_queries { assert topics.present? }
1715
    assert_no_queries { assert_not topics.blank? }
1716 1717 1718 1719 1720 1721 1722 1723

    # shows count of topics and loops after loading the query should not trigger extra queries either.
    assert_no_queries { topics.size }
    assert_no_queries { topics.length }
    assert_no_queries { topics.each }

    # count always trigger the COUNT query.
    assert_queries(1) { topics.count }
1724

1725
    assert_predicate topics, :loaded?
1726
  end
1727

1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745
  def test_delete_by
    david = authors(:david)

    assert_difference("Post.count", -3) { david.posts.delete_by(body: "hello") }

    deleted = Author.delete_by(id: david.id)
    assert_equal 1, deleted
  end

  def test_destroy_by
    david = authors(:david)

    assert_difference("Post.count", -3) { david.posts.destroy_by(body: "hello") }

    destroyed = Author.destroy_by(id: david.id)
    assert_equal [david], destroyed
  end

1746 1747 1748 1749 1750 1751 1752 1753 1754
  test "find_by with hash conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.order(:id).find_by(author_id: 2)
  end

  test "find_by with non-hash conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.order(:id).find_by("author_id = 2")
  end

  test "find_by with multi-arg conditions returns the first matching record" do
1755
    assert_equal posts(:eager_other), Post.order(:id).find_by("author_id = ?", 2)
1756 1757 1758
  end

  test "find_by returns nil if the record is missing" do
1759
    assert_nil Post.all.find_by("1 = 0")
1760 1761
  end

1762
  test "find_by doesn't have implicit ordering" do
1763
    assert_sql(/^((?!ORDER).)*$/) { Post.all.find_by(author_id: 2) }
1764 1765
  end

1766 1767 1768 1769
  test "find_by requires at least one argument" do
    assert_raises(ArgumentError) { Post.all.find_by }
  end

1770 1771 1772 1773 1774 1775 1776 1777 1778
  test "find_by! with hash conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.order(:id).find_by!(author_id: 2)
  end

  test "find_by! with non-hash conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.order(:id).find_by!("author_id = 2")
  end

  test "find_by! with multi-arg conditions returns the first matching record" do
1779
    assert_equal posts(:eager_other), Post.order(:id).find_by!("author_id = ?", 2)
1780 1781
  end

1782
  test "find_by! doesn't have implicit ordering" do
1783
    assert_sql(/^((?!ORDER).)*$/) { Post.all.find_by!(author_id: 2) }
1784 1785
  end

1786 1787
  test "find_by! raises RecordNotFound if the record is missing" do
    assert_raises(ActiveRecord::RecordNotFound) do
1788
      Post.all.find_by!("1 = 0")
1789 1790
    end
  end
1791

1792 1793 1794 1795
  test "find_by! requires at least one argument" do
    assert_raises(ArgumentError) { Post.all.find_by! }
  end

1796
  test "loaded relations cannot be mutated by multi value methods" do
1797
    relation = Post.all
1798 1799 1800
    relation.to_a

    assert_raises(ActiveRecord::ImmutableRelation) do
1801
      relation.where! "foo"
1802 1803 1804 1805
    end
  end

  test "loaded relations cannot be mutated by single value methods" do
1806
    relation = Post.all
1807 1808 1809 1810 1811 1812 1813 1814
    relation.to_a

    assert_raises(ActiveRecord::ImmutableRelation) do
      relation.limit! 5
    end
  end

  test "loaded relations cannot be mutated by merge!" do
1815
    relation = Post.all
1816 1817 1818
    relation.to_a

    assert_raises(ActiveRecord::ImmutableRelation) do
1819
      relation.merge! where: "foo"
1820 1821
    end
  end
1822

1823 1824 1825 1826 1827 1828 1829 1830 1831
  test "loaded relations cannot be mutated by extending!" do
    relation = Post.all
    relation.to_a

    assert_raises(ActiveRecord::ImmutableRelation) do
      relation.extending! Module.new
    end
  end

1832 1833
  test "relations with cached arel can't be mutated [internal API]" do
    relation = Post.all
1834
    relation.arel
1835 1836 1837 1838 1839

    assert_raises(ActiveRecord::ImmutableRelation) { relation.limit!(5) }
    assert_raises(ActiveRecord::ImmutableRelation) { relation.where!("1 = 2") }
  end

1840 1841 1842 1843
  test "relations show the records in #inspect" do
    relation = Post.limit(2)
    assert_equal "#<ActiveRecord::Relation [#{Post.limit(2).map(&:inspect).join(', ')}]>", relation.inspect
  end
1844

1845
  test "relations limit the records in #inspect at 10" do
1846 1847 1848
    relation = Post.limit(11)
    assert_equal "#<ActiveRecord::Relation [#{Post.limit(10).map(&:inspect).join(', ')}, ...]>", relation.inspect
  end
1849

1850
  test "relations don't load all records in #inspect" do
1851
    assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) do
1852 1853 1854 1855
      Post.all.inspect
    end
  end

1856 1857 1858 1859 1860 1861 1862 1863 1864 1865
  test "already-loaded relations don't perform a new query in #inspect" do
    relation = Post.limit(2)
    relation.to_a

    expected = "#<ActiveRecord::Relation [#{Post.limit(2).map(&:inspect).join(', ')}]>"

    assert_no_queries do
      assert_equal expected, relation.inspect
    end
  end
1866

1867
  test "using a custom table affects the wheres" do
1868
    post = posts(:welcome)
1869

1870 1871
    assert_equal post, custom_post_relation.where!(title: post.title).take
  end
1872

1873
  test "using a custom table with joins affects the joins" do
R
Ryuta Kamizono 已提交
1874 1875
    post = posts(:welcome)

1876
    assert_equal post, custom_post_relation.joins(:author).where!(title: post.title).take
1877
  end
J
Jon Leighton 已提交
1878

1879
  test "arel_attribute respects a custom table" do
1880
    assert_equal [posts(:sti_comments)], custom_post_relation.ranked_by_comments.limit_by(1).to_a
1881 1882
  end

1883 1884 1885 1886
  test "alias_tracker respects a custom table" do
    assert_equal posts(:welcome), custom_post_relation("categories_posts").joins(:categories).first
  end

1887
  test "#load" do
J
Jon Leighton 已提交
1888 1889 1890 1891 1892 1893
    relation = Post.all
    assert_queries(1) do
      assert_equal relation, relation.load
    end
    assert_no_queries { relation.to_a }
  end
1894

1895 1896 1897
  test "group with select and includes" do
    authors_count = Post.select("author_id, COUNT(author_id) AS num_posts").
      group("author_id").order("author_id").includes(:author).to_a
1898 1899 1900 1901 1902 1903 1904 1905 1906 1907

    assert_no_queries do
      result = authors_count.map do |post|
        [post.num_posts, post.author.try(:name)]
      end

      expected = [[1, nil], [5, "David"], [3, "Mary"], [2, "Bob"]]
      assert_equal expected, result
    end
  end
1908

1909 1910 1911 1912 1913 1914
  test "joins with select" do
    posts = Post.joins(:author).select("id", "authors.author_address_id").order("posts.id").limit(3)
    assert_equal [1, 2, 4], posts.map(&:id)
    assert_equal [1, 1, 1], posts.map(&:author_address_id)
  end

1915 1916 1917 1918 1919 1920
  test "joins with select custom attribute" do
    contract = Company.create!(name: "test").contracts.create!
    company = Company.joins(:contracts).select(:id, :metadata).find(contract.company_id)
    assert_equal contract.metadata, company.metadata
  end

1921 1922 1923 1924 1925 1926 1927
  test "joins with order by custom attribute" do
    companies = Company.create!([{ name: "test1" }, { name: "test2" }])
    companies.each { |company| company.contracts.create! }
    assert_equal companies, Company.joins(:contracts).order(:metadata)
    assert_equal companies.reverse, Company.joins(:contracts).order(metadata: :desc)
  end

1928 1929 1930
  test "delegations do not leak to other classes" do
    Topic.all.by_lifo
    assert Topic.all.class.method_defined?(:by_lifo)
D
Daniel Colson 已提交
1931
    assert_not_respond_to Post.all, :by_lifo
1932 1933
  end

R
Ryuta Kamizono 已提交
1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945
  def test_unscope_with_subquery
    p1 = Post.where(id: 1)
    p2 = Post.where(id: 2)

    assert_not_equal p1, p2

    comments = Comment.where(post: p1).unscope(where: :post_id).where(post: p2)

    assert_not_equal p1.first.comments, comments
    assert_equal p2.first.comments, comments
  end

1946 1947 1948 1949 1950 1951 1952 1953
  def test_unscope_specific_where_value
    posts = Post.where(title: "Welcome to the weblog", body: "Such a lovely day")

    assert_equal 1, posts.count
    assert_equal 1, posts.unscope(where: :title).count
    assert_equal 1, posts.unscope(where: :body).count
  end

1954
  def test_locked_should_not_build_arel
1955
    posts = Post.locked
1956
    assert_predicate posts, :locked?
1957 1958 1959
    assert_nothing_raised { posts.lock!(false) }
  end

1960
  def test_relation_join_method
1961
    assert_equal "Thank you for the welcome,Thank you again for the welcome", Post.first.comments.join(",")
1962
  end
1963

1964 1965 1966 1967 1968 1969 1970 1971 1972 1973
  def test_relation_with_private_kernel_method
    accounts = Account.all
    assert_equal [accounts(:signals37)], accounts.open
    assert_equal [accounts(:signals37)], accounts.available

    sub_accounts = SubAccount.all
    assert_equal [accounts(:signals37)], sub_accounts.open
    assert_equal [accounts(:signals37)], sub_accounts.available
  end

1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014
  test "#skip_query_cache!" do
    Post.cache do
      assert_queries(1) do
        Post.all.load
        Post.all.load
      end

      assert_queries(2) do
        Post.all.skip_query_cache!.load
        Post.all.skip_query_cache!.load
      end
    end
  end

  test "#skip_query_cache! with an eager load" do
    Post.cache do
      assert_queries(1) do
        Post.eager_load(:comments).load
        Post.eager_load(:comments).load
      end

      assert_queries(2) do
        Post.eager_load(:comments).skip_query_cache!.load
        Post.eager_load(:comments).skip_query_cache!.load
      end
    end
  end

  test "#skip_query_cache! with a preload" do
    Post.cache do
      assert_queries(2) do
        Post.preload(:comments).load
        Post.preload(:comments).load
      end

      assert_queries(4) do
        Post.preload(:comments).skip_query_cache!.load
        Post.preload(:comments).skip_query_cache!.load
      end
    end
  end
2015

2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028
  test "#where with set" do
    david = authors(:david)
    mary = authors(:mary)

    authors = Author.where(name: ["David", "Mary"].to_set)
    assert_equal [david, mary], authors
  end

  test "#where with empty set" do
    authors = Author.where(name: Set.new)
    assert_empty authors
  end

2029
  private
2030 2031
    def custom_post_relation(alias_name = "omg_posts")
      table_alias = Post.arel_table.alias(alias_name)
2032 2033 2034
      table_metadata = ActiveRecord::TableMetadata.new(Post, table_alias)
      predicate_builder = ActiveRecord::PredicateBuilder.new(table_metadata)

2035 2036 2037 2038 2039
      ActiveRecord::Relation.create(
        Post,
        table: table_alias,
        predicate_builder: predicate_builder
      )
2040
    end
P
Pratik Naik 已提交
2041
end