friendly-attributes 0.7.1.1 → 0.7.2
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.
- data/.gitignore +45 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/.yardopts +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +45 -0
- data/README.md +3 -0
- data/Rakefile +25 -0
- data/VERSION +1 -0
- data/friendly-attributes.gemspec +30 -0
- data/spec/config.sample.yml +6 -0
- data/spec/friendly_attributes/base_spec.rb +122 -0
- data/spec/friendly_attributes/class_methods_spec.rb +124 -0
- data/spec/friendly_attributes/configuration_spec.rb +99 -0
- data/spec/friendly_attributes/details_delegator_spec.rb +210 -0
- data/spec/friendly_attributes/instance_methods_spec.rb +240 -0
- data/spec/friendly_attributes_spec.rb +152 -0
- data/spec/spec_helper.rb +81 -0
- data/spec/support/active_record_fake.rb +18 -0
- data/spec/support/database_cleaner_helpers.rb +11 -0
- data/spec/support/friendly_fake.rb +15 -0
- metadata +129 -376
@@ -0,0 +1,210 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FriendlyAttributes::DetailsDelegator do
|
4
|
+
DetailsDelegator = FriendlyAttributes::DetailsDelegator
|
5
|
+
|
6
|
+
let(:details_delegator) { FriendlyAttributes::DetailsDelegator.new(friendly_model, ar_model, attributes, options, &initializer) }
|
7
|
+
let(:initializer) { proc {} }
|
8
|
+
let(:attributes) { {} }
|
9
|
+
let(:options) { {} }
|
10
|
+
|
11
|
+
let(:friendly_model) { mock_friendly_model }
|
12
|
+
let(:ar_model) { Class.new { include ActiveRecordFake } }
|
13
|
+
|
14
|
+
let(:ar_instance) { ar_model.new(:id => 42) }
|
15
|
+
let(:friendly_instance) { mock(friendly_model) }
|
16
|
+
|
17
|
+
describe "class methods" do
|
18
|
+
describe ".friendly_model_name" do
|
19
|
+
it { DetailsDelegator.friendly_model_name(UserDetails).should == :user_details }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe ".friendly_model_ivar" do
|
23
|
+
it { DetailsDelegator.friendly_model_ivar(:user_details).should == :@user_details_ivar }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe ".friendly_model_reader" do
|
27
|
+
it { DetailsDelegator.friendly_model_reader(:user_details).should == :load_user_details }
|
28
|
+
it { DetailsDelegator.friendly_model_reader(UserDetails).should == :load_user_details }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "initialization" do
|
33
|
+
shared_examples_for "DetailsDelegator initialization" do
|
34
|
+
context "DetailsDelegator attr_readers" do
|
35
|
+
subject { details_delegator }
|
36
|
+
|
37
|
+
before(:each) do
|
38
|
+
details_delegator
|
39
|
+
end
|
40
|
+
|
41
|
+
its(:active_record_model) { should == ar_model }
|
42
|
+
its(:friendly_model) { should == friendly_model }
|
43
|
+
its(:attributes) { should == attributes }
|
44
|
+
end
|
45
|
+
|
46
|
+
context "#setup_delegated_attributes" do
|
47
|
+
let(:attributes) do
|
48
|
+
{
|
49
|
+
String => :foo,
|
50
|
+
Integer => [:bar, :baz]
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
it "delegates the attributes passed in the options" do
|
55
|
+
details_delegator.should_receive(:delegated_attribute).with(:foo, String)
|
56
|
+
details_delegator.should_receive(:delegated_attribute).with(:bar, Integer)
|
57
|
+
details_delegator.should_receive(:delegated_attribute).with(:baz, Integer)
|
58
|
+
details_delegator.setup_delegated_attributes
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "the Friendly model" do
|
63
|
+
before(:each) do
|
64
|
+
details_delegator
|
65
|
+
end
|
66
|
+
|
67
|
+
it "includes Friendly::Document" do
|
68
|
+
friendly_model.ancestors.should include(Friendly::Document)
|
69
|
+
end
|
70
|
+
|
71
|
+
context "with defaults" do
|
72
|
+
it "adds the active_record_id attribute" do
|
73
|
+
friendly_model.attributes.should include(:active_record_id)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "adds an index to active_record_id" do
|
77
|
+
friendly_model.storage_proxy.index_for_fields([:active_record_id]).should be_an_instance_of(Friendly::Index)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "sets the active_record_key" do
|
81
|
+
friendly_model.active_record_key.should == :active_record_id
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "with options" do
|
86
|
+
let(:options) { { :active_record_key => :user_id } }
|
87
|
+
|
88
|
+
it "adds the active_record_id attribute" do
|
89
|
+
friendly_model.attributes.should include(:user_id)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "adds an index to active_record_id" do
|
93
|
+
friendly_model.storage_proxy.index_for_fields([:user_id]).should be_an_instance_of(Friendly::Index)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "sets the active_record_key" do
|
97
|
+
friendly_model.active_record_key.should == :user_id
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "the ActiveRecord model" do
|
103
|
+
it "installs the update_friendly_models callback after_save" do
|
104
|
+
ar_model.should_receive(:after_save).with(:update_friendly_models)
|
105
|
+
details_delegator
|
106
|
+
end
|
107
|
+
|
108
|
+
it "installs the destroy_friendly_models callback after_destroy" do
|
109
|
+
ar_model.should_receive(:after_destroy).with(:destroy_friendly_models)
|
110
|
+
details_delegator
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "friendly model reader method" do
|
114
|
+
before(:each) do
|
115
|
+
details_delegator
|
116
|
+
end
|
117
|
+
|
118
|
+
it "is defined" do
|
119
|
+
ar_instance.should respond_to(DetailsDelegator.friendly_model_reader(friendly_model))
|
120
|
+
end
|
121
|
+
|
122
|
+
it "finds or builds and memoizes the associated Friendly model" do
|
123
|
+
ar_instance.should_receive(:find_or_build_and_memoize_details).with(friendly_model)
|
124
|
+
ar_instance.send(DetailsDelegator.friendly_model_reader(friendly_model))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "cattr_accessor friendly_attributes_configuration" do
|
129
|
+
context "when no Configuration exists" do
|
130
|
+
it "creates and assigns a new Configuration with the delegator added" do
|
131
|
+
details_delegator
|
132
|
+
|
133
|
+
ar_model.friendly_attributes_configuration.should be_an_instance_of(FriendlyAttributes::Configuration)
|
134
|
+
ar_model.friendly_attributes_configuration.friendly_models.should == [friendly_model]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context "when Configuration already exists" do
|
139
|
+
let(:existing_details_delegator) { FriendlyAttributes::DetailsDelegator.new(other_friendly_model, ar_model, attributes, options, &initializer) }
|
140
|
+
let(:other_friendly_model) { mock_friendly_model }
|
141
|
+
|
142
|
+
before(:each) do
|
143
|
+
existing_details_delegator
|
144
|
+
end
|
145
|
+
|
146
|
+
it "adds to the existing configuration" do
|
147
|
+
existing_configuration = ar_model.friendly_attributes_configuration
|
148
|
+
|
149
|
+
expect do
|
150
|
+
details_delegator
|
151
|
+
end.to change { ar_model.friendly_attributes_configuration.friendly_models }.
|
152
|
+
from([other_friendly_model]).
|
153
|
+
to([other_friendly_model, friendly_model])
|
154
|
+
|
155
|
+
ar_model.friendly_attributes_configuration.should == existing_configuration
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "missing initialization block" do
|
163
|
+
let(:details_delegator) { FriendlyAttributes::DetailsDelegator.new(friendly_model, ar_model, attributes, options) }
|
164
|
+
it_should_behave_like "DetailsDelegator initialization"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe "#delegated_method" do
|
169
|
+
before(:each) do
|
170
|
+
details_delegator
|
171
|
+
details_delegator.delegated_method(:some_method)
|
172
|
+
ar_instance.stub(DetailsDelegator.friendly_model_reader(friendly_model) => friendly_instance)
|
173
|
+
end
|
174
|
+
|
175
|
+
it "delegates the method to Friendly model" do
|
176
|
+
bar = mock
|
177
|
+
friendly_instance.should_receive(:some_method).with(:foo).and_return(bar)
|
178
|
+
ar_instance.some_method(:foo).should == bar
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "#delegated_attribute" do
|
183
|
+
before(:each) do
|
184
|
+
details_delegator
|
185
|
+
details_delegator.delegated_attribute(:some_attribute, String)
|
186
|
+
ar_instance.stub(DetailsDelegator.friendly_model_reader(friendly_model) => friendly_instance)
|
187
|
+
end
|
188
|
+
|
189
|
+
it "adds an attribute to the Friendly model" do
|
190
|
+
friendly_model.attributes.should include(:some_attribute)
|
191
|
+
friendly_model.attributes[:some_attribute].type.should == String
|
192
|
+
end
|
193
|
+
|
194
|
+
it "delegates the reader to Friendly model" do
|
195
|
+
bar = mock
|
196
|
+
friendly_instance.should_receive(:some_attribute).and_return(bar)
|
197
|
+
ar_instance.some_attribute.should == bar
|
198
|
+
end
|
199
|
+
|
200
|
+
it "delegates the writer to Friendly model" do
|
201
|
+
bar = mock
|
202
|
+
friendly_instance.should_receive(:some_attribute=).with(:value)
|
203
|
+
ar_instance.some_attribute = :value
|
204
|
+
end
|
205
|
+
|
206
|
+
it "adds the attribute to the configuration" do
|
207
|
+
ar_instance.friendly_attributes_configuration.attributes.should == { :some_attribute => friendly_model }
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FriendlyAttributes::InstanceMethods do
|
4
|
+
DetailsDelegator = FriendlyAttributes::DetailsDelegator unless defined?(DetailsDelegator)
|
5
|
+
|
6
|
+
let(:object) { klass.new.tap { |o| o.stub(:friendly_attributes_configuration => configuration) } }
|
7
|
+
let(:configuration) { mock(FriendlyAttributes::Configuration) }
|
8
|
+
let(:klass) {
|
9
|
+
Class.new {
|
10
|
+
include ActiveRecordFake
|
11
|
+
include FriendlyAttributes::InstanceMethods
|
12
|
+
}
|
13
|
+
}
|
14
|
+
let(:user_details) { double(UserDetails).as_null_object }
|
15
|
+
let(:user_second_details) { double(UserSecondDetails).as_null_object }
|
16
|
+
let(:friendly_model_instances) { [user_details, user_second_details] }
|
17
|
+
|
18
|
+
describe "reading and writing Friendly attributes" do
|
19
|
+
let(:object_details) { double(FriendlyAttributes::Base, :foo => foo, :foo= => foo) }
|
20
|
+
let(:foo) { mock("object_details.foo") }
|
21
|
+
|
22
|
+
before(:each) do
|
23
|
+
object.stub(:friendly_instance_for_attribute => object_details)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#read_friendly_attribute" do
|
27
|
+
it "finds the FriendlyAttributes instance for the specified attribute" do
|
28
|
+
object.
|
29
|
+
should_receive(:friendly_instance_for_attribute).
|
30
|
+
with(:foo).
|
31
|
+
and_return(object_details)
|
32
|
+
|
33
|
+
object.read_friendly_attribute(:foo)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "reads the attribute from the FriendlyAttributes instance" do
|
37
|
+
object_details.should_receive(:foo).and_return(foo)
|
38
|
+
object.read_friendly_attribute(:foo).should == foo
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#write_friendly_attribute" do
|
43
|
+
it "finds the FriendlyAttributes instance for the specified attribute" do
|
44
|
+
object.
|
45
|
+
should_receive(:friendly_instance_for_attribute).
|
46
|
+
with(:foo).
|
47
|
+
and_return(object_details)
|
48
|
+
|
49
|
+
object.write_friendly_attribute(:foo, "bar")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "writes the attribute on the FriendlyAttributes instance" do
|
53
|
+
object_details.should_receive(:foo=).with("bar").and_return(foo)
|
54
|
+
object.write_friendly_attribute(:foo, "bar").should == foo
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#friendly_instance_for_attribute" do
|
62
|
+
it "reads the value for the friendly model from the instance" do
|
63
|
+
configuration.should_receive(:model_for_attribute).with(:foo).and_return(UserDetails)
|
64
|
+
object.should_receive(DetailsDelegator.friendly_model_reader(UserDetails)).and_return(user_details)
|
65
|
+
object.friendly_instance_for_attribute(:foo).should == user_details
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#update_friendly_models" do
|
70
|
+
it "updates each loaded friendly model instance if needed" do
|
71
|
+
object.should_receive(:present_friendly_instances).and_return(friendly_model_instances)
|
72
|
+
friendly_model_instances.each do |instance|
|
73
|
+
instance.should_receive(:update_if_changed_with_model).with(object.id)
|
74
|
+
end
|
75
|
+
object.update_friendly_models
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#destroy_friendly_details" do
|
80
|
+
it "loads and destroys all associated friendly models" do
|
81
|
+
object.should_receive(:all_friendly_instances).and_return(friendly_model_instances)
|
82
|
+
friendly_model_instances.each do |instance|
|
83
|
+
instance.should_receive(:destroy).and_return(true)
|
84
|
+
end
|
85
|
+
object.destroy_friendly_models.should be_true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#friendly_instance_present?" do
|
90
|
+
subject { object.friendly_instance_present?(friendly_model) }
|
91
|
+
let(:friendly_model) { UserDetails }
|
92
|
+
|
93
|
+
context "when friendly_details ivar is present" do
|
94
|
+
before(:each) do
|
95
|
+
object.instance_variable_set(DetailsDelegator.friendly_model_ivar(friendly_model), mock)
|
96
|
+
end
|
97
|
+
|
98
|
+
it { should be_true }
|
99
|
+
end
|
100
|
+
|
101
|
+
context "when friendly_details ivar is not present" do
|
102
|
+
it { should be_false }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#friendly_instance_presence" do
|
107
|
+
subject { object.friendly_instance_presence(friendly_model) }
|
108
|
+
let(:friendly_model) { UserDetails }
|
109
|
+
|
110
|
+
context "when present" do
|
111
|
+
before(:each) do
|
112
|
+
object.instance_variable_set(DetailsDelegator.friendly_model_ivar(friendly_model), mock)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "returns the instance using the model reader" do
|
116
|
+
object.should_receive(DetailsDelegator.friendly_model_reader(friendly_model)).and_return(user_details)
|
117
|
+
subject.should == user_details
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "when not present" do
|
122
|
+
it "returns nil" do
|
123
|
+
subject.should be_nil
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#all_friendly_instances" do
|
129
|
+
let(:friendly_models) { [UserDetails, UserSecondDetails] }
|
130
|
+
|
131
|
+
it "loads and returns all the Friendly model instances associated with the record" do
|
132
|
+
configuration.should_receive(:friendly_models).and_return(friendly_models)
|
133
|
+
object.should_receive(DetailsDelegator.friendly_model_reader(UserDetails)).and_return(user_details)
|
134
|
+
object.should_receive(DetailsDelegator.friendly_model_reader(UserSecondDetails)).and_return(user_second_details)
|
135
|
+
object.all_friendly_instances.should == [user_details, user_second_details]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "#present_friendly_instances" do
|
140
|
+
let(:friendly_models) { [UserDetails, UserSecondDetails] }
|
141
|
+
|
142
|
+
it "returns all the loaded Friendly model instances associated with the record" do
|
143
|
+
configuration.should_receive(:friendly_models).and_return(friendly_models)
|
144
|
+
object.should_receive(:friendly_instance_presence).with(UserDetails).and_return(user_details)
|
145
|
+
object.should_receive(:friendly_instance_presence).with(UserSecondDetails).and_return(nil)
|
146
|
+
object.present_friendly_instances.should == [user_details]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "#friendly_details_build_options" do
|
151
|
+
context "when friendly_details_build_options is not defined" do
|
152
|
+
it "returns and empty Hash" do
|
153
|
+
object.friendly_details_build_options.should == { }
|
154
|
+
object.friendly_details_build_options(UserDetails).should == { }
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "when friendly_details_build_options is defined" do
|
159
|
+
let(:foo) { mock("default friendly details build option") }
|
160
|
+
|
161
|
+
before(:each) do
|
162
|
+
_foo = foo
|
163
|
+
|
164
|
+
klass.class_eval do
|
165
|
+
define_method(:friendly_details_build_options) do |klass|
|
166
|
+
{ :foo => _foo }
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
it "returns the options specified by friendly_details_build_options" do
|
172
|
+
object.friendly_details_build_options(UserSecondDetails).should == { :foo => foo }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe "#changed?" do
|
178
|
+
subject { active_record.changed? }
|
179
|
+
let(:active_record) { User.create(:name => "Stan", :email => "stan@example.com") }
|
180
|
+
|
181
|
+
context "when the ActiveRecord model has changed," do
|
182
|
+
before(:each) do
|
183
|
+
active_record.email = "eric@example.com"
|
184
|
+
end
|
185
|
+
|
186
|
+
context "and the Friendly model has changed," do
|
187
|
+
before(:each) do
|
188
|
+
active_record.name = "Eric"
|
189
|
+
end
|
190
|
+
|
191
|
+
it { should be_true }
|
192
|
+
end
|
193
|
+
|
194
|
+
context "and the Friendly model has not changed" do
|
195
|
+
it { should be_true }
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
context "when the ActiveRecord model has not changed," do
|
200
|
+
context "and the Friendly model has changed" do
|
201
|
+
before(:each) do
|
202
|
+
active_record.name = "Eric"
|
203
|
+
end
|
204
|
+
|
205
|
+
it { should be_true }
|
206
|
+
end
|
207
|
+
|
208
|
+
context "and the Friendly model has not changed" do
|
209
|
+
it { should be_false }
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe "#find_or_build_and_memoize_details" do
|
215
|
+
let(:user) { @user }
|
216
|
+
let(:build_options) { mock(Hash) }
|
217
|
+
let(:user_details) { double(UserDetails) }
|
218
|
+
|
219
|
+
before(:each) do
|
220
|
+
@user = User.find(User.create(:name => "Stan", :email => "stan@example.com").id)
|
221
|
+
end
|
222
|
+
|
223
|
+
it "finds (or builds a new instance with build options) and memoizes the associated Friendly instance" do
|
224
|
+
user.
|
225
|
+
should_receive(:friendly_details_build_options).
|
226
|
+
with(UserDetails).
|
227
|
+
once.
|
228
|
+
and_return(build_options)
|
229
|
+
|
230
|
+
UserDetails.
|
231
|
+
should_receive(:find_or_build_by_active_record_id).
|
232
|
+
with(user.id, build_options).
|
233
|
+
once.
|
234
|
+
and_return(user_details)
|
235
|
+
|
236
|
+
user.find_or_build_and_memoize_details(UserDetails).should == user_details
|
237
|
+
user.find_or_build_and_memoize_details(UserDetails).should == user_details
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FriendlyAttributes do
|
4
|
+
use_database_cleanup
|
5
|
+
|
6
|
+
describe "definition" do
|
7
|
+
it { User.should have_friendly_attributes(String, :name, :through => UserDetails) }
|
8
|
+
it { User.should have_friendly_attributes(Integer, :second_int, :through => UserSecondDetails) }
|
9
|
+
it { User.new.should have_friendly_attributes(Integer, :shoe_size, :birth_year, :through => UserDetails) }
|
10
|
+
it { User.new.should have_friendly_attributes(Friendly::Boolean, :subscribed, :through => UserDetails) }
|
11
|
+
it { User.should_not have_friendly_attributes(String, :foo, :through => UserDetails) }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "creating" do
|
15
|
+
context "with Friendly attributes" do
|
16
|
+
context "when using just one Friendly model" do
|
17
|
+
let(:user) { User.create!(:name => "Stan", :email => "stan@example.com", :birth_year => 1984, :subscribed => true) }
|
18
|
+
|
19
|
+
it "creates only the required Friendly model" do
|
20
|
+
expect do
|
21
|
+
expect do
|
22
|
+
user
|
23
|
+
end.to change { UserDetails.count({}) }
|
24
|
+
end.to_not change { UserSecondDetails.count({}) }
|
25
|
+
end
|
26
|
+
|
27
|
+
it "sets the appropriate attributes on the ActiveRecord model and associated Friendly model" do
|
28
|
+
user_detail = user.load_user_details
|
29
|
+
user_detail.name.should == "Stan"
|
30
|
+
user_detail.birth_year.should == 1984
|
31
|
+
user_detail.shoe_size.should == 42
|
32
|
+
user_detail.subscribed.should be_true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when using multiple associated Friendly models" do
|
37
|
+
let(:user) { User.create!(:name => "Stan", :email => "stan@example.com", :birth_year => 1984, :second_int => 120, :subscribed => true) }
|
38
|
+
|
39
|
+
it "creates all the required Friendly models" do
|
40
|
+
expect do
|
41
|
+
expect do
|
42
|
+
user
|
43
|
+
end.to change { UserDetails.count({}) }
|
44
|
+
end.to change { UserSecondDetails.count({}) }
|
45
|
+
end
|
46
|
+
|
47
|
+
it "sets the appropriate attributes on the ActiveRecord model and associated Friendly model" do
|
48
|
+
user_detail = user.load_user_details
|
49
|
+
user_detail.name.should == "Stan"
|
50
|
+
user_detail.birth_year.should == 1984
|
51
|
+
user_detail.shoe_size.should == 42
|
52
|
+
user_detail.subscribed.should be_true
|
53
|
+
|
54
|
+
user_second_detail = user.load_user_second_details
|
55
|
+
user_second_detail.second_int.should == 120
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "without Friendly attributes" do
|
61
|
+
let(:user) { User.create(:email => "stan@example.com") }
|
62
|
+
|
63
|
+
it "does not create an associated Friendly model" do
|
64
|
+
expect do
|
65
|
+
user
|
66
|
+
end.to_not change { UserDetails.count({}) }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "reading" do
|
72
|
+
let(:user) { User.create!(:name => "Stan", :email => "stan@example.com", :birth_year => 1984, :subscribed => true) }
|
73
|
+
|
74
|
+
it "through the attr_reader" do
|
75
|
+
user.name.should == "Stan"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "through read_friendly_attribute" do
|
79
|
+
user.read_friendly_attribute(:name).should == "Stan"
|
80
|
+
user.read_friendly_attribute(:birth_year).should == 1984
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "updating" do
|
85
|
+
context "with Friendly attributes" do
|
86
|
+
let(:user) { User.create(:name => "Stan", :email => "stan@example.com", :second_int => 200) }
|
87
|
+
|
88
|
+
it "updates the attributes" do
|
89
|
+
user.update_attributes(:name => "Eric", :second_int => 123)
|
90
|
+
UserDetails.first({}).name.should == "Eric"
|
91
|
+
UserSecondDetails.first({}).second_int.should == 123
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "without Friendly attributes" do
|
96
|
+
let(:user) { User.create(:email => "stan@example.com") }
|
97
|
+
|
98
|
+
it "does not create an associated Details model, if no delegated attributes are updated" do
|
99
|
+
expect do
|
100
|
+
user.update_attributes(:email => "eric@example.com")
|
101
|
+
end.to_not change { UserDetails.count({}) }
|
102
|
+
end
|
103
|
+
|
104
|
+
it "creates an associated Details model, if delegated attributes are updated" do
|
105
|
+
expect do
|
106
|
+
user.update_attributes(:name => "Eric")
|
107
|
+
end.to change { UserDetails.count({}) }
|
108
|
+
user.name.should == "Eric"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context "with nested attributes" do
|
113
|
+
let(:user) { User.create(:name => "Stan Marsh", :email => "smarsh@example.com") }
|
114
|
+
let(:parent) { Parent.create(:users => [user]) }
|
115
|
+
|
116
|
+
before(:each) do
|
117
|
+
parent
|
118
|
+
parent.update_attributes(:users_attributes => users_attributes)
|
119
|
+
user.reload
|
120
|
+
end
|
121
|
+
|
122
|
+
context "when only changing Friendly attributes" do
|
123
|
+
let(:users_attributes) { { "0" => { "id" => user.id, "name" => "Eric Cartman" } } }
|
124
|
+
|
125
|
+
it "updates Friendly attributes through nested association" do
|
126
|
+
user.name.should == "Eric Cartman"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when changing both Friendly attributes and ActiveRecord attributes" do
|
131
|
+
let(:users_attributes) { { "0" => { "id" => user.id, "name" => "Eric Cartman", "email" => "eric@example.com" } } }
|
132
|
+
|
133
|
+
it "updates Friendly attributes through nested association" do
|
134
|
+
user.email.should == "eric@example.com"
|
135
|
+
user.name.should == "Eric Cartman"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "destroying" do
|
142
|
+
let(:user) { User.create(:name => "Stan", :email => "stan@example.com") }
|
143
|
+
|
144
|
+
it "destroys the associated Details model" do
|
145
|
+
user # create it first
|
146
|
+
|
147
|
+
expect do
|
148
|
+
user.destroy
|
149
|
+
end.to change { UserDetails.count({}) }.by(-1)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|