granite-form 0.1.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +1 -2
- data/.github/workflows/{ci.yml → ruby.yml} +22 -4
- data/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +3 -3
- data/Appraisals +1 -2
- data/CHANGELOG.md +14 -0
- data/README.md +0 -2
- data/Rakefile +4 -0
- data/docker-compose.yml +14 -0
- data/gemfiles/rails.5.0.gemfile +0 -1
- data/gemfiles/rails.5.1.gemfile +0 -1
- data/gemfiles/rails.5.2.gemfile +0 -1
- data/granite-form.gemspec +16 -15
- data/lib/granite/form/active_record/associations.rb +1 -1
- data/lib/granite/form/base.rb +1 -2
- data/lib/granite/form/config.rb +10 -10
- data/lib/granite/form/errors.rb +0 -15
- data/lib/granite/form/model/associations/base.rb +0 -4
- data/lib/granite/form/model/associations/collection/embedded.rb +2 -1
- data/lib/granite/form/model/associations/collection/proxy.rb +1 -1
- data/lib/granite/form/model/associations/embeds_any.rb +7 -0
- data/lib/granite/form/model/associations/embeds_many.rb +9 -58
- data/lib/granite/form/model/associations/embeds_one.rb +7 -36
- data/lib/granite/form/model/associations/nested_attributes.rb +8 -8
- data/lib/granite/form/model/associations/persistence_adapters/active_record.rb +0 -4
- data/lib/granite/form/model/associations/persistence_adapters/base.rb +0 -4
- data/lib/granite/form/model/associations/references_many.rb +0 -32
- data/lib/granite/form/model/associations/references_one.rb +0 -28
- data/lib/granite/form/model/associations/reflections/embeds_any.rb +1 -1
- data/lib/granite/form/model/associations/reflections/references_any.rb +0 -4
- data/lib/granite/form/model/associations/reflections/references_many.rb +3 -1
- data/lib/granite/form/model/associations/reflections/references_one.rb +3 -3
- data/lib/granite/form/model/associations/reflections/singular.rb +0 -8
- data/lib/granite/form/model/associations.rb +0 -6
- data/lib/granite/form/model/attributes/attribute.rb +1 -1
- data/lib/granite/form/model/attributes/base.rb +14 -17
- data/lib/granite/form/model/attributes/collection.rb +1 -1
- data/lib/granite/form/model/attributes/dictionary.rb +1 -1
- data/lib/granite/form/model/attributes/localized.rb +1 -1
- data/lib/granite/form/model/attributes/reference_many.rb +1 -1
- data/lib/granite/form/model/attributes/reference_one.rb +1 -9
- data/lib/granite/form/model/attributes/reflections/attribute.rb +0 -6
- data/lib/granite/form/model/attributes/reflections/base.rb +9 -12
- data/lib/granite/form/model/attributes/reflections/reference_one.rb +0 -10
- data/lib/granite/form/model/persistence.rb +1 -19
- data/lib/granite/form/model/validations/nested.rb +1 -1
- data/lib/granite/form/model.rb +0 -2
- data/lib/granite/form/types/active_support/time_zone.rb +22 -0
- data/lib/granite/form/types/array.rb +17 -0
- data/lib/granite/form/types/big_decimal.rb +15 -0
- data/lib/granite/form/types/boolean.rb +38 -0
- data/lib/granite/form/types/date.rb +15 -0
- data/lib/granite/form/types/date_time.rb +15 -0
- data/lib/granite/form/types/float.rb +15 -0
- data/lib/granite/form/types/hash_with_action_controller_parameters.rb +18 -0
- data/lib/granite/form/types/integer.rb +13 -0
- data/lib/granite/form/types/object.rb +30 -0
- data/lib/granite/form/types/string.rb +13 -0
- data/lib/granite/form/types/time.rb +15 -0
- data/lib/granite/form/types/uuid.rb +22 -0
- data/lib/granite/form/types.rb +15 -0
- data/lib/granite/form/version.rb +1 -1
- data/lib/granite/form.rb +19 -118
- data/spec/{lib/granite → granite}/form/active_record/associations_spec.rb +16 -18
- data/spec/{lib/granite → granite}/form/active_record/nested_attributes_spec.rb +0 -1
- data/spec/{lib/granite → granite}/form/config_spec.rb +22 -10
- data/spec/granite/form/extensions_spec.rb +12 -0
- data/spec/{lib/granite → granite}/form/model/associations/embeds_many_spec.rb +29 -305
- data/spec/{lib/granite → granite}/form/model/associations/embeds_one_spec.rb +27 -212
- data/spec/granite/form/model/associations/nested_attributes_spec.rb +23 -0
- data/spec/{lib/granite → granite}/form/model/associations/persistence_adapters/active_record_spec.rb +0 -0
- data/spec/granite/form/model/associations/references_many_spec.rb +251 -0
- data/spec/granite/form/model/associations/references_one_spec.rb +173 -0
- data/spec/{lib/granite → granite}/form/model/associations/reflections/embeds_any_spec.rb +1 -2
- data/spec/{lib/granite → granite}/form/model/associations/reflections/embeds_many_spec.rb +18 -26
- data/spec/{lib/granite → granite}/form/model/associations/reflections/embeds_one_spec.rb +16 -23
- data/spec/{lib/granite → granite}/form/model/associations/reflections/references_many_spec.rb +1 -1
- data/spec/{lib/granite → granite}/form/model/associations/reflections/references_one_spec.rb +1 -22
- data/spec/{lib/granite → granite}/form/model/associations/validations_spec.rb +0 -3
- data/spec/{lib/granite → granite}/form/model/associations_spec.rb +3 -24
- data/spec/{lib/granite → granite}/form/model/attributes/attribute_spec.rb +4 -46
- data/spec/{lib/granite → granite}/form/model/attributes/base_spec.rb +11 -2
- data/spec/{lib/granite → granite}/form/model/attributes/collection_spec.rb +0 -0
- data/spec/{lib/granite → granite}/form/model/attributes/dictionary_spec.rb +0 -0
- data/spec/{lib/granite → granite}/form/model/attributes/localized_spec.rb +1 -1
- data/spec/{lib/granite → granite}/form/model/attributes/reflections/attribute_spec.rb +0 -12
- data/spec/{lib/granite → granite}/form/model/attributes/reflections/base_spec.rb +1 -1
- data/spec/{lib/granite → granite}/form/model/attributes/reflections/collection_spec.rb +0 -0
- data/spec/{lib/granite → granite}/form/model/attributes/reflections/dictionary_spec.rb +0 -0
- data/spec/{lib/granite → granite}/form/model/attributes/reflections/localized_spec.rb +0 -0
- data/spec/{lib/granite → granite}/form/model/attributes/reflections/represents_spec.rb +0 -0
- data/spec/{lib/granite → granite}/form/model/attributes/represents_spec.rb +0 -0
- data/spec/{lib/granite → granite}/form/model/attributes_spec.rb +0 -0
- data/spec/{lib/granite → granite}/form/model/conventions_spec.rb +0 -0
- data/spec/{lib/granite → granite}/form/model/dirty_spec.rb +1 -1
- data/spec/{lib/granite → granite}/form/model/persistence_spec.rb +0 -2
- data/spec/{lib/granite → granite}/form/model/primary_spec.rb +1 -1
- data/spec/{lib/granite → granite}/form/model/representation_spec.rb +0 -0
- data/spec/{lib/granite → granite}/form/model/scopes_spec.rb +0 -0
- data/spec/{lib/granite → granite}/form/model/validations/associated_spec.rb +2 -4
- data/spec/{lib/granite → granite}/form/model/validations/nested_spec.rb +57 -15
- data/spec/{lib/granite → granite}/form/model/validations_spec.rb +0 -0
- data/spec/{lib/granite → granite}/form/model_spec.rb +0 -0
- data/spec/granite/form/types/active_support/time_zone_spec.rb +24 -0
- data/spec/granite/form/types/array_spec.rb +13 -0
- data/spec/granite/form/types/big_decimal_spec.rb +19 -0
- data/spec/granite/form/types/boolean_spec.rb +21 -0
- data/spec/granite/form/types/date_spec.rb +18 -0
- data/spec/granite/form/types/date_time_spec.rb +20 -0
- data/spec/granite/form/types/float_spec.rb +19 -0
- data/spec/granite/form/types/hash_with_action_controller_parameters_spec.rb +22 -0
- data/spec/granite/form/types/integer_spec.rb +18 -0
- data/spec/granite/form/types/object_spec.rb +40 -0
- data/spec/granite/form/types/string_spec.rb +13 -0
- data/spec/granite/form/types/time_spec.rb +31 -0
- data/spec/granite/form/types/uuid_spec.rb +21 -0
- data/spec/{lib/granite → granite}/form_spec.rb +0 -0
- data/spec/spec_helper.rb +0 -15
- data/spec/support/active_record.rb +20 -0
- data/spec/{shared → support/shared}/nested_attribute_examples.rb +3 -21
- data/spec/support/shared/type_examples.rb +7 -0
- metadata +173 -123
- data/.github/workflows/main.yml +0 -29
- data/gemfiles/rails.4.2.gemfile +0 -15
- data/lib/granite/form/model/callbacks.rb +0 -72
- data/lib/granite/form/model/lifecycle.rb +0 -309
- data/spec/lib/granite/form/model/associations/nested_attributes_spec.rb +0 -119
- data/spec/lib/granite/form/model/associations/references_many_spec.rb +0 -572
- data/spec/lib/granite/form/model/associations/references_one_spec.rb +0 -445
- data/spec/lib/granite/form/model/callbacks_spec.rb +0 -337
- data/spec/lib/granite/form/model/lifecycle_spec.rb +0 -356
- data/spec/lib/granite/form/model/typecasting_spec.rb +0 -193
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Granite::Form::Model::Associations::ReferencesOne do
|
4
|
+
before do
|
5
|
+
stub_class(:author, ActiveRecord::Base) do
|
6
|
+
validates :name, presence: true
|
7
|
+
end
|
8
|
+
|
9
|
+
stub_model(:book) do
|
10
|
+
include Granite::Form::Model::Persistence
|
11
|
+
include Granite::Form::Model::Associations
|
12
|
+
|
13
|
+
attribute :title, String
|
14
|
+
references_one :author
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:author) { Author.create!(name: 'Johny') }
|
19
|
+
let(:other) { Author.create!(name: 'Other') }
|
20
|
+
let(:book) { Book.new }
|
21
|
+
let(:association) { book.association(:author) }
|
22
|
+
|
23
|
+
let(:existing_book) { Book.instantiate title: 'My Life', author_id: author.id }
|
24
|
+
let(:existing_association) { existing_book.association(:author) }
|
25
|
+
|
26
|
+
describe 'book#association' do
|
27
|
+
specify { expect(association).to be_a described_class }
|
28
|
+
specify { expect(association).to eq(book.association(:author)) }
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'book#inspect' do
|
32
|
+
specify { expect(existing_book.inspect).to eq(<<~STR.chomp) }
|
33
|
+
#<Book author: #<ReferencesOne #{author.inspect}>, title: "My Life", author_id: #{author.id}>
|
34
|
+
STR
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#target' do
|
38
|
+
specify { expect(association.target).to be_nil }
|
39
|
+
specify { expect(existing_association.target).to eq(existing_book.author) }
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#loaded?' do
|
43
|
+
let(:new_author) { Author.create(name: 'Morty') }
|
44
|
+
|
45
|
+
specify { expect(association.loaded?).to eq(false) }
|
46
|
+
specify { expect { association.target }.to change { association.loaded? }.to(true) }
|
47
|
+
specify { expect { association.replace(new_author) }.to change { association.loaded? }.to(true) }
|
48
|
+
specify { expect { association.replace(nil) }.to change { association.loaded? }.to(true) }
|
49
|
+
specify { expect { existing_association.replace(new_author) }.to change { existing_association.loaded? }.to(true) }
|
50
|
+
specify { expect { existing_association.replace(nil) }.to change { existing_association.loaded? }.to(true) }
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#reload' do
|
54
|
+
specify { expect(association.reload).to be_nil }
|
55
|
+
|
56
|
+
specify { expect(existing_association.reload).to be_a Author }
|
57
|
+
specify { expect(existing_association.reload).to be_persisted }
|
58
|
+
|
59
|
+
context do
|
60
|
+
before { existing_association.reader.name = 'New' }
|
61
|
+
specify do
|
62
|
+
expect { existing_association.reload }
|
63
|
+
.to change { existing_association.reader.name }
|
64
|
+
.from('New').to('Johny')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#reader' do
|
70
|
+
specify { expect(association.reader).to be_nil }
|
71
|
+
|
72
|
+
specify { expect(existing_association.reader).to be_a Author }
|
73
|
+
specify { expect(existing_association.reader).to be_persisted }
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#default' do
|
77
|
+
before { Book.references_one :author, default: ->(_book) { author.id } }
|
78
|
+
let(:existing_book) { Book.instantiate title: 'My Life' }
|
79
|
+
|
80
|
+
specify { expect(association.target).to eq(author) }
|
81
|
+
specify { expect { association.replace(other) }.to change { association.target }.to(other) }
|
82
|
+
specify { expect { association.replace(nil) }.to change { association.target }.to be_nil }
|
83
|
+
|
84
|
+
specify { expect(existing_association.target).to be_nil }
|
85
|
+
specify { expect { existing_association.replace(other) }.to change { existing_association.target }.to(other) }
|
86
|
+
specify { expect { existing_association.replace(nil) }.not_to change { existing_association.target } }
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#writer' do
|
90
|
+
context 'new owner' do
|
91
|
+
let(:new_author) { Author.new(name: 'Morty') }
|
92
|
+
|
93
|
+
let(:book) do
|
94
|
+
Book.new.tap do |book|
|
95
|
+
book.send(:mark_persisted!)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
specify do
|
100
|
+
expect { association.writer(nil) }
|
101
|
+
.not_to change { book.author_id }
|
102
|
+
end
|
103
|
+
specify do
|
104
|
+
expect { association.writer(new_author) }
|
105
|
+
.to change { muffle(NoMethodError) { association.reader.name } }
|
106
|
+
.from(nil).to('Morty')
|
107
|
+
end
|
108
|
+
specify do
|
109
|
+
expect { association.writer(new_author) }
|
110
|
+
.not_to change { book.author_id }.from(nil)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'persisted owner' do
|
115
|
+
let(:new_author) { Author.create!(name: 'Morty') }
|
116
|
+
|
117
|
+
specify do
|
118
|
+
expect { association.writer(stub_model(:dummy).new) }
|
119
|
+
.to raise_error Granite::Form::AssociationTypeMismatch
|
120
|
+
end
|
121
|
+
|
122
|
+
specify { expect(association.writer(nil)).to be_nil }
|
123
|
+
specify { expect(association.writer(new_author)).to eq(new_author) }
|
124
|
+
specify do
|
125
|
+
expect { association.writer(nil) }
|
126
|
+
.not_to change { book.read_attribute(:author_id) }
|
127
|
+
end
|
128
|
+
specify do
|
129
|
+
expect { association.writer(new_author) }
|
130
|
+
.to change { association.reader.try(:attributes) }.from(nil).to('id' => new_author.id, 'name' => 'Morty')
|
131
|
+
end
|
132
|
+
specify do
|
133
|
+
expect { association.writer(new_author) }
|
134
|
+
.to change { book.read_attribute(:author_id) }
|
135
|
+
end
|
136
|
+
|
137
|
+
context do
|
138
|
+
before do
|
139
|
+
stub_class(:dummy, ActiveRecord::Base) do
|
140
|
+
self.table_name = :authors
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
specify do
|
145
|
+
expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.writer(Dummy.new) } }
|
146
|
+
.not_to change { existing_book.read_attribute(:author_id) }
|
147
|
+
end
|
148
|
+
specify do
|
149
|
+
expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.writer(Dummy.new) } }
|
150
|
+
.not_to change { existing_association.reader }
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
specify { expect(existing_association.writer(nil)).to be_nil }
|
155
|
+
specify { expect(existing_association.writer(new_author)).to eq(new_author) }
|
156
|
+
specify do
|
157
|
+
expect { existing_association.writer(nil) }
|
158
|
+
.to change { existing_book.read_attribute(:author_id) }
|
159
|
+
.from(author.id).to(nil)
|
160
|
+
end
|
161
|
+
specify do
|
162
|
+
expect { existing_association.writer(new_author) }
|
163
|
+
.to change { existing_association.reader.try(:attributes) }
|
164
|
+
.from('id' => author.id, 'name' => 'Johny').to('id' => new_author.id, 'name' => 'Morty')
|
165
|
+
end
|
166
|
+
specify do
|
167
|
+
expect { existing_association.writer(new_author) }
|
168
|
+
.to change { existing_book.read_attribute(:author_id) }
|
169
|
+
.from(author.id).to(new_author.id)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -7,7 +7,6 @@ describe Granite::Form::Model::Associations::Reflections::EmbedsAny do
|
|
7
7
|
|
8
8
|
before do
|
9
9
|
stub_model(:project) do
|
10
|
-
include Granite::Form::Model::Lifecycle
|
11
10
|
attribute :title, String
|
12
11
|
end
|
13
12
|
stub_model(:user) do
|
@@ -20,7 +19,7 @@ describe Granite::Form::Model::Associations::Reflections::EmbedsAny do
|
|
20
19
|
|
21
20
|
it { is_expected.to be_a(Granite::Form::Model) }
|
22
21
|
it { is_expected.to be_a(Granite::Form::Model::Primary) }
|
23
|
-
it { is_expected.to be_a(Granite::Form::Model::
|
22
|
+
it { is_expected.to be_a(Granite::Form::Model::Persistence) }
|
24
23
|
it { is_expected.to be_a(Granite::Form::Model::Associations) }
|
25
24
|
|
26
25
|
context 'when Granite::Form.base_concern is defined' do
|
@@ -3,7 +3,8 @@ require 'spec_helper'
|
|
3
3
|
describe Granite::Form::Model::Associations::Reflections::EmbedsMany do
|
4
4
|
before do
|
5
5
|
stub_model(:project) do
|
6
|
-
include Granite::Form::Model::
|
6
|
+
include Granite::Form::Model::Persistence
|
7
|
+
include Granite::Form::Model::Associations
|
7
8
|
attribute :title, String
|
8
9
|
end
|
9
10
|
stub_model(:user) do
|
@@ -24,24 +25,28 @@ describe Granite::Form::Model::Associations::Reflections::EmbedsMany do
|
|
24
25
|
attribute :name
|
25
26
|
embeds_many :projects,
|
26
27
|
read: lambda { |reflection, object|
|
27
|
-
value = object.
|
28
|
+
value = object.instance_variable_get("@_value_#{reflection.name}")
|
28
29
|
JSON.parse(value) if value.present?
|
29
30
|
},
|
30
31
|
write: lambda { |reflection, object, value|
|
31
|
-
|
32
|
+
value = value.to_json if value
|
33
|
+
object.instance_variable_set("@_value_#{reflection.name}", value)
|
32
34
|
}
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
|
-
let(:user) { User.
|
38
|
+
let(:user) { User.new }
|
37
39
|
let(:new_project1) { Project.new(title: 'Project 1') }
|
38
40
|
let(:new_project2) { Project.new(title: 'Project 2') }
|
39
41
|
|
40
42
|
specify do
|
41
|
-
expect
|
42
|
-
.
|
43
|
-
.
|
44
|
-
|
43
|
+
expect do
|
44
|
+
user.projects = [new_project1, new_project2]
|
45
|
+
user.association(:projects).sync
|
46
|
+
end
|
47
|
+
.to change { user.projects(true) }
|
48
|
+
.from([])
|
49
|
+
.to([have_attributes(title: 'Project 1'), have_attributes(title: 'Project 2')])
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
@@ -54,23 +59,10 @@ describe Granite::Form::Model::Associations::Reflections::EmbedsMany do
|
|
54
59
|
specify { expect { user.projects.build(title: 'Project') }.to change { user.projects }.from([]).to([project]) }
|
55
60
|
end
|
56
61
|
|
57
|
-
describe '#create' do
|
58
|
-
let(:project) { Project.new title: 'Project' }
|
59
|
-
specify { expect(user.projects.create(title: 'Project')).to eq(project) }
|
60
|
-
specify { expect { user.projects.create(title: 'Project') }.to change { user.projects }.from([]).to([project]) }
|
61
|
-
end
|
62
|
-
|
63
|
-
describe '#create!' do
|
64
|
-
let(:project) { Project.new title: 'Project' }
|
65
|
-
specify { expect(user.projects.create!(title: 'Project')).to eq(project) }
|
66
|
-
specify { expect { user.projects.create!(title: 'Project') }.to change { user.projects }.from([]).to([project]) }
|
67
|
-
end
|
68
|
-
|
69
62
|
describe '#reload' do
|
70
63
|
let(:project) { Project.new title: 'Project' }
|
71
64
|
before do
|
72
|
-
user.
|
73
|
-
user.apply_association_changes!
|
65
|
+
user.write_attribute(:projects, [{title: 'Project'}])
|
74
66
|
end
|
75
67
|
before { user.projects.build }
|
76
68
|
|
@@ -120,8 +112,8 @@ describe Granite::Form::Model::Associations::Reflections::EmbedsMany do
|
|
120
112
|
|
121
113
|
specify { expect(User.reflect_on_association(:projects).klass).to eq(User::Project) }
|
122
114
|
specify { expect(User.new.projects).to eq([]) }
|
123
|
-
specify { expect(User.new.tap { |u| u.projects.
|
124
|
-
specify { expect(User.new.tap { |u| u.projects.
|
115
|
+
specify { expect(User.new.tap { |u| u.projects.build(title: 'Project') }.projects).to be_a(Granite::Form::Model::Associations::Collection::Embedded) }
|
116
|
+
specify { expect(User.new.tap { |u| u.projects.build(title: 'Project') }.projects).to match([have_attributes(title: 'Project')]) }
|
125
117
|
end
|
126
118
|
|
127
119
|
context do
|
@@ -138,8 +130,8 @@ describe Granite::Form::Model::Associations::Reflections::EmbedsMany do
|
|
138
130
|
|
139
131
|
specify { expect(User.reflect_on_association(:projects).klass).to eq(User::Project) }
|
140
132
|
specify { expect(User.new.projects).to eq([]) }
|
141
|
-
specify { expect(User.new.tap { |u| u.projects.
|
142
|
-
specify { expect(User.new.tap { |u| u.projects.
|
133
|
+
specify { expect(User.new.tap { |u| u.projects.build(title: 'Project') }.projects).to be_a(Granite::Form::Model::Associations::Collection::Embedded) }
|
134
|
+
specify { expect(User.new.tap { |u| u.projects.build(title: 'Project') }.projects).to match([have_attributes(title: 'Project', value: nil)]) }
|
143
135
|
end
|
144
136
|
end
|
145
137
|
end
|
@@ -3,7 +3,8 @@ require 'spec_helper'
|
|
3
3
|
describe Granite::Form::Model::Associations::Reflections::EmbedsOne do
|
4
4
|
before do
|
5
5
|
stub_model(:author) do
|
6
|
-
include Granite::Form::Model::
|
6
|
+
include Granite::Form::Model::Persistence
|
7
|
+
include Granite::Form::Model::Associations
|
7
8
|
attribute :name, String
|
8
9
|
end
|
9
10
|
|
@@ -27,22 +28,26 @@ describe Granite::Form::Model::Associations::Reflections::EmbedsOne do
|
|
27
28
|
attribute :title
|
28
29
|
embeds_one :author,
|
29
30
|
read: lambda { |reflection, object|
|
30
|
-
value = object.
|
31
|
+
value = object.instance_variable_get("@_value_#{reflection.name}")
|
31
32
|
JSON.parse(value) if value.present?
|
32
33
|
},
|
33
34
|
write: lambda { |reflection, object, value|
|
34
|
-
|
35
|
+
value = value.to_json if value
|
36
|
+
object.instance_variable_set("@_value_#{reflection.name}", value)
|
35
37
|
}
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
39
|
-
let(:book) { Book.
|
41
|
+
let(:book) { Book.new }
|
40
42
|
let(:author) { Author.new(name: 'Rick') }
|
41
43
|
|
42
44
|
specify do
|
43
|
-
expect
|
44
|
-
.
|
45
|
-
.
|
45
|
+
expect do
|
46
|
+
book.author = author
|
47
|
+
book.association(:author).sync
|
48
|
+
end
|
49
|
+
.to change { book.author(true) }
|
50
|
+
.from(nil).to(have_attributes(name: 'Rick'))
|
46
51
|
end
|
47
52
|
end
|
48
53
|
|
@@ -65,18 +70,6 @@ describe Granite::Form::Model::Associations::Reflections::EmbedsOne do
|
|
65
70
|
specify { expect { book.build_author(name: 'Author') }.to change { book.author }.from(nil).to(author) }
|
66
71
|
end
|
67
72
|
|
68
|
-
describe '#create_author' do
|
69
|
-
let(:author) { Author.new name: 'Author' }
|
70
|
-
specify { expect(book.create_author(name: 'Author')).to eq(author) }
|
71
|
-
specify { expect { book.create_author(name: 'Author') }.to change { book.author }.from(nil).to(author) }
|
72
|
-
end
|
73
|
-
|
74
|
-
describe '#create_author!' do
|
75
|
-
let(:author) { Author.new name: 'Author' }
|
76
|
-
specify { expect(book.create_author!(name: 'Author')).to eq(author) }
|
77
|
-
specify { expect { book.create_author!(name: 'Author') }.to change { book.author }.from(nil).to(author) }
|
78
|
-
end
|
79
|
-
|
80
73
|
context 'on the fly' do
|
81
74
|
context do
|
82
75
|
before do
|
@@ -92,8 +85,8 @@ describe Granite::Form::Model::Associations::Reflections::EmbedsOne do
|
|
92
85
|
|
93
86
|
specify { expect(Book.reflect_on_association(:author).klass).to eq(Book::Author) }
|
94
87
|
specify { expect(Book.new.author).to be_nil }
|
95
|
-
specify { expect(Book.new.tap { |b| b.
|
96
|
-
specify { expect(Book.new.tap { |b| b.
|
88
|
+
specify { expect(Book.new.tap { |b| b.build_author(name: 'Author') }.author).to be_a(Book::Author) }
|
89
|
+
specify { expect(Book.new.tap { |b| b.build_author(name: 'Author') }.author).to have_attributes(name: 'Author') }
|
97
90
|
end
|
98
91
|
|
99
92
|
context do
|
@@ -110,8 +103,8 @@ describe Granite::Form::Model::Associations::Reflections::EmbedsOne do
|
|
110
103
|
|
111
104
|
specify { expect(Book.reflect_on_association(:author).klass).to eq(Book::Author) }
|
112
105
|
specify { expect(Book.new.author).to be_nil }
|
113
|
-
specify { expect(Book.new.tap { |b| b.
|
114
|
-
specify { expect(Book.new.tap { |b| b.
|
106
|
+
specify { expect(Book.new.tap { |b| b.build_author(name: 'Author') }.author).to be_a(Book::Author) }
|
107
|
+
specify { expect(Book.new.tap { |b| b.build_author(name: 'Author') }.author).to have_attributes(name: 'Author', age: nil) }
|
115
108
|
end
|
116
109
|
end
|
117
110
|
end
|
data/spec/{lib/granite → granite}/form/model/associations/reflections/references_many_spec.rb
RENAMED
@@ -4,7 +4,7 @@ describe Granite::Form::Model::Associations::Reflections::ReferencesMany do
|
|
4
4
|
before do
|
5
5
|
stub_class(:author, ActiveRecord::Base) do
|
6
6
|
scope :name_starts_with_a, -> { name_starts_with('a') }
|
7
|
-
scope :name_starts_with, ->(letter) { where("name
|
7
|
+
scope :name_starts_with, ->(letter) { where("name ILIKE '#{letter}%'") }
|
8
8
|
end
|
9
9
|
|
10
10
|
stub_model(:book) do
|
data/spec/{lib/granite → granite}/form/model/associations/reflections/references_one_spec.rb
RENAMED
@@ -4,7 +4,7 @@ describe Granite::Form::Model::Associations::Reflections::ReferencesOne do
|
|
4
4
|
before do
|
5
5
|
stub_class(:author, ActiveRecord::Base) do
|
6
6
|
scope :name_starts_with_a, -> { name_starts_with('a') }
|
7
|
-
scope :name_starts_with, ->(letter) { where("name
|
7
|
+
scope :name_starts_with, ->(letter) { where("name ILIKE '#{letter}%'") }
|
8
8
|
end
|
9
9
|
|
10
10
|
stub_model(:book) do
|
@@ -263,25 +263,4 @@ describe Granite::Form::Model::Associations::Reflections::ReferencesOne do
|
|
263
263
|
specify { expect { book.author_id = nil }.to change { book.author }.from(other).to(nil) }
|
264
264
|
end
|
265
265
|
end
|
266
|
-
|
267
|
-
describe '#build_author' do
|
268
|
-
specify { expect(book.build_author(name: 'Author')).to be_a(Author) }
|
269
|
-
specify { expect(book.build_author(name: 'Author')).not_to be_persisted }
|
270
|
-
specify { expect { book.build_author(name: 'Author') }.to change { book.author }.from(nil).to(an_instance_of(Author)) }
|
271
|
-
specify { expect { book.build_author(name: 'Author') }.not_to change { book.author_id }.from(nil) }
|
272
|
-
end
|
273
|
-
|
274
|
-
describe '#create_author' do
|
275
|
-
specify { expect(book.create_author(name: 'Author')).to be_a(Author) }
|
276
|
-
specify { expect(book.create_author(name: 'Author')).to be_persisted }
|
277
|
-
specify { expect { book.create_author(name: 'Author') }.to change { book.author }.from(nil).to(an_instance_of(Author)) }
|
278
|
-
specify { expect { book.create_author(name: 'Author') }.to change { book.author_id }.from(nil).to(be_a(Integer)) }
|
279
|
-
end
|
280
|
-
|
281
|
-
describe '#create_author!' do
|
282
|
-
specify { expect(book.create_author!(name: 'Author')).to be_a(Author) }
|
283
|
-
specify { expect(book.create_author!(name: 'Author')).to be_persisted }
|
284
|
-
specify { expect { book.create_author!(name: 'Author') }.to change { book.author }.from(nil).to(an_instance_of(Author)) }
|
285
|
-
specify { expect { book.create_author!(name: 'Author') }.to change { book.author_id }.from(nil).to(be_a(Integer)) }
|
286
|
-
end
|
287
266
|
end
|
@@ -3,7 +3,6 @@ require 'spec_helper'
|
|
3
3
|
describe Granite::Form::Model::Associations::Validations do
|
4
4
|
before do
|
5
5
|
stub_model(:project) do
|
6
|
-
include Granite::Form::Model::Lifecycle
|
7
6
|
include Granite::Form::Model::Associations
|
8
7
|
include Granite::Form::Model::Associations::Validations
|
9
8
|
|
@@ -17,8 +16,6 @@ describe Granite::Form::Model::Associations::Validations do
|
|
17
16
|
end
|
18
17
|
|
19
18
|
stub_model(:profile) do
|
20
|
-
include Granite::Form::Model::Lifecycle
|
21
|
-
|
22
19
|
attribute :first_name, String
|
23
20
|
attribute :last_name, String
|
24
21
|
validates :first_name, presence: true
|
@@ -7,7 +7,7 @@ describe Granite::Form::Model::Associations do
|
|
7
7
|
include Granite::Form::Model::Associations
|
8
8
|
end
|
9
9
|
stub_model(:project) do
|
10
|
-
include Granite::Form::Model::
|
10
|
+
include Granite::Form::Model::Persistence
|
11
11
|
end
|
12
12
|
stub_model(:user, Nobody) do
|
13
13
|
include Granite::Form::Model::Associations
|
@@ -65,7 +65,7 @@ describe Granite::Form::Model::Associations do
|
|
65
65
|
context do
|
66
66
|
before do
|
67
67
|
stub_model(:project) do
|
68
|
-
include Granite::Form::Model::
|
68
|
+
include Granite::Form::Model::Persistence
|
69
69
|
include Granite::Form::Model::Associations
|
70
70
|
|
71
71
|
attribute :title, String
|
@@ -80,7 +80,7 @@ describe Granite::Form::Model::Associations do
|
|
80
80
|
end
|
81
81
|
|
82
82
|
stub_model(:profile) do
|
83
|
-
include Granite::Form::Model::
|
83
|
+
include Granite::Form::Model::Persistence
|
84
84
|
|
85
85
|
attribute :first_name, String
|
86
86
|
attribute :last_name, String
|
@@ -160,27 +160,6 @@ describe Granite::Form::Model::Associations do
|
|
160
160
|
specify { expect(user.association_names).to eq(%i[profile projects]) }
|
161
161
|
end
|
162
162
|
|
163
|
-
describe '#apply_association_changes!' do
|
164
|
-
let(:profile) { Profile.new first_name: 'Name' }
|
165
|
-
let(:project) { Project.new title: 'Project' }
|
166
|
-
let(:user) { User.new(profile: profile, projects: [project]) }
|
167
|
-
before { project.build_author(name: 'Author') }
|
168
|
-
|
169
|
-
specify do
|
170
|
-
expect { user.apply_association_changes! }.to change { user.attributes['profile'] }
|
171
|
-
.from(nil).to('first_name' => 'Name', 'last_name' => nil)
|
172
|
-
end
|
173
|
-
specify do
|
174
|
-
expect { user.apply_association_changes! }.to change { user.attributes['projects'] }
|
175
|
-
.from(nil).to([{'title' => 'Project', 'author' => {'name' => 'Author'}}])
|
176
|
-
end
|
177
|
-
|
178
|
-
context do
|
179
|
-
let(:project) { Project.new }
|
180
|
-
specify { expect { user.apply_association_changes! }.to raise_error Granite::Form::AssociationChangesNotApplied }
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
163
|
describe '#instantiate' do
|
185
164
|
before { User.send(:include, Granite::Form::Model::Persistence) }
|
186
165
|
let(:profile) { Profile.new first_name: 'Name' }
|
@@ -57,51 +57,6 @@ describe Granite::Form::Model::Attributes::Attribute do
|
|
57
57
|
specify { expect(attribute(default: false, type: Boolean).defaultize(nil)).to eq(false) }
|
58
58
|
end
|
59
59
|
|
60
|
-
describe '#typecast' do
|
61
|
-
context 'when Object' do
|
62
|
-
specify { expect(attribute.typecast(:hello)).to eq(:hello) }
|
63
|
-
end
|
64
|
-
|
65
|
-
context 'when Integer' do
|
66
|
-
specify { expect(attribute(type: Integer).typecast(42)).to eq(42) }
|
67
|
-
specify { expect(attribute(type: Integer).typecast('42')).to eq(42) }
|
68
|
-
end
|
69
|
-
|
70
|
-
context 'when Hash' do
|
71
|
-
let(:to_h) { {'x' => {'foo' => 'bar'}, 'y' => 2} }
|
72
|
-
let(:parameters) { ActionController::Parameters.new(to_h) }
|
73
|
-
|
74
|
-
before(:all) do
|
75
|
-
@default_hash_typecaster = Granite::Form.typecaster('Hash')
|
76
|
-
require 'action_controller'
|
77
|
-
Class.new(ActionController::Base)
|
78
|
-
@action_controller_hash_typecaster = Granite::Form.typecaster('Hash')
|
79
|
-
end
|
80
|
-
|
81
|
-
context 'when ActionController is loaded' do
|
82
|
-
before { Granite::Form.typecaster('Hash', &@action_controller_hash_typecaster) }
|
83
|
-
after { Granite::Form.typecaster('Hash', &@default_hash_typecaster) }
|
84
|
-
|
85
|
-
specify { expect(attribute(type: Hash).typecast(nil)).to be_nil }
|
86
|
-
specify { expect(attribute(type: Hash).typecast(to_h)).to eq(to_h) }
|
87
|
-
specify { expect(attribute(type: Hash).typecast(parameters)).to be_nil }
|
88
|
-
specify { expect(attribute(type: Hash).typecast(parameters.permit(:y, x: [:foo]))).to eq(to_h) }
|
89
|
-
end
|
90
|
-
|
91
|
-
context 'when ActionController is not loaded' do
|
92
|
-
before { Granite::Form.typecaster('Hash', &@default_hash_typecaster) }
|
93
|
-
|
94
|
-
specify { expect(attribute(type: Hash).typecast(nil)).to be_nil }
|
95
|
-
specify { expect(attribute(type: Hash).typecast(to_h)).to eq(to_h) }
|
96
|
-
if ActiveSupport.version > Gem::Version.new('4.3')
|
97
|
-
specify { expect(attribute(type: Hash).typecast(parameters.permit(:y, x: [:foo]))).to be_nil }
|
98
|
-
else
|
99
|
-
specify { expect(attribute(type: Hash).typecast(parameters.permit(:y, x: [:foo]))).to eq(to_h) }
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
60
|
describe '#enum' do
|
106
61
|
before { allow_any_instance_of(Dummy).to receive_messages(value: 1..5) }
|
107
62
|
|
@@ -144,7 +99,10 @@ describe Granite::Form::Model::Attributes::Attribute do
|
|
144
99
|
|
145
100
|
context 'integration' do
|
146
101
|
before do
|
147
|
-
|
102
|
+
config = Granite::Form::Config.send(:new)
|
103
|
+
config.types.merge! Granite::Form.config.types
|
104
|
+
allow(Granite::Form).to receive_messages(config: config)
|
105
|
+
|
148
106
|
Granite::Form.normalizer(:strip) { |value, _, _| value.strip }
|
149
107
|
Granite::Form.normalizer(:trim) do |value, options, _attribute|
|
150
108
|
value.first(length || options[:length] || 2)
|
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Granite::Form::Model::Attributes::Base do
|
4
|
+
let(:model) { Dummy.new }
|
5
|
+
|
4
6
|
before { stub_model(:dummy) }
|
5
7
|
|
6
8
|
def attribute(*args)
|
7
9
|
options = args.extract_options!
|
8
|
-
Dummy.add_attribute(Granite::Form::Model::Attributes::Reflections::Base, :field, options)
|
9
|
-
|
10
|
+
Dummy.add_attribute(Granite::Form::Model::Attributes::Reflections::Base, :field, options.reverse_merge(type: Object))
|
11
|
+
model.attribute(:field)
|
10
12
|
end
|
11
13
|
|
12
14
|
describe '#read' do
|
@@ -94,4 +96,11 @@ describe Granite::Form::Model::Attributes::Base do
|
|
94
96
|
specify { expect(attribute(readonly: -> { false })).not_to be_readonly }
|
95
97
|
specify { expect(attribute(readonly: -> { true })).to be_readonly }
|
96
98
|
end
|
99
|
+
|
100
|
+
describe '#type_definition' do
|
101
|
+
subject { attr.type_definition }
|
102
|
+
let(:attr) { attribute(type: String) }
|
103
|
+
|
104
|
+
it { is_expected.to have_attributes(type: String, reflection: subject.reflection, owner: model) }
|
105
|
+
end
|
97
106
|
end
|
File without changes
|
File without changes
|
@@ -6,7 +6,7 @@ describe Granite::Form::Model::Attributes::Localized do
|
|
6
6
|
def attribute(*args)
|
7
7
|
options = args.extract_options!
|
8
8
|
Dummy.add_attribute(Granite::Form::Model::Attributes::Reflections::Localized, :field, options)
|
9
|
-
|
9
|
+
Dummy.new.attribute(:field)
|
10
10
|
end
|
11
11
|
|
12
12
|
describe '#read' do
|
@@ -43,18 +43,6 @@ describe Granite::Form::Model::Attributes::Reflections::Attribute do
|
|
43
43
|
specify { expect(reflection(default: -> {}).defaultizer).to be_a Proc }
|
44
44
|
end
|
45
45
|
|
46
|
-
describe '#typecaster' do
|
47
|
-
before do
|
48
|
-
stub_class(:dummy, String)
|
49
|
-
stub_class(:dummy_dummy, Dummy)
|
50
|
-
end
|
51
|
-
|
52
|
-
specify { expect(reflection(type: Object).typecaster).to eq(Granite::Form.typecaster(Object)) }
|
53
|
-
specify { expect(reflection(type: String).typecaster).to eq(Granite::Form.typecaster(String)) }
|
54
|
-
specify { expect(reflection(type: Dummy).typecaster).to eq(Granite::Form.typecaster(String)) }
|
55
|
-
specify { expect(reflection(type: DummyDummy).typecaster).to eq(Granite::Form.typecaster(String)) }
|
56
|
-
end
|
57
|
-
|
58
46
|
describe '#enumerizer' do
|
59
47
|
specify { expect(reflection.enumerizer).to be_nil }
|
60
48
|
specify { expect(reflection(enum: 42).enumerizer).to eq(42) }
|
@@ -36,7 +36,7 @@ describe Granite::Form::Model::Attributes::Reflections::Base do
|
|
36
36
|
stub_class(:owner)
|
37
37
|
end
|
38
38
|
|
39
|
-
let(:reflection) { SomeScope::Borogoves.new(:field) }
|
39
|
+
let(:reflection) { SomeScope::Borogoves.new(:field, type: Object) }
|
40
40
|
let(:owner) { Owner.new }
|
41
41
|
|
42
42
|
specify { expect(reflection.build_attribute(owner, nil)).to be_a(Granite::Form::Model::Attributes::Borogoves) }
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -30,7 +30,7 @@ describe Granite::Form::Model::Dirty do
|
|
30
30
|
let(:other_author) { Author.create!(name: 'Other') }
|
31
31
|
|
32
32
|
specify { expect(Model.new.changes).to eq({}) }
|
33
|
-
specify { expect(Model.new.tap { |m| m.
|
33
|
+
specify { expect(Model.new.tap { |m| m.build_something(value: 'Value') }.changes).to eq({}) }
|
34
34
|
|
35
35
|
specify { expect(Model.new(author: author).changes).to eq('author_id' => [nil, author.id]) }
|
36
36
|
specify { expect(Model.new(author_id: author.id).changes).to eq('author_id' => [nil, author.id]) }
|