persistence_test.rb 27.1 KB
Newer Older
1
require "cases/helper"
2
require 'models/aircraft'
3
require 'models/post'
4
require 'models/comment'
5 6 7 8 9 10
require 'models/author'
require 'models/topic'
require 'models/reply'
require 'models/category'
require 'models/company'
require 'models/developer'
A
Arun Agrawal 已提交
11
require 'models/computer'
12 13 14 15
require 'models/project'
require 'models/minimalistic'
require 'models/warehouse_thing'
require 'models/parrot'
16
require 'models/minivan'
17
require 'models/owner'
18
require 'models/person'
19 20
require 'models/pet'
require 'models/toy'
21 22
require 'rexml/document'

V
Vipul A M 已提交
23
class PersistenceTest < ActiveRecord::TestCase
24
  fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :author_addresses, :categorizations, :categories, :posts, :minivans, :pets, :toys
25

26 27 28 29 30 31 32 33 34
  # Oracle UPDATE does not support ORDER BY
  unless current_adapter?(:OracleAdapter)
    def test_update_all_ignores_order_without_limit_from_association
      author = authors(:david)
      assert_nothing_raised do
        assert_equal author.posts_with_comments_and_categories.length, author.posts_with_comments_and_categories.update_all([ "body = ?", "bulk update!" ])
      end
    end

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
    def test_update_all_doesnt_ignore_order
      assert_equal authors(:david).id + 1, authors(:mary).id # make sure there is going to be a duplicate PK error
      test_update_with_order_succeeds = lambda do |order|
        begin
          Author.order(order).update_all('id = id + 1')
        rescue ActiveRecord::ActiveRecordError
          false
        end
      end

      if test_update_with_order_succeeds.call('id DESC')
        assert !test_update_with_order_succeeds.call('id ASC') # test that this wasn't a fluke and using an incorrect order results in an exception
      else
        # test that we're failing because the current Arel's engine doesn't support UPDATE ORDER BY queries is using subselects instead
        assert_sql(/\AUPDATE .+ \(SELECT .* ORDER BY id DESC\)\Z/i) do
          test_update_with_order_succeeds.call('id DESC')
        end
      end
    end

55 56 57 58
    def test_update_all_with_order_and_limit_updates_subset_only
      author = authors(:david)
      assert_nothing_raised do
        assert_equal 1, author.posts_sorted_by_id_limited.size
59
        assert_equal 2, author.posts_sorted_by_id_limited.limit(2).to_a.size
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
        assert_equal 1, author.posts_sorted_by_id_limited.update_all([ "body = ?", "bulk update!" ])
        assert_equal "bulk update!", posts(:welcome).body
        assert_not_equal "bulk update!", posts(:thinking).body
      end
    end
  end

  def test_update_many
    topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
    updated = Topic.update(topic_data.keys, topic_data.values)

    assert_equal 2, updated.size
    assert_equal "1 updated", Topic.find(1).content
    assert_equal "2 updated", Topic.find(2).content
  end

  def test_delete_all
    assert Topic.count > 0

    assert_equal Topic.count, Topic.delete_all
  end

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
  def test_delete_all_with_joins_and_where_part_is_hash
    where_args = {:toys => {:name => 'Bone'}}
    count = Pet.joins(:toys).where(where_args).count

    assert_equal count, 1
    assert_equal count, Pet.joins(:toys).where(where_args).delete_all
  end

  def test_delete_all_with_joins_and_where_part_is_not_hash
    where_args = ['toys.name = ?', 'Bone']
    count = Pet.joins(:toys).where(where_args).count

    assert_equal count, 1
    assert_equal count, Pet.joins(:toys).where(where_args).delete_all
  end

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
  def test_increment_attribute
    assert_equal 50, accounts(:signals37).credit_limit
    accounts(:signals37).increment! :credit_limit
    assert_equal 51, accounts(:signals37, :reload).credit_limit

    accounts(:signals37).increment(:credit_limit).increment!(:credit_limit)
    assert_equal 53, accounts(:signals37, :reload).credit_limit
  end

  def test_increment_nil_attribute
    assert_nil topics(:first).parent_id
    topics(:first).increment! :parent_id
    assert_equal 1, topics(:first).parent_id
  end

  def test_increment_attribute_by
    assert_equal 50, accounts(:signals37).credit_limit
    accounts(:signals37).increment! :credit_limit, 5
    assert_equal 55, accounts(:signals37, :reload).credit_limit

    accounts(:signals37).increment(:credit_limit, 1).increment!(:credit_limit, 3)
    assert_equal 59, accounts(:signals37, :reload).credit_limit
  end

  def test_destroy_all
    conditions = "author_name = 'Mary'"
