aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases/validations/association_validation_test.rb
blob: 7ac34bc71eae41c697dc228e1e576b745e856882 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# encoding: utf-8
require "cases/helper"
require 'models/topic'
require 'models/reply'
require 'models/owner'
require 'models/pet'
require 'models/man'
require 'models/interest'

class AssociationValidationTest < ActiveRecord::TestCase
  fixtures :topics, :owners

  repair_validations(Topic, Reply, Owner)

  def test_validates_size_of_association
    assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 }
    o = Owner.new('name' => 'nopets')
    assert !o.save
    assert o.errors[:pets].any?
    o.pets.build('name' => 'apet')
    assert o.valid?
  end

  def test_validates_size_of_association_using_within
    assert_nothing_raised { Owner.validates_size_of :pets, :within => 1..2 }
    o = Owner.new('name' => 'nopets')
    assert !o.save
    assert o.errors[:pets].any?

    o.pets.build('name' => 'apet')
    assert o.valid?

    2.times { o.pets.build('name' => 'apet') }
    assert !o.save
    assert o.errors[:pets].any?
  end

  def test_validates_associated_many
    Topic.validates_associated(:replies)
    Reply.validates_presence_of(:content)
    t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
    t.replies << [r = Reply.new("title" => "A reply"), r2 = Reply.new("title" => "Another reply", "content" => "non-empty"), r3 = Reply.new("title" => "Yet another reply"), r4 = Reply.new("title" => "The last reply", "content" => "non-empty")]
    assert !t.valid?
    assert t.errors[:replies].any?
    assert_equal 1, r.errors.count  # make sure all associated objects have been validated
    assert_equal 0, r2.errors.count
    assert_equal 1, r3.errors.count
    assert_equal 0, r4.errors.count
    r.content = r3.content = "non-empty"
    assert t.valid?
  end

  def test_validates_associated_one
    Reply.validates :topic, :associated => true
    Topic.validates_presence_of( :content )
    r = Reply.new("title" => "A reply", "content" => "with content!")
    r.topic = Topic.create("title" => "uhohuhoh")
    assert !r.valid?
    assert r.errors[:topic].any?
    r.topic.content = "non-empty"
    assert r.valid?
  end

  def test_validates_associated_marked_for_destruction
    Topic.validates_associated(:replies)
    Reply.validates_presence_of(:content)
    t = Topic.new
    t.replies << Reply.new
    assert t.invalid?
    t.replies.first.mark_for_destruction
    assert t.valid?
  end

  def test_validates_associated_with_custom_message_using_quotes
    Reply.validates_associated :topic, :message=> "This string contains 'single' and \"double\" quotes"
    Topic.validates_presence_of :content
    r = Reply.create("title" => "A reply", "content" => "with content!")
    r.topic = Topic.create("title" => "uhohuhoh")
    assert !r.valid?
    assert_equal ["This string contains 'single' and \"double\" quotes"], r.errors[:topic]
  end

  def test_validates_associated_missing
    Reply.validates_presence_of(:topic)
    r = Reply.create("title" => "A reply", "content" => "with content!")
    assert !r.valid?
    assert r.errors[:topic].any?

    r.topic = Topic.first
    assert r.valid?
  end

  def test_validates_size_of_association_utf8
    assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 }
    o = Owner.new('name' => 'あいうえおかきくけこ')
    assert !o.save
    assert o.errors[:pets].any?
    o.pets.build('name' => 'あいうえおかきくけこ')
    assert o.valid?
  end

  def test_validates_presence_of_belongs_to_association__parent_is_new_record
    repair_validations(Interest) do
      # Note that Interest and Man have the :inverse_of option set
      Interest.validates_presence_of(:man)
      man = Man.new(:name => 'John')
      interest = man.interests.build(:topic => 'Airplanes')
      assert interest.valid?, "Expected interest to be valid, but was not. Interest should have a man object associated"
    end
  end

  def test_validates_presence_of_belongs_to_association__existing_parent
    repair_validations(Interest) do
      Interest.validates_presence_of(:man)
      man = Man.create!(:name => 'John')
      interest = man.interests.build(:topic => 'Airplanes')
      assert interest.valid?, "Expected interest to be valid, but was not. Interest should have a man object associated"
    end
  end

  def test_validates_associated_models_in_the_same_context
    Topic.validates_presence_of :title, :on => :custom_context
    Topic.validates_associated :replies
    Reply.validates_presence_of :title, :on => :custom_context

    t = Topic.new('title' => '')
    r = t.replies.new('title' => '')

    assert t.valid?
    assert !t.valid?(:custom_context)

    t.title = "Longer"
    assert !t.valid?(:custom_context), "Should NOT be valid if the associated object is not valid in the same context."

    r.title = "Longer"
    assert t.valid?(:custom_context), "Should be valid if the associated object is not valid in the same context."
  end
end