polymorpheus 3.1.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/polymorpheus.rb +1 -0
- data/lib/polymorpheus/mysql_adapter.rb +1 -1
- data/lib/polymorpheus/schema_dumper.rb +3 -2
- data/lib/polymorpheus/trigger.rb +21 -20
- data/lib/polymorpheus/version.rb +1 -1
- data/polymorpheus.gemspec +2 -3
- data/spec/interface/belongs_to_polymorphic_spec.rb +135 -0
- data/spec/interface/has_many_as_polymorph_spec.rb +69 -0
- data/spec/interface/validates_polymorph_spec.rb +35 -0
- data/spec/interface_spec.rb +18 -206
- data/spec/mysql2_adapter_spec.rb +270 -120
- data/spec/schema_dumper_spec.rb +14 -21
- data/spec/spec_helper.rb +34 -2
- data/spec/support/active_record/connection_adapters/abstract_mysql_adapter.rb +9 -0
- data/spec/support/class_defs.rb +12 -0
- data/spec/support/connection_helpers.rb +21 -0
- data/spec/support/schema_helpers.rb +17 -0
- data/spec/{sql_logger.rb → support/sql_logger.rb} +1 -1
- data/spec/support/sql_test_helpers.rb +41 -0
- data/spec/trigger_spec.rb +5 -6
- metadata +14 -23
- data/spec/shared_examples.rb +0 -125
- data/spec/support/db_setup.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e181e9294980f79aa4b50efdd7edb588de1c390a
|
4
|
+
data.tar.gz: 317c3f2e0da8513874d57955042e547a2077c3bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5ccb72b1c3a0ed0d247b67a5c2dbf71b04a46d6947c64b71e16a4212960acc60cf1b8771e8768b04967c1a8b64df9238aa7102febf67c5fe95ce36facbd0f3c
|
7
|
+
data.tar.gz: 5ef3e30327eaab0914ea2731cf3d5699ea1f058320ebfc2ada4704e8e4b497db556d112dcca7f8a694efb8cc74b7b1bf7d3f7307ed35ceb532e89acc2ccbe8ae
|
data/lib/polymorpheus.rb
CHANGED
@@ -3,14 +3,15 @@ module Polymorpheus
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
|
6
|
+
alias_method :tables_without_triggers, :tables
|
7
|
+
alias_method :tables, :tables_with_triggers
|
7
8
|
end
|
8
9
|
|
9
10
|
def tables_with_triggers(stream)
|
10
11
|
tables_without_triggers(stream)
|
11
12
|
|
12
13
|
if @connection.respond_to?(:triggers)
|
13
|
-
@connection.triggers.collect(&:schema_statement).each do |statement|
|
14
|
+
@connection.triggers.collect(&:schema_statement).uniq.each do |statement|
|
14
15
|
stream.puts statement
|
15
16
|
end
|
16
17
|
end
|
data/lib/polymorpheus/trigger.rb
CHANGED
@@ -1,29 +1,30 @@
|
|
1
|
-
|
1
|
+
module Polymorpheus
|
2
|
+
class Trigger
|
2
3
|
|
3
|
-
|
4
|
-
|
4
|
+
attr_accessor :name, :event, :table, :statement, :timing, :created, :sql_mode,
|
5
|
+
:definer, :charset, :collation_connection, :db_collation
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
def initialize(arr)
|
8
|
+
raise ArgumentError unless arr.is_a?(Array) && arr.length == 11
|
9
|
+
[:name, :event, :table, :statement, :timing, :created, :sql_mode,
|
10
|
+
:definer, :charset, :collation_connection, :db_collation].
|
11
|
+
each_with_index do |attr, ind|
|
12
|
+
self.send("#{attr}=", arr[ind])
|
13
|
+
end
|
12
14
|
end
|
13
|
-
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
def columns
|
17
|
+
/IF\((.*)\) \<\> 1/.match(self.statement) do |match|
|
18
|
+
match[1].split(' + ').collect do |submatch|
|
19
|
+
/NEW\.([^ ]*)/.match(submatch)[1]
|
20
|
+
end
|
19
21
|
end
|
20
22
|
end
|
21
|
-
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
def schema_statement
|
25
|
+
# note that we don't need to worry about unique indices or foreign keys
|
26
|
+
# because separate schema statements will be generated for them
|
27
|
+
" add_polymorphic_triggers(:#{table}, #{columns.to_s})"
|
28
|
+
end
|
27
29
|
end
|
28
|
-
|
29
30
|
end
|
data/lib/polymorpheus/version.rb
CHANGED
data/polymorpheus.gemspec
CHANGED
@@ -17,9 +17,8 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.extra_rdoc_files = ["README.md", "LICENSE.txt"]
|
18
18
|
s.license = 'MIT'
|
19
19
|
|
20
|
-
s.add_dependency('activerecord', '>= 3.2', '< 5')
|
20
|
+
s.add_dependency('activerecord', '>= 3.2', '< 5.2')
|
21
21
|
|
22
22
|
s.add_development_dependency('rake', '~> 10.4.2')
|
23
|
-
s.add_development_dependency('rspec
|
24
|
-
s.add_development_dependency('mysql2', '~> 0.3.10')
|
23
|
+
s.add_development_dependency('rspec', '~> 2.14.0')
|
25
24
|
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Polymorpheus::Interface::BelongsToPolymorphic do
|
4
|
+
let(:hero) { Hero.create! }
|
5
|
+
let(:villain) { Villain.create! }
|
6
|
+
let(:superhero) { Superhero.create! }
|
7
|
+
let(:alien_demigod) { AlienDemigod.create! }
|
8
|
+
|
9
|
+
before do
|
10
|
+
create_table :story_arcs do |t|
|
11
|
+
t.references :hero
|
12
|
+
t.references :villain
|
13
|
+
end
|
14
|
+
create_table :heros
|
15
|
+
create_table :villains
|
16
|
+
end
|
17
|
+
|
18
|
+
specify { StoryArc::POLYMORPHEUS_ASSOCIATIONS.should == %w[hero villain] }
|
19
|
+
specify { Superpower::POLYMORPHEUS_ASSOCIATIONS.should == %w[superhero
|
20
|
+
supervillain] }
|
21
|
+
|
22
|
+
describe "setter methods for ActiveRecord objects" do
|
23
|
+
let(:story_arc) { StoryArc.new(attributes) }
|
24
|
+
let(:attributes) { {} }
|
25
|
+
|
26
|
+
it "sets the correct attribute value for the setter" do
|
27
|
+
story_arc.character = hero
|
28
|
+
story_arc.hero_id.should == hero.id
|
29
|
+
story_arc.villain_id.should == nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it "sets competing associations to nil" do
|
33
|
+
story_arc.character = hero
|
34
|
+
story_arc.hero_id.should == hero.id
|
35
|
+
story_arc.character = villain
|
36
|
+
story_arc.villain_id.should == villain.id
|
37
|
+
story_arc.hero_id.should == nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "throws an error if the assigned object isn't a valid type" do
|
41
|
+
create_table :trees
|
42
|
+
|
43
|
+
tree = Tree.create!
|
44
|
+
expect { story_arc.character = tree }
|
45
|
+
.to raise_error(Polymorpheus::Interface::InvalidTypeError,
|
46
|
+
"Invalid type. Must be one of {hero, villain}")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "does not throw an error if the assigned object is a subclass of a
|
50
|
+
valid type" do
|
51
|
+
expect { story_arc.character = superhero }.not_to raise_error
|
52
|
+
story_arc.hero_id.should == superhero.id
|
53
|
+
end
|
54
|
+
|
55
|
+
it "does not throw an error if the assigned object is a descendant of a
|
56
|
+
valid type" do
|
57
|
+
expect { story_arc.character = alien_demigod }.not_to raise_error
|
58
|
+
story_arc.hero_id.should == alien_demigod.id
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "setter methods for objects inheriting from ActiveRecord objects" do
|
63
|
+
let(:superpower) { Superpower.new }
|
64
|
+
|
65
|
+
before do
|
66
|
+
create_table :superpowers do |t|
|
67
|
+
t.references :superhero
|
68
|
+
t.references :supervillain
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it "throws an error if the assigned object is an instance of the parent
|
73
|
+
ActiveRecord class" do
|
74
|
+
expect { superpower.wielder = hero }.to raise_error(
|
75
|
+
Polymorpheus::Interface::InvalidTypeError,
|
76
|
+
"Invalid type. Must be one of {superhero, supervillain}"
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "works if the assigned object is of the specified class" do
|
81
|
+
expect { superpower.wielder = superhero }.not_to raise_error
|
82
|
+
superpower.superhero_id.should == superhero.id
|
83
|
+
end
|
84
|
+
|
85
|
+
it "works if the assigned object is an instance of a child class" do
|
86
|
+
expect { superpower.wielder = alien_demigod }.not_to raise_error
|
87
|
+
superpower.superhero_id.should == alien_demigod.id
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#polymorpheus exposed interface method' do
|
92
|
+
subject(:interface) { story_arc.polymorpheus }
|
93
|
+
|
94
|
+
context 'when there is no relationship defined' do
|
95
|
+
let(:story_arc) { StoryArc.new }
|
96
|
+
|
97
|
+
its(:associations) { should match_associations(:hero, :villain) }
|
98
|
+
its(:active_association) { should == nil }
|
99
|
+
its(:query_condition) { should == nil }
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when there is are multiple relationships defined' do
|
103
|
+
let(:story_arc) { StoryArc.new(hero_id: hero.id, villain_id: villain.id) }
|
104
|
+
|
105
|
+
its(:associations) { should match_associations(:hero, :villain) }
|
106
|
+
its(:active_association) { should == nil }
|
107
|
+
its(:query_condition) { should == nil }
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'when there is one relationship defined through the id value' do
|
111
|
+
let(:story_arc) { StoryArc.new(hero_id: hero.id) }
|
112
|
+
|
113
|
+
its(:associations) { should match_associations(:hero, :villain) }
|
114
|
+
its(:active_association) { be_association(:hero) }
|
115
|
+
its(:query_condition) { should == { 'hero_id' => hero.id } }
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'when there is one relationship defined through the setter' do
|
119
|
+
let(:story_arc) { StoryArc.new(character: hero) }
|
120
|
+
|
121
|
+
its(:associations) { should match_associations(:hero, :villain) }
|
122
|
+
its(:active_association) { be_association(:hero) }
|
123
|
+
its(:query_condition) { should == { 'hero_id' => hero.id } }
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'when there is one association, to a new record' do
|
127
|
+
let(:new_hero) { Hero.new }
|
128
|
+
let(:story_arc) { StoryArc.new(character: new_hero) }
|
129
|
+
|
130
|
+
its(:associations) { should match_associations(:hero, :villain) }
|
131
|
+
its(:active_association) { be_association(:hero) }
|
132
|
+
its(:query_condition) { should == nil }
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Polymorpheus::Interface::HasManyAsPolymorph do
|
4
|
+
before do
|
5
|
+
create_table :story_arcs do |t|
|
6
|
+
t.references :hero
|
7
|
+
t.references :villain
|
8
|
+
t.references :battle
|
9
|
+
t.references :issue
|
10
|
+
end
|
11
|
+
create_table :battles
|
12
|
+
create_table :heros
|
13
|
+
create_table :issues
|
14
|
+
create_table :villains
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'sets conditions on association to ensure we retrieve correct result' do
|
18
|
+
hero = Hero.create!
|
19
|
+
hero.story_arcs.to_sql
|
20
|
+
.should match_sql(%{SELECT `story_arcs`.* FROM `story_arcs`
|
21
|
+
WHERE `story_arcs`.`hero_id` = #{hero.id}
|
22
|
+
AND `story_arcs`.`villain_id` IS NULL})
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'supports existing conditions on the association' do
|
26
|
+
villain = Villain.create!
|
27
|
+
villain.story_arcs.to_sql
|
28
|
+
.should match_sql(%{SELECT `story_arcs`.* FROM `story_arcs`
|
29
|
+
WHERE `story_arcs`.`villain_id` = #{villain.id}
|
30
|
+
AND `story_arcs`.`hero_id` IS NULL
|
31
|
+
ORDER BY id DESC})
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'returns the correct result when used with new records' do
|
35
|
+
villain = Villain.create!
|
36
|
+
story_arc = StoryArc.create!(villain: villain, issue_id: 10)
|
37
|
+
Hero.new.story_arcs.where(issue_id: 10).should == []
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'sets conditions on associations with enough specificity that they work
|
41
|
+
in conjunction with has_many :through relationships' do
|
42
|
+
hero = Hero.create!
|
43
|
+
hero.battles.to_sql
|
44
|
+
.should match_sql(%{SELECT `battles`.* FROM `battles`
|
45
|
+
INNER JOIN `story_arcs`
|
46
|
+
ON `battles`.`id` = `story_arcs`.`battle_id`
|
47
|
+
WHERE `story_arcs`.`hero_id` = #{hero.id}
|
48
|
+
AND `story_arcs`.`villain_id` IS NULL})
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'uses the correct association table name when used in conjunction with a
|
52
|
+
join condition' do
|
53
|
+
battle = Battle.create!
|
54
|
+
battle.heros.to_sql
|
55
|
+
.should match_sql(%{SELECT `heros`.* FROM `heros`
|
56
|
+
INNER JOIN `story_arcs`
|
57
|
+
ON `heros`.`id` = `story_arcs`.`hero_id`
|
58
|
+
WHERE `story_arcs`.`battle_id` = #{battle.id}})
|
59
|
+
|
60
|
+
battle.heros.joins(:story_arcs).to_sql
|
61
|
+
.should match_sql(%{SELECT `heros`.* FROM `heros`
|
62
|
+
INNER JOIN `story_arcs` `story_arcs_heros`
|
63
|
+
ON `story_arcs_heros`.`hero_id` = `heros`.`id`
|
64
|
+
AND `story_arcs_heros`.`villain_id` IS NULL
|
65
|
+
INNER JOIN `story_arcs`
|
66
|
+
ON `heros`.`id` = `story_arcs`.`hero_id`
|
67
|
+
WHERE `story_arcs`.`battle_id` = #{battle.id}})
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Polymorpheus::Interface::ValidatesPolymorph do
|
4
|
+
let(:hero) { Hero.create! }
|
5
|
+
let(:villain) { Villain.create! }
|
6
|
+
|
7
|
+
before do
|
8
|
+
create_table(:story_arcs) do |t|
|
9
|
+
t.references :hero
|
10
|
+
t.references :villain
|
11
|
+
end
|
12
|
+
create_table(:heros)
|
13
|
+
create_table(:villains)
|
14
|
+
end
|
15
|
+
|
16
|
+
specify { StoryArc.new(character: hero).valid?.should == true }
|
17
|
+
specify { StoryArc.new(character: villain).valid?.should == true }
|
18
|
+
specify { StoryArc.new(hero_id: hero.id).valid?.should == true }
|
19
|
+
specify { StoryArc.new(hero: hero).valid?.should == true }
|
20
|
+
specify { StoryArc.new(hero: Hero.new).valid?.should == true }
|
21
|
+
|
22
|
+
it 'is invalid if no association is specified' do
|
23
|
+
story_arc = StoryArc.new
|
24
|
+
story_arc.valid?.should == false
|
25
|
+
story_arc.errors[:base].should ==
|
26
|
+
["You must specify exactly one of the following: {hero, villain}"]
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'is invalid if multiple associations are specified' do
|
30
|
+
story_arc = StoryArc.new(hero_id: hero.id, villain_id: villain.id)
|
31
|
+
story_arc.valid?.should == false
|
32
|
+
story_arc.errors[:base].should ==
|
33
|
+
["You must specify exactly one of the following: {hero, villain}"]
|
34
|
+
end
|
35
|
+
end
|
data/spec/interface_spec.rb
CHANGED
@@ -1,215 +1,27 @@
|
|
1
|
-
require 'active_record'
|
2
|
-
require 'polymorpheus'
|
3
1
|
require 'spec_helper'
|
4
|
-
require 'support/class_defs'
|
5
2
|
|
6
|
-
describe
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
describe Polymorpheus::Interface do
|
4
|
+
describe 'association options' do
|
5
|
+
it 'without options' do
|
6
|
+
create_table :drawings
|
7
|
+
create_table :books
|
8
|
+
create_table :binders
|
11
9
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
describe "setter methods for ActiveRecord objects" do
|
17
|
-
let(:story_arc) { StoryArc.new(attributes) }
|
18
|
-
let(:attributes) { {} }
|
19
|
-
|
20
|
-
it "sets the correct attribute value for the setter" do
|
21
|
-
story_arc.character = hero
|
22
|
-
story_arc.hero_id.should == hero.id
|
23
|
-
story_arc.villain_id.should == nil
|
24
|
-
end
|
25
|
-
|
26
|
-
it "sets competing associations to nil" do
|
27
|
-
story_arc.character = hero
|
28
|
-
story_arc.hero_id.should == hero.id
|
29
|
-
story_arc.character = villain
|
30
|
-
story_arc.villain_id.should == villain.id
|
31
|
-
story_arc.hero_id.should == nil
|
32
|
-
end
|
33
|
-
|
34
|
-
it "throws an error if the assigned object isn't a valid type" do
|
35
|
-
tree = Tree.create!
|
36
|
-
expect { story_arc.character = tree }
|
37
|
-
.to raise_error(Polymorpheus::Interface::InvalidTypeError,
|
38
|
-
"Invalid type. Must be one of {hero, villain}")
|
39
|
-
end
|
40
|
-
|
41
|
-
it "does not throw an error if the assigned object is a subclass of a
|
42
|
-
valid type" do
|
43
|
-
expect { story_arc.character = superhero }.not_to raise_error
|
44
|
-
story_arc.hero_id.should == superhero.id
|
45
|
-
end
|
46
|
-
|
47
|
-
it "does not throw an error if the assigned object is a descendant of a
|
48
|
-
valid type" do
|
49
|
-
expect { story_arc.character = alien_demigod }.not_to raise_error
|
50
|
-
story_arc.hero_id.should == alien_demigod.id
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
describe "setter methods for objects inheriting from ActiveRecord objects" do
|
55
|
-
let(:superpower) { Superpower.new }
|
56
|
-
|
57
|
-
it "throws an error if the assigned object is an instance of the parent
|
58
|
-
ActiveRecord class" do
|
59
|
-
expect { superpower.wielder = hero }.to raise_error(
|
60
|
-
Polymorpheus::Interface::InvalidTypeError,
|
61
|
-
"Invalid type. Must be one of {superhero, supervillain}"
|
62
|
-
)
|
10
|
+
Drawing.new.association(:book).reflection.inverse_of.should == nil
|
11
|
+
Drawing.new.association(:binder).reflection.inverse_of.should == nil
|
12
|
+
Book.new.association(:drawings).reflection.inverse_of.should == nil
|
13
|
+
Binder.new.association(:drawings).reflection.inverse_of.should == nil
|
63
14
|
end
|
64
15
|
|
65
|
-
it
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
it "works if the assigned object is an instance of a child class" do
|
71
|
-
expect { superpower.wielder = alien_demigod }.not_to raise_error
|
72
|
-
superpower.superhero_id.should == alien_demigod.id
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
describe '#polymorpheus exposed interface method' do
|
77
|
-
subject(:interface) { story_arc.polymorpheus }
|
78
|
-
|
79
|
-
context 'when there is no relationship defined' do
|
80
|
-
let(:story_arc) { StoryArc.new }
|
81
|
-
|
82
|
-
its(:associations) { should match_associations(:hero, :villain) }
|
83
|
-
its(:active_association) { should == nil }
|
84
|
-
its(:query_condition) { should == nil }
|
85
|
-
end
|
86
|
-
|
87
|
-
context 'when there is are multiple relationships defined' do
|
88
|
-
let(:story_arc) { StoryArc.new(hero_id: hero.id, villain_id: villain.id) }
|
16
|
+
it 'with options' do
|
17
|
+
create_table :pictures
|
18
|
+
create_table :web_pages
|
19
|
+
create_table :printed_works
|
89
20
|
|
90
|
-
|
91
|
-
|
92
|
-
|
21
|
+
Picture.new.association(:web_page).reflection.inverse_of.name.should == :pictures
|
22
|
+
Picture.new.association(:printed_work).reflection.inverse_of.name.should == :pictures
|
23
|
+
WebPage.new.association(:pictures).reflection.inverse_of.name.should == :web_page
|
24
|
+
PrintedWork.new.association(:pictures).reflection.inverse_of.name.should == :printed_work
|
93
25
|
end
|
94
|
-
|
95
|
-
context 'when there is one relationship defined through the id value' do
|
96
|
-
let(:story_arc) { StoryArc.new(hero_id: hero.id) }
|
97
|
-
|
98
|
-
its(:associations) { should match_associations(:hero, :villain) }
|
99
|
-
its(:active_association) { be_association(:hero) }
|
100
|
-
its(:query_condition) { should == { 'hero_id' => hero.id } }
|
101
|
-
end
|
102
|
-
|
103
|
-
context 'when there is one relationship defined through the setter' do
|
104
|
-
let(:story_arc) { StoryArc.new(character: hero) }
|
105
|
-
|
106
|
-
its(:associations) { should match_associations(:hero, :villain) }
|
107
|
-
its(:active_association) { be_association(:hero) }
|
108
|
-
its(:query_condition) { should == { 'hero_id' => hero.id } }
|
109
|
-
end
|
110
|
-
|
111
|
-
context 'when there is one association, to a new record' do
|
112
|
-
let(:new_hero) { Hero.new }
|
113
|
-
let(:story_arc) { StoryArc.new(character: new_hero) }
|
114
|
-
|
115
|
-
its(:associations) { should match_associations(:hero, :villain) }
|
116
|
-
its(:active_association) { be_association(:hero) }
|
117
|
-
its(:query_condition) { should == nil }
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
describe '.has_many_as_polymorph' do
|
123
|
-
it 'sets conditions on association to ensure we retrieve correct result' do
|
124
|
-
hero = Hero.create!
|
125
|
-
hero.story_arcs.to_sql
|
126
|
-
.should match_sql(%{SELECT `story_arcs`.* FROM `story_arcs`
|
127
|
-
WHERE `story_arcs`.`hero_id` = #{hero.id}
|
128
|
-
AND `story_arcs`.`villain_id` IS NULL})
|
129
|
-
end
|
130
|
-
|
131
|
-
it 'supports existing conditions on the association' do
|
132
|
-
villain = Villain.create!
|
133
|
-
villain.story_arcs.to_sql
|
134
|
-
.should match_sql(%{SELECT `story_arcs`.* FROM `story_arcs`
|
135
|
-
WHERE `story_arcs`.`villain_id` = #{villain.id}
|
136
|
-
AND `story_arcs`.`hero_id` IS NULL
|
137
|
-
ORDER BY id DESC})
|
138
|
-
end
|
139
|
-
|
140
|
-
it 'returns the correct result when used with new records' do
|
141
|
-
villain = Villain.create!
|
142
|
-
story_arc = StoryArc.create!(villain: villain, issue_id: 10)
|
143
|
-
Hero.new.story_arcs.where(issue_id: 10).should == []
|
144
|
-
end
|
145
|
-
|
146
|
-
it 'sets conditions on associations with enough specificity that they work
|
147
|
-
in conjunction with has_many :through relationships' do
|
148
|
-
hero = Hero.create!
|
149
|
-
hero.battles.to_sql
|
150
|
-
.should match_sql(%{SELECT `battles`.* FROM `battles`
|
151
|
-
INNER JOIN `story_arcs`
|
152
|
-
ON `battles`.`id` = `story_arcs`.`battle_id`
|
153
|
-
WHERE `story_arcs`.`hero_id` = 16
|
154
|
-
AND `story_arcs`.`villain_id` IS NULL})
|
155
|
-
end
|
156
|
-
|
157
|
-
it 'uses the correct association table name when used in conjunction with a
|
158
|
-
join condition' do
|
159
|
-
battle = Battle.create!
|
160
|
-
battle.heros.to_sql
|
161
|
-
.should match_sql(%{SELECT `heros`.* FROM `heros`
|
162
|
-
INNER JOIN `story_arcs`
|
163
|
-
ON `heros`.`id` = `story_arcs`.`hero_id`
|
164
|
-
WHERE `story_arcs`.`battle_id` = #{battle.id}})
|
165
|
-
|
166
|
-
battle.heros.joins(:story_arcs).to_sql
|
167
|
-
.should match_sql(%{SELECT `heros`.* FROM `heros`
|
168
|
-
INNER JOIN `story_arcs` `story_arcs_heros`
|
169
|
-
ON `story_arcs_heros`.`hero_id` = `heros`.`id`
|
170
|
-
AND `story_arcs_heros`.`villain_id` IS NULL
|
171
|
-
INNER JOIN `story_arcs`
|
172
|
-
ON `heros`.`id` = `story_arcs`.`hero_id`
|
173
|
-
WHERE `story_arcs`.`battle_id` = #{battle.id}})
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
describe '.validates_polymorph' do
|
178
|
-
let(:hero) { Hero.create! }
|
179
|
-
let(:villain) { Villain.create! }
|
180
|
-
|
181
|
-
specify { StoryArc.new(character: hero).valid?.should == true }
|
182
|
-
specify { StoryArc.new(character: villain).valid?.should == true }
|
183
|
-
specify { StoryArc.new(hero_id: hero.id).valid?.should == true }
|
184
|
-
specify { StoryArc.new(hero: hero).valid?.should == true }
|
185
|
-
specify { StoryArc.new(hero: Hero.new).valid?.should == true }
|
186
|
-
|
187
|
-
it 'is invalid if no association is specified' do
|
188
|
-
story_arc = StoryArc.new
|
189
|
-
story_arc.valid?.should == false
|
190
|
-
story_arc.errors[:base].should ==
|
191
|
-
["You must specify exactly one of the following: {hero, villain}"]
|
192
|
-
end
|
193
|
-
|
194
|
-
it 'is invalid if multiple associations are specified' do
|
195
|
-
story_arc = StoryArc.new(hero_id: hero.id, villain_id: villain.id)
|
196
|
-
story_arc.valid?.should == false
|
197
|
-
story_arc.errors[:base].should ==
|
198
|
-
["You must specify exactly one of the following: {hero, villain}"]
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
describe 'association options' do
|
203
|
-
it 'without options' do
|
204
|
-
Drawing.new.association(:book).reflection.inverse_of.should == nil
|
205
|
-
Drawing.new.association(:binder).reflection.inverse_of.should == nil
|
206
|
-
Book.new.association(:drawings).reflection.inverse_of.should == nil
|
207
|
-
Binder.new.association(:drawings).reflection.inverse_of.should == nil
|
208
|
-
end
|
209
|
-
it 'with options' do
|
210
|
-
Picture.new.association(:web_page).reflection.inverse_of.name.should == :pictures
|
211
|
-
Picture.new.association(:printed_work).reflection.inverse_of.name.should == :pictures
|
212
|
-
WebPage.new.association(:pictures).reflection.inverse_of.name.should == :web_page
|
213
|
-
PrintedWork.new.association(:pictures).reflection.inverse_of.name.should == :printed_work
|
214
26
|
end
|
215
27
|
end
|