124
    topics_by_mary = Topic.all.merge!(:where => conditions, :order => 'id').to_a
125 126 127 128 129
    assert ! topics_by_mary.empty?

    assert_difference('Topic.count', -topics_by_mary.size) do
      destroyed = Topic.destroy_all(conditions).sort_by(&:id)
      assert_equal topics_by_mary, destroyed
130
      assert destroyed.all?(&:frozen?), "destroyed topics should be frozen"
131 132 133 134
    end
  end

  def test_destroy_many
135
    clients = Client.all.merge!(:order => 'id').find([2, 3])
136 137 138 139

    assert_difference('Client.count', -2) do
      destroyed = Client.destroy([2, 3]).sort_by(&:id)
      assert_equal clients, destroyed
140
      assert destroyed.all?(&:frozen?), "destroyed clients should be frozen"
141 142 143
    end
  end

144 145 146 147 148 149 150 151 152 153 154 155 156
  def test_becomes
    assert_kind_of Reply, topics(:first).becomes(Reply)
    assert_equal "The First Topic", topics(:first).becomes(Reply).title
  end

  def test_becomes_includes_errors
    company = Company.new(:name => nil)
    assert !company.valid?
    original_errors = company.errors
    client = company.becomes(Client)
    assert_equal original_errors, client.errors
  end

157 158 159 160 161 162 163 164 165 166 167 168 169 170
  def test_dupd_becomes_persists_changes_from_the_original
    original = topics(:first)
    copy = original.dup.becomes(Reply)
    copy.save!
    assert_equal "The First Topic", Topic.find(copy.id).title
  end

  def test_becomes_includes_changed_attributes
    company = Company.new(name: "37signals")
    client = company.becomes(Client)
    assert_equal "37signals", client.name
    assert_equal %w{name}, client.changed
  end

171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
  def test_delete_many
    original_count = Topic.count
    Topic.delete(deleting = [1, 2])
    assert_equal original_count - deleting.size, Topic.count
  end

  def test_decrement_attribute
    assert_equal 50, accounts(:signals37).credit_limit

    accounts(:signals37).decrement!(:credit_limit)
    assert_equal 49, accounts(:signals37, :reload).credit_limit

    accounts(:signals37).decrement(:credit_limit).decrement!(:credit_limit)
    assert_equal 47, accounts(:signals37, :reload).credit_limit
  end

  def test_decrement_attribute_by
    assert_equal 50, accounts(:signals37).credit_limit
    accounts(:signals37).decrement! :credit_limit, 5
    assert_equal 45, accounts(:signals37, :reload).credit_limit

    accounts(:signals37).decrement(:credit_limit, 1).decrement!(:credit_limit, 3)
    assert_equal 41, accounts(:signals37, :reload).credit_limit
  end

196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
  def test_create
    topic = Topic.new
    topic.title = "New Topic"
    topic.save
    topic_reloaded = Topic.find(topic.id)
    assert_equal("New Topic", topic_reloaded.title)
  end

  def test_save!
    topic = Topic.new(:title => "New Topic")
    assert topic.save!

    reply = WrongReply.new
    assert_raise(ActiveRecord::RecordInvalid) { reply.save! }
  end

  def test_save_null_string_attributes
    topic = Topic.find(1)
    topic.attributes = { "title" => "null", "author_name" => "null" }
    topic.save!
    topic.reload
    assert_equal("null", topic.title)
    assert_equal("null", topic.author_name)
  end

  def test_save_nil_string_attributes
    topic = Topic.find(1)
    topic.title = nil
    topic.save!
    topic.reload
    assert_nil topic.title
  end

  def test_save_for_record_with_only_primary_key
    minimalistic = Minimalistic.new
    assert_nothing_raised { minimalistic.save }
  end

  def test_save_for_record_with_only_primary_key_that_is_provided
    assert_nothing_raised { Minimalistic.create!(:id => 2) }
  end

238
  def test_save_with_duping_of_destroyed_object
239
    developer = Developer.first
240 241 242 243
    developer.destroy
    new_developer = developer.dup
    new_developer.save
    assert new_developer.persisted?
