external_fields 0.1.0
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 +7 -0
- data/.gitignore +15 -0
- data/.overcommit.yml +60 -0
- data/.rubocop.yml +271 -0
- data/.travis.yml +12 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +152 -0
- data/external_fields.gemspec +39 -0
- data/lib/external_fields/version.rb +3 -0
- data/lib/external_fields.rb +87 -0
- data/spec/external_fields_spec.rb +90 -0
- data/spec/spec_helper.rb +48 -0
- metadata +202 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 7f07e8a7db6679bd7137bc5b612118d5d7554738
|
|
4
|
+
data.tar.gz: 9591ced4076f386180722d103d6177e46ea9f6f0
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 47c6d1ceacace126d600488a85b980ba7c466d32ef80e7b15b147015410134ae8b4a41175cc1ff911785e15499805cbaef07f89a5d38eda5a9694e142fa57fb6
|
|
7
|
+
data.tar.gz: 650583bada54722659ce56b4ac884e1b5fa460116263c32be4588e6ab31057c1e1480db31ca4fbabf81689503799da58f7d08f09d42af621ebe4fe11499e080a
|
data/.gitignore
ADDED
data/.overcommit.yml
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
CommitMsg:
|
|
2
|
+
CapitalizedSubject:
|
|
3
|
+
enabled: true
|
|
4
|
+
HardTabs:
|
|
5
|
+
enabled: true
|
|
6
|
+
RussianNovel:
|
|
7
|
+
enabled: true
|
|
8
|
+
SingleLineSubject:
|
|
9
|
+
enabled: true
|
|
10
|
+
TextWidth:
|
|
11
|
+
enabled: true
|
|
12
|
+
TrailingPeriod:
|
|
13
|
+
enabled: true
|
|
14
|
+
PreCommit:
|
|
15
|
+
AuthorEmail:
|
|
16
|
+
enabled: true
|
|
17
|
+
AuthorName:
|
|
18
|
+
enabled: true
|
|
19
|
+
Brakeman: # Performs static code security checking.
|
|
20
|
+
enabled: false
|
|
21
|
+
BrokenSymlinks:
|
|
22
|
+
enabled: true
|
|
23
|
+
BundleCheck:
|
|
24
|
+
enabled: true
|
|
25
|
+
CssLint:
|
|
26
|
+
enabled: true
|
|
27
|
+
HamlLint:
|
|
28
|
+
enabled: true
|
|
29
|
+
HardTabs:
|
|
30
|
+
enabled: true
|
|
31
|
+
HtmlTidy: # Uses the `tidy` executable (installed on OS X by default).
|
|
32
|
+
enabled: true
|
|
33
|
+
ImageOptim:
|
|
34
|
+
enabled: true
|
|
35
|
+
Jscs: # Checks for JavaScript style.
|
|
36
|
+
enabled: true
|
|
37
|
+
JsHint: # Checks for JavaScript best practices.
|
|
38
|
+
enabled: true
|
|
39
|
+
JsonSyntax:
|
|
40
|
+
enabled: true
|
|
41
|
+
LocalPathsInGemfile:
|
|
42
|
+
enabled: true
|
|
43
|
+
MergeConflicts:
|
|
44
|
+
enabled: true
|
|
45
|
+
PryBinding:
|
|
46
|
+
enabled: true
|
|
47
|
+
Reek:
|
|
48
|
+
enabled: false
|
|
49
|
+
RuboCop:
|
|
50
|
+
enabled: true
|
|
51
|
+
problem_on_unmodified_line: warn
|
|
52
|
+
ScssLint:
|
|
53
|
+
enabled: true
|
|
54
|
+
TrailingWhitespace:
|
|
55
|
+
enabled: true
|
|
56
|
+
TravisLint: # Checks Travis CI configurations. We use Travis for our open-
|
|
57
|
+
# source repositories.
|
|
58
|
+
enabled: true
|
|
59
|
+
YamlSyntax:
|
|
60
|
+
enabled: true
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
require:
|
|
2
|
+
- rubocop/rspec/focused
|
|
3
|
+
|
|
4
|
+
# This (http://c2.com/cgi/wiki?AbcMetric) is super obnoxious
|
|
5
|
+
AbcSize:
|
|
6
|
+
Enabled: false
|
|
7
|
+
|
|
8
|
+
AccessorMethodName:
|
|
9
|
+
Enabled: false
|
|
10
|
+
|
|
11
|
+
Alias:
|
|
12
|
+
Enabled: false
|
|
13
|
+
|
|
14
|
+
AllCops:
|
|
15
|
+
Exclude:
|
|
16
|
+
- "vendor/**/*"
|
|
17
|
+
- "spec/dummy/**/*"
|
|
18
|
+
- "db/schema.rb"
|
|
19
|
+
- "db/migrate/**/*"
|
|
20
|
+
RunRailsCops: true
|
|
21
|
+
|
|
22
|
+
AmbiguousOperator:
|
|
23
|
+
Enabled: false
|
|
24
|
+
|
|
25
|
+
AmbiguousRegexpLiteral:
|
|
26
|
+
Enabled: false
|
|
27
|
+
|
|
28
|
+
ArrayJoin:
|
|
29
|
+
Enabled: false
|
|
30
|
+
|
|
31
|
+
AsciiComments:
|
|
32
|
+
Enabled: false
|
|
33
|
+
|
|
34
|
+
AsciiIdentifiers:
|
|
35
|
+
Enabled: false
|
|
36
|
+
|
|
37
|
+
AssignmentInCondition:
|
|
38
|
+
Enabled: true
|
|
39
|
+
|
|
40
|
+
Attr:
|
|
41
|
+
Enabled: false
|
|
42
|
+
|
|
43
|
+
BlockNesting:
|
|
44
|
+
Enabled: false
|
|
45
|
+
|
|
46
|
+
BracesAroundHashParameters:
|
|
47
|
+
Enabled: false
|
|
48
|
+
|
|
49
|
+
CaseEquality:
|
|
50
|
+
Enabled: false
|
|
51
|
+
|
|
52
|
+
CharacterLiteral:
|
|
53
|
+
Enabled: false
|
|
54
|
+
|
|
55
|
+
ClassLength:
|
|
56
|
+
Enabled: false
|
|
57
|
+
|
|
58
|
+
ClassVars:
|
|
59
|
+
Enabled: false
|
|
60
|
+
|
|
61
|
+
CollectionMethods:
|
|
62
|
+
PreferredMethods:
|
|
63
|
+
find: detect
|
|
64
|
+
reduce: inject
|
|
65
|
+
collect: map
|
|
66
|
+
find_all: select
|
|
67
|
+
|
|
68
|
+
ColonMethodCall:
|
|
69
|
+
Enabled: false
|
|
70
|
+
|
|
71
|
+
CommentAnnotation:
|
|
72
|
+
Enabled: false
|
|
73
|
+
|
|
74
|
+
ConditionPosition:
|
|
75
|
+
Enabled: false
|
|
76
|
+
|
|
77
|
+
CyclomaticComplexity:
|
|
78
|
+
Enabled: false
|
|
79
|
+
|
|
80
|
+
Delegate:
|
|
81
|
+
Enabled: false
|
|
82
|
+
|
|
83
|
+
DeprecatedClassMethods:
|
|
84
|
+
Enabled: false
|
|
85
|
+
|
|
86
|
+
DeprecatedHashMethods:
|
|
87
|
+
Enabled: false
|
|
88
|
+
|
|
89
|
+
Documentation:
|
|
90
|
+
Enabled: false
|
|
91
|
+
|
|
92
|
+
DotPosition:
|
|
93
|
+
EnforcedStyle: trailing
|
|
94
|
+
|
|
95
|
+
DoubleNegation:
|
|
96
|
+
Enabled: false
|
|
97
|
+
|
|
98
|
+
ElseLayout:
|
|
99
|
+
Enabled: false
|
|
100
|
+
|
|
101
|
+
EmptyLiteral:
|
|
102
|
+
Enabled: false
|
|
103
|
+
|
|
104
|
+
Encoding:
|
|
105
|
+
Enabled: false
|
|
106
|
+
|
|
107
|
+
EvenOdd:
|
|
108
|
+
Enabled: false
|
|
109
|
+
|
|
110
|
+
FileName:
|
|
111
|
+
Enabled: false
|
|
112
|
+
|
|
113
|
+
FlipFlop:
|
|
114
|
+
Enabled: false
|
|
115
|
+
|
|
116
|
+
FormatString:
|
|
117
|
+
Enabled: false
|
|
118
|
+
|
|
119
|
+
GlobalVars:
|
|
120
|
+
Enabled: false
|
|
121
|
+
|
|
122
|
+
GuardClause:
|
|
123
|
+
Enabled: false
|
|
124
|
+
|
|
125
|
+
HandleExceptions:
|
|
126
|
+
Enabled: false
|
|
127
|
+
|
|
128
|
+
IfUnlessModifier:
|
|
129
|
+
Enabled: false
|
|
130
|
+
|
|
131
|
+
IfWithSemicolon:
|
|
132
|
+
Enabled: false
|
|
133
|
+
|
|
134
|
+
InvalidCharacterLiteral:
|
|
135
|
+
Enabled: false
|
|
136
|
+
|
|
137
|
+
Lambda:
|
|
138
|
+
Enabled: false
|
|
139
|
+
|
|
140
|
+
LambdaCall:
|
|
141
|
+
Enabled: false
|
|
142
|
+
|
|
143
|
+
LineEndConcatenation:
|
|
144
|
+
Enabled: false
|
|
145
|
+
|
|
146
|
+
LineLength:
|
|
147
|
+
Max: 80
|
|
148
|
+
|
|
149
|
+
LiteralInCondition:
|
|
150
|
+
Enabled: false
|
|
151
|
+
|
|
152
|
+
LiteralInInterpolation:
|
|
153
|
+
Enabled: false
|
|
154
|
+
|
|
155
|
+
Loop:
|
|
156
|
+
Enabled: false
|
|
157
|
+
|
|
158
|
+
MethodLength:
|
|
159
|
+
Enabled: false
|
|
160
|
+
|
|
161
|
+
ModuleFunction:
|
|
162
|
+
Enabled: false
|
|
163
|
+
|
|
164
|
+
NegatedIf:
|
|
165
|
+
Enabled: false
|
|
166
|
+
|
|
167
|
+
NegatedWhile:
|
|
168
|
+
Enabled: false
|
|
169
|
+
|
|
170
|
+
Next:
|
|
171
|
+
Enabled: false
|
|
172
|
+
|
|
173
|
+
NilComparison:
|
|
174
|
+
Enabled: false
|
|
175
|
+
|
|
176
|
+
Not:
|
|
177
|
+
Enabled: false
|
|
178
|
+
|
|
179
|
+
NumericLiterals:
|
|
180
|
+
Enabled: false
|
|
181
|
+
|
|
182
|
+
OneLineConditional:
|
|
183
|
+
Enabled: false
|
|
184
|
+
|
|
185
|
+
OpMethod:
|
|
186
|
+
Enabled: false
|
|
187
|
+
|
|
188
|
+
ParameterLists:
|
|
189
|
+
Enabled: false
|
|
190
|
+
|
|
191
|
+
ParenthesesAsGroupedExpression:
|
|
192
|
+
Enabled: false
|
|
193
|
+
|
|
194
|
+
PercentLiteralDelimiters:
|
|
195
|
+
PreferredDelimiters:
|
|
196
|
+
'%': '{}'
|
|
197
|
+
|
|
198
|
+
PerceivedComplexity:
|
|
199
|
+
Enabled: false
|
|
200
|
+
|
|
201
|
+
PerlBackrefs:
|
|
202
|
+
Enabled: false
|
|
203
|
+
|
|
204
|
+
PredicateName:
|
|
205
|
+
Enabled: false
|
|
206
|
+
|
|
207
|
+
Proc:
|
|
208
|
+
Enabled: false
|
|
209
|
+
|
|
210
|
+
RaiseArgs:
|
|
211
|
+
Enabled: false
|
|
212
|
+
|
|
213
|
+
RedundantReturn:
|
|
214
|
+
AllowMultipleReturnValues: true
|
|
215
|
+
|
|
216
|
+
RegexpLiteral:
|
|
217
|
+
Enabled: false
|
|
218
|
+
|
|
219
|
+
RequireParentheses:
|
|
220
|
+
Enabled: false
|
|
221
|
+
|
|
222
|
+
Rspec/Focused:
|
|
223
|
+
Enabled: true
|
|
224
|
+
|
|
225
|
+
SelfAssignment:
|
|
226
|
+
Enabled: false
|
|
227
|
+
|
|
228
|
+
SignalException:
|
|
229
|
+
EnforcedStyle: only_raise
|
|
230
|
+
|
|
231
|
+
SingleLineBlockParams:
|
|
232
|
+
Enabled: false
|
|
233
|
+
|
|
234
|
+
SingleLineMethods:
|
|
235
|
+
Enabled: false
|
|
236
|
+
|
|
237
|
+
SpecialGlobalVars:
|
|
238
|
+
Enabled: false
|
|
239
|
+
|
|
240
|
+
StringLiterals:
|
|
241
|
+
EnforcedStyle: double_quotes
|
|
242
|
+
|
|
243
|
+
Style/MultilineBlockChain:
|
|
244
|
+
Enabled: false
|
|
245
|
+
|
|
246
|
+
VariableInterpolation:
|
|
247
|
+
Enabled: false
|
|
248
|
+
|
|
249
|
+
TrailingComma:
|
|
250
|
+
Enabled: false
|
|
251
|
+
|
|
252
|
+
TrivialAccessors:
|
|
253
|
+
Enabled: false
|
|
254
|
+
|
|
255
|
+
UnderscorePrefixedVariableName:
|
|
256
|
+
Enabled: false
|
|
257
|
+
|
|
258
|
+
VariableInterpolation:
|
|
259
|
+
Enabled: false
|
|
260
|
+
|
|
261
|
+
Void:
|
|
262
|
+
Enabled: false
|
|
263
|
+
|
|
264
|
+
WhenThen:
|
|
265
|
+
Enabled: false
|
|
266
|
+
|
|
267
|
+
WhileUntilModifier:
|
|
268
|
+
Enabled: false
|
|
269
|
+
|
|
270
|
+
WordArray:
|
|
271
|
+
Enabled: false
|
data/.travis.yml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
language: ruby
|
|
2
|
+
rvm:
|
|
3
|
+
- 2.2.1
|
|
4
|
+
script: bundle exec rspec
|
|
5
|
+
addons:
|
|
6
|
+
code_climate:
|
|
7
|
+
repo_token: 9f025c501f5daf9ffc6712005e4cda18ce4f6afe76c2c0913889712cefb3679e
|
|
8
|
+
notifications:
|
|
9
|
+
email: false
|
|
10
|
+
hipchat:
|
|
11
|
+
rooms:
|
|
12
|
+
secure: c6XVH78Isrp/TvZsQaq2Ne442rLoUU5FX4N6PgF8jdbMIiPN5dEyURH1LgBop5grv2ZY8BwZeVjNvKVlr8V9wDoER6AV81MclV398qOiIy020dS8ahgpj7F7EO/hKU3iQX4d+3r3a5oeeWjDXdN4uPbeWR5uLXEsXDtX3HUZGxc1p/fT8xUSQufb+kZXccrYV2ryWIa7bQxWlpfAnTm/VQxl3tf5riK7vjq1TkwxvNl4Rv5TjkPFJkryyEcDtutX1jWF8O/nsxzejG604pfyZHcoDjl5erIatalHDwOxr7H1u0XYVpnldiv/L37TGkZaMWuRnCraWn6GDdmqWrpRWYqQfanpdNq9iNB8lWpsPDfnMgLQAbDnSobeeKkkQAeY0lgZjDwcP8AySjEGX/BhdIcYgs6l3C6JR3lj1P47w0KU9YgOxrRf32RGfVRfbT9cz/xqalPjVpJPOmdEoG4vC9tWZTaTBHNnmfJwrcuqnbCLh3mufVvjQD8LDo53xzKJqDguR+j7G0pKfYrwRyRbc1fwBeiVhQwmwtS8u/Swr8ImHN1r50Ma4FId+dBRkstqunfzHjchv/Om96KVPp8rL1sTMHyZvobre8OA4ovjxgQfTFIXholNtOH4Ege/ol9KxF+Sg1fBeELT8c2Jw8Hp46WduyrIcFkRBgNnSqcKnD8=
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015 Panorama Education
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
[](https://codeclimate.com/github/panorama-ed/rails_external_fields) [](https://codeclimate.com/github/panorama-ed/rails_external_fields) [](https://travis-ci.org/panorama-ed/rails_external_fields) [](http://inch-ci.org/github/panorama-ed/rails_external_fields) [](http://badge.fury.io/rb/rails_external_fields)
|
|
2
|
+
|
|
3
|
+
# ExternalFields
|
|
4
|
+
Create the illusion that an object has specific attributes when those attributes
|
|
5
|
+
actually belong to an associated object.
|
|
6
|
+
|
|
7
|
+
This is particularly useful for different classes within a single-
|
|
8
|
+
table inheritance table to have access to separate fields in class-specific
|
|
9
|
+
associations.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
Add this line to your application's Gemfile:
|
|
13
|
+
|
|
14
|
+
````
|
|
15
|
+
gem "external_fields"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
And then execute:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
$ bundle
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or install it yourself as:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
$ gem install external_fields
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
Include `ExternalFields` and define the external fields using the `external_field` method. For example, if `grade_level`, `age` and `credits` are defined in another class `StudentData` and you want to access them in `Student` you could do:
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
require "active_record"
|
|
35
|
+
require "active_support"
|
|
36
|
+
|
|
37
|
+
require "external_fields"
|
|
38
|
+
|
|
39
|
+
class Student < ActiveRecord::Base
|
|
40
|
+
include ExternalFields
|
|
41
|
+
|
|
42
|
+
has_one :data,
|
|
43
|
+
class_name: StudentData
|
|
44
|
+
|
|
45
|
+
external_field :grade_level, # External attribute 1
|
|
46
|
+
:age, # External attribute 2
|
|
47
|
+
:credits, # External attribute 3
|
|
48
|
+
:data, # Name of the association
|
|
49
|
+
class_name: "StudentData" # Class name of association
|
|
50
|
+
end
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
where the external fields are defined in another associated class:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
class StudentData < ActiveRecord::Base
|
|
57
|
+
attr_accessor :grade_level, :age, :credits
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Now you can directly call the accessors on the `Student` objects:
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
> s = Student.create!
|
|
65
|
+
> s.age
|
|
66
|
+
=> nil
|
|
67
|
+
|
|
68
|
+
> s.age = 10
|
|
69
|
+
> s.age
|
|
70
|
+
=> 10
|
|
71
|
+
|
|
72
|
+
> s.grade_level = 4
|
|
73
|
+
> s.grade_level
|
|
74
|
+
=> 4
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Overriding default behavior using `underscored` accessors
|
|
78
|
+
You can also add underscored accessors using the `underscore` flag
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
...
|
|
82
|
+
external_field :grade_level, # External attribute 1
|
|
83
|
+
:age, # External attribute 2
|
|
84
|
+
:credits, # External attribute 3
|
|
85
|
+
:data, # Name of the association
|
|
86
|
+
class_name: "StudentData" # Class name of association
|
|
87
|
+
underscore: true # Flag for underscored accessors
|
|
88
|
+
...
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
This will allow you to use the external fields using underscored methods:
|
|
92
|
+
```ruby
|
|
93
|
+
s = Student.create!
|
|
94
|
+
s._age
|
|
95
|
+
s._grade_level
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
This approach lets you override the default behavior cleanly. For example,
|
|
99
|
+
you could override the grade level using this method:
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
def grade_level
|
|
103
|
+
if _grade_level == 0
|
|
104
|
+
"Kindergarten"
|
|
105
|
+
else
|
|
106
|
+
_grade_level
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Accessing the original association
|
|
112
|
+
|
|
113
|
+
In some instances it's helpful to be able to use the original association
|
|
114
|
+
without building an object on access. For instance, you might want to have a
|
|
115
|
+
validation inspect a value without creating a new object on each save. In that
|
|
116
|
+
case, you can use the `use_original` flag on the association like so:
|
|
117
|
+
|
|
118
|
+
```ruby
|
|
119
|
+
validate :kindergarten_students_have_names
|
|
120
|
+
|
|
121
|
+
def kindergarten_students_have_names
|
|
122
|
+
data_obj = data(use_original: true)
|
|
123
|
+
|
|
124
|
+
if data_obj && grade_level == "Kindergarten" && name.blank?
|
|
125
|
+
# Note that `name` is an attribute on `Student` but `grade_level`
|
|
126
|
+
# is accessed through the `data` association as defined earlier
|
|
127
|
+
# in the README.
|
|
128
|
+
errors.add(:name, "must be present for kindergarten students")
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Documentation
|
|
134
|
+
|
|
135
|
+
We have documentation on [RubyDoc](http://www.rubydoc.info/github/panorama-ed/rails_external_fields/master).
|
|
136
|
+
|
|
137
|
+
## Contributing
|
|
138
|
+
|
|
139
|
+
1. Fork it (https://github.com/panorama-ed/rails_external_fields/fork)
|
|
140
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
141
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
142
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
143
|
+
5. Create a new Pull Request
|
|
144
|
+
|
|
145
|
+
**Make sure your changes have appropriate tests (`bundle exec rspec`)
|
|
146
|
+
and conform to the Rubocop style specified.** We use
|
|
147
|
+
[overcommit](https://github.com/causes/overcommit) to enforce good code.
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
`ExternalFields` is released under the
|
|
152
|
+
[MIT License](https://github.com/panorama-ed/rails_external_fields/blob/master/LICENSE).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require "external_fields/version"
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "external_fields"
|
|
8
|
+
spec.version = ExternalFields::VERSION
|
|
9
|
+
spec.authors = ["Sagar Jauhari"]
|
|
10
|
+
spec.email = ["sagarjauhari@gmail.com"]
|
|
11
|
+
spec.summary = "Access attributes from an associated model."
|
|
12
|
+
spec.description = "This concern maintains the illusion that a given "\
|
|
13
|
+
"object has specified attributes, when those "\
|
|
14
|
+
"attributes are in fact attached to an associated "\
|
|
15
|
+
"object. This is particularly useful for different "\
|
|
16
|
+
"classes within a single-table inheritance table to "\
|
|
17
|
+
"have access to separate fields in class-specific "\
|
|
18
|
+
"associations."
|
|
19
|
+
|
|
20
|
+
spec.homepage = "https://github.com/panorama-ed/rails-external-fields"
|
|
21
|
+
spec.license = "MIT"
|
|
22
|
+
|
|
23
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
24
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
25
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
26
|
+
spec.require_paths = ["lib"]
|
|
27
|
+
|
|
28
|
+
spec.add_dependency "activerecord", "~> 4.0"
|
|
29
|
+
|
|
30
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
|
31
|
+
spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4"
|
|
32
|
+
spec.add_development_dependency "overcommit", "~> 0.23"
|
|
33
|
+
spec.add_development_dependency "rspec", "~> 3.2"
|
|
34
|
+
spec.add_development_dependency "rspec-rails", "~> 3.2"
|
|
35
|
+
spec.add_development_dependency "rubocop", "~> 0.29"
|
|
36
|
+
spec.add_development_dependency "rubocop-rspec-focused", "~> 0.0"
|
|
37
|
+
spec.add_development_dependency "temping", "~> 3.2"
|
|
38
|
+
spec.add_development_dependency "sqlite3", "~> 1.3"
|
|
39
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require "external_fields/version"
|
|
2
|
+
|
|
3
|
+
# This concern maintains the illusion that a given object has specified
|
|
4
|
+
# attributes, when those attributes are in fact attached to an associated
|
|
5
|
+
# object. This is particularly useful for different classes within a single-
|
|
6
|
+
# table inheritance table to have access to separate fields in class-specific
|
|
7
|
+
# associations.
|
|
8
|
+
|
|
9
|
+
module ExternalFields
|
|
10
|
+
extend ActiveSupport::Concern
|
|
11
|
+
|
|
12
|
+
included do
|
|
13
|
+
class_attribute :_external_field_associations
|
|
14
|
+
|
|
15
|
+
# Provides a getter and setter for the given attribute on the associated
|
|
16
|
+
# object. We provide either normal or underscored getters and setters, the
|
|
17
|
+
# latter allowing the defining class to use alias_method to override
|
|
18
|
+
# behavior while still accessing these underlying implementations.
|
|
19
|
+
#
|
|
20
|
+
# @param attrs [Array<Symbol>] list of external fields
|
|
21
|
+
# @param assoc [Symbol] name of the association
|
|
22
|
+
# @param class_name [String] name of the associated class
|
|
23
|
+
# @param underscore [Boolean] underscored accessor created if true
|
|
24
|
+
def self.external_field(*attrs, assoc, class_name: nil, underscore: false)
|
|
25
|
+
self._external_field_associations ||= []
|
|
26
|
+
|
|
27
|
+
attrs.each do |attr|
|
|
28
|
+
# Store the original association method for use in the overwritten one.
|
|
29
|
+
original_method = instance_method(assoc)
|
|
30
|
+
|
|
31
|
+
# First, we define an accessor for the associated object.
|
|
32
|
+
# Note we ensure that we only define the accessor once. Further, if
|
|
33
|
+
# `use_original` is true, we use the original Rails association
|
|
34
|
+
# accessor, which will not build a new object. Otherwise, we build a new
|
|
35
|
+
# object if one does not exist already.
|
|
36
|
+
unless self._external_field_associations.include? assoc
|
|
37
|
+
define_method assoc do |use_original: false|
|
|
38
|
+
if use_original
|
|
39
|
+
# Call original overwritten method
|
|
40
|
+
original_method.bind(self).call
|
|
41
|
+
else
|
|
42
|
+
# Try calling the original method to see if we get a result.
|
|
43
|
+
existing_value = original_method.bind(self).call
|
|
44
|
+
|
|
45
|
+
# Use existing value if one is there.
|
|
46
|
+
if existing_value
|
|
47
|
+
existing_value
|
|
48
|
+
else # Otherwise, build a new object.
|
|
49
|
+
# Find the class of the object we need to build.
|
|
50
|
+
klass = class_name.try(:constantize) ||
|
|
51
|
+
self.class.reflect_on_association(assoc).klass
|
|
52
|
+
|
|
53
|
+
send("#{assoc}=", klass.new)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Now, define the getters for the specific attribute.
|
|
60
|
+
define_method(underscore ? "_#{attr}" : attr) do
|
|
61
|
+
send(assoc).try(attr)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Now, define the setters for the specific attribute.
|
|
65
|
+
define_method(underscore ? "_#{attr}=" : "#{attr}=") do |new_attr|
|
|
66
|
+
send(assoc).send("#{attr}=", new_attr)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Add the association name to the set of external field associations.
|
|
70
|
+
# This allows other parts of the codebase to quickly see all of the
|
|
71
|
+
# associations a class has that store external fields. This array stores
|
|
72
|
+
# association name symbols, like: [:address, :extra_data]
|
|
73
|
+
# Note that a Set could be used here but an Array was chosen for
|
|
74
|
+
# familiarity since the size of the array will be relatively small.
|
|
75
|
+
unless self._external_field_associations.include? assoc
|
|
76
|
+
# We need to duplicate the array because a subclass of a model with
|
|
77
|
+
# this mixin would otherwise modify its parent class' array, since the
|
|
78
|
+
# << operator works in-place.
|
|
79
|
+
self._external_field_associations =
|
|
80
|
+
self._external_field_associations.dup
|
|
81
|
+
|
|
82
|
+
self._external_field_associations << assoc
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe ExternalFields do
|
|
4
|
+
describe ".external_fields" do
|
|
5
|
+
describe "the association" do
|
|
6
|
+
Temping.create :test_class do
|
|
7
|
+
with_columns do |t|
|
|
8
|
+
t.string :name
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
include ExternalFields
|
|
12
|
+
|
|
13
|
+
has_one :assoc,
|
|
14
|
+
class_name: "AssociationTestClass"
|
|
15
|
+
|
|
16
|
+
external_field :ext_field_1,
|
|
17
|
+
:assoc,
|
|
18
|
+
class_name: "AssociationTestClass"
|
|
19
|
+
|
|
20
|
+
external_field :ext_field_2,
|
|
21
|
+
:assoc,
|
|
22
|
+
class_name: "AssociationTestClass",
|
|
23
|
+
underscore: true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Temping.create :association_test_class do
|
|
27
|
+
with_columns do |t|
|
|
28
|
+
t.integer :test_class_id
|
|
29
|
+
t.string :ext_field_1
|
|
30
|
+
t.string :ext_field_2
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
belongs_to :test_class
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Clean up after each test. This is a lot lighter for these few tests than
|
|
37
|
+
# trying to wrangle with RSpec-Rails to get transactional tests to work.
|
|
38
|
+
after :each do
|
|
39
|
+
TestClass.delete_all
|
|
40
|
+
AssociationTestClass.delete_all
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should be built on first access" do
|
|
44
|
+
e = TestClass.create!(name: "Hello")
|
|
45
|
+
|
|
46
|
+
expect(AssociationTestClass.count).to eq(0)
|
|
47
|
+
expect(e.assoc.class).to eq(AssociationTestClass)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should be saved when the model is saved" do
|
|
51
|
+
e = TestClass.create!(name: "Hello")
|
|
52
|
+
expect(AssociationTestClass.count).to eq(0)
|
|
53
|
+
expect(e.assoc.class).to eq(AssociationTestClass)
|
|
54
|
+
e.save!
|
|
55
|
+
expect(AssociationTestClass.count).to eq(1)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should not be created or saved if unused" do
|
|
59
|
+
e = TestClass.create!
|
|
60
|
+
e.name = "TEST"
|
|
61
|
+
e.save!
|
|
62
|
+
expect(AssociationTestClass.count).to eq(0)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "should be created if used" do
|
|
66
|
+
e = TestClass.create!(name: "Hello", ext_field_1: "Field1")
|
|
67
|
+
|
|
68
|
+
expect(AssociationTestClass.count).to eq(1)
|
|
69
|
+
expect(e.ext_field_1).to eq "Field1"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context "when underscore flag is true" do
|
|
73
|
+
it "should provide underscored methods" do
|
|
74
|
+
e = TestClass.create!(_ext_field_2: "_Field2")
|
|
75
|
+
|
|
76
|
+
expect(AssociationTestClass.count).to eq(1)
|
|
77
|
+
expect(e._ext_field_2).to eq "_Field2"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "should provide an accessor that does not build a new object" do
|
|
82
|
+
e = TestClass.new(name: "Hello")
|
|
83
|
+
|
|
84
|
+
e.assoc(use_original: true) # Access without creating
|
|
85
|
+
e.save!
|
|
86
|
+
expect(AssociationTestClass.count).to eq 0
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require "codeclimate-test-reporter"
|
|
2
|
+
CodeClimate::TestReporter.start
|
|
3
|
+
|
|
4
|
+
# Connect to an in-memory database for ActiveRecord tests.
|
|
5
|
+
require "temping"
|
|
6
|
+
ActiveRecord::Base.
|
|
7
|
+
establish_connection(adapter: "sqlite3", database: ":memory:")
|
|
8
|
+
|
|
9
|
+
require "external_fields"
|
|
10
|
+
|
|
11
|
+
RSpec.configure do |config|
|
|
12
|
+
# These two settings work together to allow you to limit a spec run
|
|
13
|
+
# to individual examples or groups you care about by tagging them with
|
|
14
|
+
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
|
15
|
+
# get run.
|
|
16
|
+
config.filter_run :focus
|
|
17
|
+
config.run_all_when_everything_filtered = true
|
|
18
|
+
|
|
19
|
+
# Limits the available syntax to the non-monkey patched syntax that is
|
|
20
|
+
# recommended.
|
|
21
|
+
# For more details, see:
|
|
22
|
+
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
|
23
|
+
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
|
24
|
+
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
|
|
25
|
+
config.disable_monkey_patching!
|
|
26
|
+
|
|
27
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
|
28
|
+
# file, and it's useful to allow more verbose output when running an
|
|
29
|
+
# individual spec file.
|
|
30
|
+
if config.files_to_run.one?
|
|
31
|
+
# Use the documentation formatter for detailed output,
|
|
32
|
+
# unless a formatter has already been configured
|
|
33
|
+
# (e.g. via a command-line flag).
|
|
34
|
+
config.default_formatter = "doc"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Run specs in random order to surface order dependencies. If you find an
|
|
38
|
+
# order dependency and want to debug it, you can fix the order by providing
|
|
39
|
+
# the seed, which is printed after each run.
|
|
40
|
+
# --seed 1234
|
|
41
|
+
config.order = :random
|
|
42
|
+
|
|
43
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
|
44
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
|
45
|
+
# test failures related to randomization by passing the same `--seed` value
|
|
46
|
+
# as the one that triggered the failure.
|
|
47
|
+
Kernel.srand config.seed
|
|
48
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: external_fields
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Sagar Jauhari
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-09-18 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activerecord
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '4.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '4.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.7'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.7'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: codeclimate-test-reporter
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0.4'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0.4'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: overcommit
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0.23'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0.23'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rspec
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '3.2'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '3.2'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rspec-rails
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '3.2'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '3.2'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rubocop
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0.29'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0.29'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: rubocop-rspec-focused
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - "~>"
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0.0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - "~>"
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0.0'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: temping
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - "~>"
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '3.2'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - "~>"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '3.2'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: sqlite3
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - "~>"
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '1.3'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - "~>"
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '1.3'
|
|
153
|
+
description: This concern maintains the illusion that a given object has specified
|
|
154
|
+
attributes, when those attributes are in fact attached to an associated object.
|
|
155
|
+
This is particularly useful for different classes within a single-table inheritance
|
|
156
|
+
table to have access to separate fields in class-specific associations.
|
|
157
|
+
email:
|
|
158
|
+
- sagarjauhari@gmail.com
|
|
159
|
+
executables: []
|
|
160
|
+
extensions: []
|
|
161
|
+
extra_rdoc_files: []
|
|
162
|
+
files:
|
|
163
|
+
- ".gitignore"
|
|
164
|
+
- ".overcommit.yml"
|
|
165
|
+
- ".rubocop.yml"
|
|
166
|
+
- ".travis.yml"
|
|
167
|
+
- Gemfile
|
|
168
|
+
- LICENSE
|
|
169
|
+
- README.md
|
|
170
|
+
- external_fields.gemspec
|
|
171
|
+
- lib/external_fields.rb
|
|
172
|
+
- lib/external_fields/version.rb
|
|
173
|
+
- spec/external_fields_spec.rb
|
|
174
|
+
- spec/spec_helper.rb
|
|
175
|
+
homepage: https://github.com/panorama-ed/rails-external-fields
|
|
176
|
+
licenses:
|
|
177
|
+
- MIT
|
|
178
|
+
metadata: {}
|
|
179
|
+
post_install_message:
|
|
180
|
+
rdoc_options: []
|
|
181
|
+
require_paths:
|
|
182
|
+
- lib
|
|
183
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
184
|
+
requirements:
|
|
185
|
+
- - ">="
|
|
186
|
+
- !ruby/object:Gem::Version
|
|
187
|
+
version: '0'
|
|
188
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
189
|
+
requirements:
|
|
190
|
+
- - ">="
|
|
191
|
+
- !ruby/object:Gem::Version
|
|
192
|
+
version: '0'
|
|
193
|
+
requirements: []
|
|
194
|
+
rubyforge_project:
|
|
195
|
+
rubygems_version: 2.4.8
|
|
196
|
+
signing_key:
|
|
197
|
+
specification_version: 4
|
|
198
|
+
summary: Access attributes from an associated model.
|
|
199
|
+
test_files:
|
|
200
|
+
- spec/external_fields_spec.rb
|
|
201
|
+
- spec/spec_helper.rb
|
|
202
|
+
has_rdoc:
|