244
    assert_not new_developer.destroyed?
245 246
  end

247 248 249 250 251 252 253
  def test_create_many
    topics = Topic.create([ { "title" => "first" }, { "title" => "second" }])
    assert_equal 2, topics.size
    assert_equal "first", topics.first.title
  end

  def test_create_columns_not_equal_attributes
254 255 256
    topic = Topic.instantiate(
      'title'          => 'Another New Topic',
      'does_not_exist' => 'test'
257
    )
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
    assert_nothing_raised { topic.save }
  end

  def test_create_through_factory_with_block
    topic = Topic.create("title" => "New Topic") do |t|
      t.author_name = "David"
    end
    assert_equal("New Topic", topic.title)
    assert_equal("David", topic.author_name)
  end

  def test_create_many_through_factory_with_block
    topics = Topic.create([ { "title" => "first" }, { "title" => "second" }]) do |t|
      t.author_name = "David"
    end
    assert_equal 2, topics.size
    topic1, topic2 = Topic.find(topics[0].id), Topic.find(topics[1].id)
    assert_equal "first", topic1.title
    assert_equal "David", topic1.author_name
    assert_equal "second", topic2.title
    assert_equal "David", topic2.author_name
  end

281
  def test_update_object
282 283 284 285
    topic = Topic.new
    topic.title = "Another New Topic"
    topic.written_on = "2003-12-12 23:23:00"
    topic.save
286 287
    topic_reloaded = Topic.find(topic.id)
    assert_equal("Another New Topic", topic_reloaded.title)
288

289 290
    topic_reloaded.title = "Updated topic"
    topic_reloaded.save
291

292
    topic_reloaded_again = Topic.find(topic.id)
293

294
    assert_equal("Updated topic", topic_reloaded_again.title)
295 296 297 298 299 300 301
  end

  def test_update_columns_not_equal_attributes
    topic = Topic.new
    topic.title = "Still another topic"
    topic.save

302
    topic_reloaded = Topic.instantiate(topic.attributes.merge('does_not_exist' => 'test'))
303 304
    topic_reloaded.title = 'A New Topic'
    assert_nothing_raised { topic_reloaded.save }
305 306 307 308 309 310 311
  end

  def test_update_for_record_with_only_primary_key
    minimalistic = minimalistics(:first)
    assert_nothing_raised { minimalistic.save }
  end

312 313 314
  def test_update_sti_type
    assert_instance_of Reply, topics(:second)

315
    topic = topics(:second).becomes!(Topic)
316 317 318 319 320
    assert_instance_of Topic, topic
    topic.save!
    assert_instance_of Topic, Topic.find(topic.id)
  end

321 322 323 324 325 326 327 328 329 330 331
  def test_preserve_original_sti_type
    reply = topics(:second)
    assert_equal "Reply", reply.type

    topic = reply.becomes(Topic)
    assert_equal "Reply", reply.type

    assert_instance_of Topic, topic
    assert_equal "Reply", topic.type
  end

E
Edo Balvers 已提交
332 333 334 335 336 337 338 339 340
  def test_update_sti_subclass_type
    assert_instance_of Topic, topics(:first)

    reply = topics(:first).becomes!(Reply)
    assert_instance_of Reply, reply
    reply.save!
    assert_instance_of Reply, Reply.find(reply.id)
  end

341 342 343 344 345 346 347 348 349 350 351
  def test_update_after_create
    klass = Class.new(Topic) do
      def self.name; 'Topic'; end
      after_create do
        update_attribute("author_name", "David")
      end
    end
    topic = klass.new
    topic.title = "Another New Topic"
    topic.save

352 353 354
    topic_reloaded = Topic.find(topic.id)
    assert_equal("Another New Topic", topic_reloaded.title)
    assert_equal("David", topic_reloaded.author_name)
355 356
  end

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
  def test_delete
    topic = Topic.find(1)
    assert_equal topic, topic.delete, 'topic.delete did not return self'
    assert topic.frozen?, 'topic not frozen after delete'
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
  end

  def test_delete_doesnt_run_callbacks
    Topic.find(1).delete
    assert_not_nil Topic.find(2)
  end

  def test_destroy
    topic = Topic.find(1)
    assert_equal topic, topic.destroy, 'topic.destroy did not return self'
    assert topic.frozen?, 'topic not frozen after destroy'
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
  end

376 377 378 379 380 381 382
  def test_destroy!
    topic = Topic.find(1)
    assert_equal topic, topic.destroy!, 'topic.destroy! did not return self'
    assert topic.frozen?, 'topic not frozen after destroy!'
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
  end

383
  def test_record_not_found_exception
A
Aaron Patterson 已提交
384
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(99999) }
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
  end

  def test_update_all
    assert_equal Topic.count, Topic.update_all("content = 'bulk updated!'")
    assert_equal "bulk updated!", Topic.find(1).content
    assert_equal "bulk updated!", Topic.find(2).content

    assert_equal Topic.count, Topic.update_all(['content = ?', 'bulk updated again!'])
    assert_equal "bulk updated again!", Topic.find(1).content
    assert_equal "bulk updated again!", Topic.find(2).content

    assert_equal Topic.count, Topic.update_all(['content = ?', nil])
    assert_nil Topic.find(1).content
  end

  def test_update_all_with_hash
    assert_not_nil Topic.find(1).last_read
    assert_equal Topic.count, Topic.update_all(:content => 'bulk updated with hash!', :last_read => nil)
    assert_equal "bulk updated with hash!", Topic.find(1).content
    assert_equal "bulk updated with hash!", Topic.find(2).content
    assert_nil Topic.find(1).last_read
    assert_nil Topic.find(2).last_read
  end

  def test_update_all_with_non_standard_table_name
410
    assert_equal 1, WarehouseThing.where(id: 1).update_all(['value = ?', 0])
411 412 413 414 415 416 417 418 419 420 421 422 423 424
    assert_equal 0, WarehouseThing.find(1).value
  end

  def test_delete_new_record
    client = Client.new
    client.delete
    assert client.frozen?
  end

  def test_delete_record_with_associations
    client = Client.find(3)
    client.delete
    assert client.frozen?
    assert_kind_of Firm, client.firm
425
    assert_raise(RuntimeError) { client.name = "something else" }
426 427 428 429 430 431 432 433 434 435 436 437 438
  end

  def test_destroy_new_record
    client = Client.new
    client.destroy
    assert client.frozen?
  end

  def test_destroy_record_with_associations
    client = Client.find(3)
    client.destroy
    assert client.frozen?
    assert_kind_of Firm, client.firm
439
    assert_raise(RuntimeError) { client.name = "something else" }
440 441
  end

442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
  def test_update_attribute
    assert !Topic.find(1).approved?
    Topic.find(1).update_attribute("approved", true)
    assert Topic.find(1).approved?

    Topic.find(1).update_attribute(:approved, false)
    assert !Topic.find(1).approved?
  end

  def test_update_attribute_for_readonly_attribute
    minivan = Minivan.find('m1')
    assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, 'black') }
  end

  def test_update_attribute_with_one_updated
    t = Topic.first
    t.update_attribute(:title, 'super_title')
    assert_equal 'super_title', t.title
    assert !t.changed?, "topic should not have changed"
    assert !t.title_changed?, "title should not have changed"
    assert_nil t.title_change, 'title change should be nil'

    t.reload
    assert_equal 'super_title', t.title
  end

  def test_update_attribute_for_updated_at_on
    developer = Developer.find(1)
470
    prev_month = Time.now.prev_month.change(usec: 0)
471 472 473 474 475 476 477 478 479 480 481

    developer.update_attribute(:updated_at, prev_month)
    assert_equal prev_month, developer.updated_at

    developer.update_attribute(:salary, 80001)
    assert_not_equal prev_month, developer.updated_at

    developer.reload
    assert_not_equal prev_month, developer.updated_at
  end

482 483
  def test_update_column
    topic = Topic.find(1)
484
    topic.update_column("approved", true)
485 486 487
    assert topic.approved?
    topic.reload
    assert topic.approved?
488 489 490 491 492

    topic.update_column(:approved, false)
    assert !topic.approved?
    topic.reload
    assert !topic.approved?
493 494 495 496 497 498
  end

  def test_update_column_should_not_use_setter_method
    dev = Developer.find(1)
    dev.instance_eval { def salary=(value); write_attribute(:salary, value * 2); end }

499
    dev.update_column(:salary, 80000)
500 501 502 503 504 505 506 507
    assert_equal 80000, dev.salary

    dev.reload
    assert_equal 80000, dev.salary
  end

  def test_update_column_should_raise_exception_if_new_record
    topic = Topic.new
508
    assert_raises(ActiveRecord::ActiveRecordError) { topic.update_column("approved", false) }
509 510 511 512
  end

  def test_update_column_should_not_leave_the_object_dirty
    topic = Topic.find(1)
513
    topic.update_column("content", "--- Have a nice day\n...\n")
514 515

    topic.reload
516
    topic.update_column(:content, "--- You too\n...\n")
517 518 519
    assert_equal [], topic.changed

    topic.reload
520
    topic.update_column("content", "--- Have a nice day\n...\n")
521 522 523 524 525 526 527
    assert_equal [], topic.changed
  end

  def test_update_column_with_model_having_primary_key_other_than_id
    minivan = Minivan.find('m1')
    new_name = 'sebavan'

528
    minivan.update_column(:name, new_name)
529 530 531 532 533 534
    assert_equal new_name, minivan.name
  end

  def test_update_column_for_readonly_attribute
    minivan = Minivan.find('m1')
    prev_color = minivan.color
535
    assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_column(:color, 'black') }
536 537 538 539 540
    assert_equal prev_color, minivan.color
  end

  def test_update_column_should_not_modify_updated_at
    developer = Developer.find(1)
541
    prev_month = Time.now.prev_month.change(usec: 0)
542

543
    developer.update_column(:updated_at, prev_month)
544 545
    assert_equal prev_month, developer.updated_at

546
    developer.update_column(:salary, 80001)
547 548 549
    assert_equal prev_month, developer.updated_at

    developer.reload
550
    assert_equal prev_month.to_i, developer.updated_at.to_i
551 552 553 554
  end

  def test_update_column_with_one_changed_and_one_updated
    t = Topic.order('id').limit(1).first
555
    author_name = t.author_name
556
    t.author_name = 'John'
557
    t.update_column(:title, 'super_title')
558 559 560 561 562 563 564 565 566 567
    assert_equal 'John', t.author_name
    assert_equal 'super_title', t.title
    assert t.changed?, "topic should have changed"
    assert t.author_name_changed?, "author_name should have changed"

    t.reload
    assert_equal author_name, t.author_name
    assert_equal 'super_title', t.title
  end

568 569 570 571 572 573 574 575
  def test_update_column_with_default_scope
    developer = DeveloperCalledDavid.first
    developer.name = 'John'
    developer.save!

    assert developer.update_column(:name, 'Will'), 'did not update record due to default scope'
  end

S
Sebastian Martinez 已提交
576 577 578 579 580 581 582 583 584 585
  def test_update_columns
    topic = Topic.find(1)
    topic.update_columns({ "approved" => true, title: "Sebastian Topic" })
    assert topic.approved?
    assert_equal "Sebastian Topic", topic.title
    topic.reload
    assert topic.approved?
    assert_equal "Sebastian Topic", topic.title
  end

586 587 588 589 590 591 592 593 594 595 596
  def test_update_columns_should_not_use_setter_method
    dev = Developer.find(1)
    dev.instance_eval { def salary=(value); write_attribute(:salary, value * 2); end }

    dev.update_columns(salary: 80000)
    assert_equal 80000, dev.salary

    dev.reload
    assert_equal 80000, dev.salary
  end

S
Sebastian Martinez 已提交
597 598 599 600 601 602 603
  def test_update_columns_should_raise_exception_if_new_record
    topic = Topic.new
    assert_raises(ActiveRecord::ActiveRecordError) { topic.update_columns({ approved: false }) }
  end

  def test_update_columns_should_not_leave_the_object_dirty
    topic = Topic.find(1)
604
    topic.update({ "content" => "--- Have a nice day\n...\n", :author_name => "Jose" })
S
Sebastian Martinez 已提交
605 606

    topic.reload
607
    topic.update_columns({ content: "--- You too\n...\n", "author_name" => "Sebastian" })
S
Sebastian Martinez 已提交
608 609 610
    assert_equal [], topic.changed

    topic.reload
611
    topic.update_columns({ content: "--- Have a nice day\n...\n", author_name: "Jose" })
S
Sebastian Martinez 已提交
612 613 614
    assert_equal [], topic.changed
  end

615 616 617 618 619 620 621 622
  def test_update_columns_with_model_having_primary_key_other_than_id
    minivan = Minivan.find('m1')
    new_name = 'sebavan'

    minivan.update_columns(name: new_name)
    assert_equal new_name, minivan.name
  end

S
Sebastian Martinez 已提交
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
  def test_update_columns_with_one_readonly_attribute
    minivan = Minivan.find('m1')
    prev_color = minivan.color
    prev_name = minivan.name
    assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_columns({ name: "My old minivan", color: 'black' }) }
    assert_equal prev_color, minivan.color
    assert_equal prev_name, minivan.name

    minivan.reload
    assert_equal prev_color, minivan.color
    assert_equal prev_name, minivan.name
  end

  def test_update_columns_should_not_modify_updated_at
    developer = Developer.find(1)
638
    prev_month = Time.now.prev_month.change(usec: 0)
S
Sebastian Martinez 已提交
639

640
    developer.update_columns(updated_at: prev_month)
S
Sebastian Martinez 已提交
641 642
    assert_equal prev_month, developer.updated_at

643
    developer.update_columns(salary: 80000)
S
Sebastian Martinez 已提交
644 645 646 647 648 649 650 651
    assert_equal prev_month, developer.updated_at
    assert_equal 80000, developer.salary

    developer.reload
    assert_equal prev_month.to_i, developer.updated_at.to_i
    assert_equal 80000, developer.salary
  end

652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
  def test_update_columns_with_one_changed_and_one_updated
    t = Topic.order('id').limit(1).first
    author_name = t.author_name
    t.author_name = 'John'
    t.update_columns(title: 'super_title')
    assert_equal 'John', t.author_name
    assert_equal 'super_title', t.title
    assert t.changed?, "topic should have changed"
    assert t.author_name_changed?, "author_name should have changed"

    t.reload
    assert_equal author_name, t.author_name
    assert_equal 'super_title', t.title
  end

667 668 669 670 671 672 673 674 675 676 677 678 679
  def test_update_columns_changing_id
    topic = Topic.find(1)
    topic.update_columns(id: 123)
    assert_equal 123, topic.id
    topic.reload
    assert_equal 123, topic.id
  end

  def test_update_columns_returns_boolean
    topic = Topic.find(1)
    assert_equal true, topic.update_columns(title: "New title")
  end

680 681 682 683 684 685 686 687
  def test_update_columns_with_default_scope
    developer = DeveloperCalledDavid.first
    developer.name = 'John'
    developer.save!

    assert developer.update_columns(name: 'Will'), 'did not update record due to default scope'
  end

688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
  def test_update
    topic = Topic.find(1)
    assert !topic.approved?
    assert_equal "The First Topic", topic.title

    topic.update("approved" => true, "title" => "The First Topic Updated")
    topic.reload
    assert topic.approved?
    assert_equal "The First Topic Updated", topic.title

    topic.update(approved: false, title: "The First Topic")
    topic.reload
    assert !topic.approved?
    assert_equal "The First Topic", topic.title
  end
703

704 705 706 707 708 709 710 711 712 713
  def test_update_attributes
    topic = Topic.find(1)
    assert !topic.approved?
    assert_equal "The First Topic", topic.title

    topic.update_attributes("approved" => true, "title" => "The First Topic Updated")
    topic.reload
    assert topic.approved?
    assert_equal "The First Topic Updated", topic.title

714
    topic.update_attributes(approved: false, title: "The First Topic")
715 716 717
    topic.reload
    assert !topic.approved?
    assert_equal "The First Topic", topic.title
718 719 720 721 722 723 724 725 726

    assert_raise(ActiveRecord::RecordNotUnique, ActiveRecord::StatementInvalid) do
      topic.update_attributes(id: 3, title: "Hm is it possible?")
    end
    assert_not_equal "Hm is it possible?", Topic.find(3).title

    topic.update_attributes(id: 1234)
    assert_nothing_raised { topic.reload }
    assert_equal topic.title, Topic.find(1234).title
727 728
  end

729 730 731 732 733 734 735 736 737 738 739
  def test_update_attributes_parameters
    topic = Topic.find(1)
    assert_nothing_raised do
      topic.update_attributes({})
    end

    assert_raises(ArgumentError) do
      topic.update_attributes(nil)
    end
  end

740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
  def test_update!
    Reply.validates_presence_of(:title)
    reply = Reply.find(2)
    assert_equal "The Second Topic of the day", reply.title
    assert_equal "Have a nice day", reply.content

    reply.update!("title" => "The Second Topic of the day updated", "content" => "Have a nice evening")
    reply.reload
    assert_equal "The Second Topic of the day updated", reply.title
    assert_equal "Have a nice evening", reply.content

    reply.update!(title: "The Second Topic of the day", content: "Have a nice day")
    reply.reload
    assert_equal "The Second Topic of the day", reply.title
    assert_equal "Have a nice day", reply.content

    assert_raise(ActiveRecord::RecordInvalid) { reply.update!(title: nil, content: "Have a nice evening") }
  ensure
758
    Reply.clear_validators!
759 760
  end

761 762 763 764 765 766 767 768 769 770 771
  def test_update_attributes!
    Reply.validates_presence_of(:title)
    reply = Reply.find(2)
    assert_equal "The Second Topic of the day", reply.title
    assert_equal "Have a nice day", reply.content

    reply.update_attributes!("title" => "The Second Topic of the day updated", "content" => "Have a nice evening")
    reply.reload
    assert_equal "The Second Topic of the day updated", reply.title
    assert_equal "Have a nice evening", reply.content

772
    reply.update_attributes!(title: "The Second Topic of the day", content: "Have a nice day")
773 774 775 776
    reply.reload
    assert_equal "The Second Topic of the day", reply.title
    assert_equal "Have a nice day", reply.content

777
    assert_raise(ActiveRecord::RecordInvalid) { reply.update_attributes!(title: nil, content: "Have a nice evening") }
778
  ensure
779
    Reply.clear_validators!
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
  end

  def test_destroyed_returns_boolean
    developer = Developer.first
    assert_equal false, developer.destroyed?
    developer.destroy
    assert_equal true, developer.destroyed?

    developer = Developer.last
    assert_equal false, developer.destroyed?
    developer.delete
    assert_equal true, developer.destroyed?
  end

  def test_persisted_returns_boolean
    developer = Developer.new(:name => "Jose")
    assert_equal false, developer.persisted?
    developer.save!
    assert_equal true, developer.persisted?

    developer = Developer.first
    assert_equal true, developer.persisted?
    developer.destroy
    assert_equal false, developer.persisted?

    developer = Developer.last
    assert_equal true, developer.persisted?
    developer.delete
    assert_equal false, developer.persisted?
  end

  def test_class_level_destroy
    should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
    Topic.find(1).replies << should_be_destroyed_reply

    Topic.destroy(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
    assert_raise(ActiveRecord::RecordNotFound) { Reply.find(should_be_destroyed_reply.id) }
  end

  def test_class_level_delete
    should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
    Topic.find(1).replies << should_be_destroyed_reply

    Topic.delete(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
    assert_nothing_raised { Reply.find(should_be_destroyed_reply.id) }
  end

  def test_create_with_custom_timestamps
    custom_datetime = 1.hour.ago.beginning_of_day

    %w(created_at created_on updated_at updated_on).each do |attribute|
      parrot = LiveParrot.create(:name => "colombian", attribute => custom_datetime)
      assert_equal custom_datetime, parrot[attribute]
    end
  end

838 839 840 841 842 843 844 845 846 847 848 849 850
  def test_persist_inherited_class_with_different_table_name
    minimalistic_aircrafts = Class.new(Minimalistic) do
      self.table_name = "aircraft"
    end

    assert_difference "Aircraft.count", 1 do
      aircraft = minimalistic_aircrafts.create(name: "Wright Flyer")
      aircraft.name = "Wright Glider"
      aircraft.save
    end

    assert_equal "Wright Glider", Aircraft.last.name
  end
851 852 853 854 855 856 857 858 859 860 861

  def test_instantiate_creates_a_new_instance
    post = Post.instantiate("title" => "appropriate documentation", "type" => "SpecialPost")
    assert_equal "appropriate documentation", post.title
    assert_instance_of SpecialPost, post

    # body was not initialized
    assert_raises ActiveModel::MissingAttributeError do
      post.body
    end
  end
862 863 864 865 866 867 868

  def test_reload_removes_custom_selects
    post = Post.select('posts.*, 1 as wibble').last!

    assert_equal 1, post[:wibble]
    assert_nil post.reload[:wibble]
  end
869 870 871 872 873 874 875 876 877 878 879 880

  def test_find_via_reload
    post = Post.new

    assert post.new_record?

    post.id = 1
    post.reload

    assert_equal "Welcome to the weblog", post.title
    assert_not post.new_record?
  end
881
end