her 0.5.3 → 0.5.4
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 +8 -8
- data/.gitignore +2 -2
- data/.rspec +1 -2
- data/.travis.yml +2 -2
- data/README.md +10 -16
- data/UPGRADE.md +4 -0
- data/examples/grape-and-her/.env.default +3 -0
- data/examples/grape-and-her/Procfile +2 -0
- data/examples/grape-and-her/README.md +27 -0
- data/examples/grape-and-her/api/Gemfile +11 -0
- data/examples/grape-and-her/api/Rakefile +14 -0
- data/examples/grape-and-her/api/app/api.rb +49 -0
- data/examples/grape-and-her/api/app/models/organization.rb +7 -0
- data/examples/grape-and-her/api/app/models/user.rb +9 -0
- data/examples/grape-and-her/api/app/views/organizations/_base.rabl +2 -0
- data/examples/grape-and-her/api/app/views/organizations/index.rabl +3 -0
- data/examples/grape-and-her/api/app/views/organizations/show.rabl +3 -0
- data/examples/grape-and-her/api/app/views/users/_base.rabl +8 -0
- data/examples/grape-and-her/api/app/views/users/index.rabl +3 -0
- data/examples/grape-and-her/api/app/views/users/show.rabl +3 -0
- data/examples/grape-and-her/api/config.ru +5 -0
- data/examples/grape-and-her/api/config/boot.rb +17 -0
- data/examples/grape-and-her/api/config/unicorn.rb +7 -0
- data/examples/grape-and-her/api/db/migrations/001_create_users.rb +11 -0
- data/examples/grape-and-her/api/db/migrations/002_create_organizations.rb +8 -0
- data/examples/grape-and-her/consumer/Gemfile +23 -0
- data/examples/grape-and-her/consumer/app/assets/stylesheets/application.scss +190 -0
- data/examples/grape-and-her/consumer/app/assets/stylesheets/reset.scss +53 -0
- data/examples/grape-and-her/consumer/app/consumer.rb +74 -0
- data/examples/grape-and-her/consumer/app/models/organization.rb +13 -0
- data/examples/grape-and-her/consumer/app/models/user.rb +13 -0
- data/examples/grape-and-her/consumer/app/views/index.haml +9 -0
- data/examples/grape-and-her/consumer/app/views/layout.haml +20 -0
- data/examples/grape-and-her/consumer/app/views/organizations/index.haml +25 -0
- data/examples/grape-and-her/consumer/app/views/organizations/show.haml +11 -0
- data/examples/grape-and-her/consumer/app/views/users/index.haml +33 -0
- data/examples/grape-and-her/consumer/app/views/users/show.haml +9 -0
- data/examples/grape-and-her/consumer/config.ru +20 -0
- data/examples/grape-and-her/consumer/config/boot.rb +30 -0
- data/examples/grape-and-her/consumer/config/unicorn.rb +7 -0
- data/examples/grape-and-her/consumer/lib/response_logger.rb +18 -0
- data/her.gemspec +2 -2
- data/lib/her/model.rb +22 -26
- data/lib/her/model/associations.rb +19 -19
- data/lib/her/model/attributes.rb +173 -0
- data/lib/her/model/base.rb +17 -0
- data/lib/her/model/http.rb +58 -242
- data/lib/her/model/introspection.rb +7 -8
- data/lib/her/model/nested_attributes.rb +3 -3
- data/lib/her/model/orm.rb +15 -205
- data/lib/her/model/parse.rb +86 -0
- data/lib/her/model/paths.rb +54 -14
- data/lib/her/version.rb +1 -1
- data/spec/model/attributes_spec.rb +139 -0
- data/spec/model/dirty_spec.rb +40 -0
- data/spec/model/introspection_spec.rb +5 -5
- data/spec/model/orm_spec.rb +14 -128
- data/spec/model/paths_spec.rb +26 -0
- data/spec/model/validations_spec.rb +17 -0
- data/spec/spec_helper.rb +7 -32
- data/spec/support/extensions/array.rb +5 -0
- data/spec/support/extensions/hash.rb +5 -0
- data/spec/support/macros/model_macros.rb +29 -0
- metadata +52 -15
- data/examples/twitter-oauth/Gemfile +0 -13
- data/examples/twitter-oauth/app.rb +0 -50
- data/examples/twitter-oauth/config.ru +0 -5
- data/examples/twitter-oauth/views/index.haml +0 -9
- data/examples/twitter-search/Gemfile +0 -12
- data/examples/twitter-search/app.rb +0 -55
- data/examples/twitter-search/config.ru +0 -5
- data/examples/twitter-search/views/index.haml +0 -9
@@ -30,24 +30,23 @@ module Her
|
|
30
30
|
module ClassMethods
|
31
31
|
# Finds a class at the same level as this one or at the global level.
|
32
32
|
# @private
|
33
|
-
def
|
34
|
-
|
33
|
+
def her_nearby_class(name)
|
34
|
+
her_sibling_class(name) || name.constantize rescue nil
|
35
35
|
end
|
36
36
|
|
37
37
|
protected
|
38
38
|
# Looks for a class at the same level as this one with the given name.
|
39
39
|
# @private
|
40
|
-
def
|
41
|
-
if mod = self.
|
42
|
-
@
|
43
|
-
@
|
44
|
-
@sibling_class[mod][name] ||= "#{mod.name}::#{name}".constantize rescue nil
|
40
|
+
def her_sibling_class(name)
|
41
|
+
if mod = self.her_containing_module
|
42
|
+
@_her_sibling_class ||= Hash.new { Hash.new }
|
43
|
+
@_her_sibling_class[mod][name] ||= "#{mod.name}::#{name}".constantize rescue nil
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
48
47
|
# If available, returns the containing Module for this class.
|
49
48
|
# @private
|
50
|
-
def
|
49
|
+
def her_containing_module
|
51
50
|
return unless self.name =~ /::/
|
52
51
|
self.name.split("::")[0..-2].join("::").constantize
|
53
52
|
end
|
@@ -37,8 +37,8 @@ module Her
|
|
37
37
|
|
38
38
|
def assign_nested_attributes_for_has_many_association(association_name, attributes)
|
39
39
|
association = self.class.associations[:has_many].find { |association| association[:name] == association_name }
|
40
|
-
klass = self.class.
|
41
|
-
self.send("#{association[:name]}=", Her::Model::
|
40
|
+
klass = self.class.her_nearby_class(association[:class_name])
|
41
|
+
self.send("#{association[:name]}=", Her::Model::Attributes.initialize_collection(klass, :data => attributes))
|
42
42
|
end
|
43
43
|
|
44
44
|
private
|
@@ -47,7 +47,7 @@ module Her
|
|
47
47
|
if has_data?(association[:name])
|
48
48
|
self.send("#{association[:name]}").assign_data(attributes)
|
49
49
|
else
|
50
|
-
klass = self.class.
|
50
|
+
klass = self.class.her_nearby_class(association[:class_name])
|
51
51
|
instance = klass.new(klass.parse(attributes))
|
52
52
|
self.send("#{association[:name]}=", instance)
|
53
53
|
end
|
data/lib/her/model/orm.rb
CHANGED
@@ -3,125 +3,20 @@ module Her
|
|
3
3
|
# This module adds ORM-like capabilities to the model
|
4
4
|
module ORM
|
5
5
|
extend ActiveSupport::Concern
|
6
|
-
attr_accessor :attributes, :metadata, :response_errors
|
7
|
-
alias :data :attributes
|
8
|
-
alias :data= :attributes=
|
9
|
-
|
10
|
-
# Initialize a new object with data received from an HTTP request
|
11
|
-
def initialize(attributes={})
|
12
|
-
attributes ||= {}
|
13
|
-
@metadata = attributes.delete(:_metadata) || {}
|
14
|
-
@response_errors = attributes.delete(:_errors) || {}
|
15
|
-
@destroyed = attributes.delete(:_destroyed) || false
|
16
|
-
|
17
|
-
update_attributes(attributes)
|
18
|
-
end
|
19
|
-
|
20
|
-
# Initialize a collection of resources
|
21
|
-
# @private
|
22
|
-
def self.initialize_collection(klass, parsed_data={})
|
23
|
-
collection_data = parsed_data[:data].map do |item_data|
|
24
|
-
resource = klass.new(klass.parse(item_data))
|
25
|
-
resource.run_callbacks :find
|
26
|
-
resource
|
27
|
-
end
|
28
|
-
Her::Collection.new(collection_data, parsed_data[:metadata], parsed_data[:errors])
|
29
|
-
end
|
30
|
-
|
31
|
-
# Use setter methods of model for each key / value pair in params
|
32
|
-
# Return key / value pairs for which no setter method was defined on the model
|
33
|
-
# @private
|
34
|
-
def self.use_setter_methods(model, params)
|
35
|
-
setter_method_names = model.class.setter_method_names
|
36
|
-
params ||= {}
|
37
|
-
params.inject({}) do |memo, (key, value)|
|
38
|
-
setter_method = key.to_s + '='
|
39
|
-
if setter_method_names.include?(setter_method)
|
40
|
-
model.send(setter_method, value)
|
41
|
-
else
|
42
|
-
if key.is_a?(String)
|
43
|
-
key = key.to_sym
|
44
|
-
end
|
45
|
-
memo[key] = value
|
46
|
-
end
|
47
|
-
memo
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Handles missing methods
|
52
|
-
# @private
|
53
|
-
def method_missing(method, *args, &blk)
|
54
|
-
if method.to_s =~ /[?=]$/ || attributes.include?(method)
|
55
|
-
# Extract the attribute
|
56
|
-
attribute = method.to_s.sub(/[?=]$/, '')
|
57
|
-
|
58
|
-
# Create a new `attribute` methods set
|
59
|
-
self.class.attributes(*attribute)
|
60
|
-
|
61
|
-
# Resend the method!
|
62
|
-
send(method, *args, &blk)
|
63
|
-
else
|
64
|
-
super
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# Handles returning true for the cases handled by method_missing
|
69
|
-
def respond_to?(method, include_private = false)
|
70
|
-
method.to_s.end_with?('=') || method.to_s.end_with?('?') || @attributes.include?(method) || super
|
71
|
-
end
|
72
|
-
|
73
|
-
def respond_to_missing?(method, include_private = false)
|
74
|
-
method.to_s.end_with?('=') || method.to_s.end_with?('?') || @attributes.include?(method) || @attributes.include?(method) || super
|
75
|
-
end
|
76
|
-
|
77
|
-
# Assign new data to an instance
|
78
|
-
def assign_attributes(new_attributes)
|
79
|
-
new_attributes = Her::Model::ORM.use_setter_methods(self, new_attributes)
|
80
|
-
attributes.update new_attributes
|
81
|
-
end
|
82
|
-
alias :assign_data :assign_attributes
|
83
|
-
|
84
|
-
# Handles returning true for the accessible attributes
|
85
|
-
def has_attribute?(attribute_name)
|
86
|
-
attributes.include?(attribute_name)
|
87
|
-
end
|
88
|
-
alias :has_data? :has_attribute?
|
89
|
-
|
90
|
-
def get_attribute(attribute_name)
|
91
|
-
attributes[attribute_name]
|
92
|
-
end
|
93
|
-
alias :get_data :get_attribute
|
94
|
-
|
95
|
-
# Override the method to prevent from returning the object ID (in ruby-1.8.7)
|
96
|
-
# @private
|
97
|
-
def id
|
98
|
-
attributes[:id] || super
|
99
|
-
end
|
100
6
|
|
101
7
|
# Return `true` if a resource was not saved yet
|
102
8
|
def new?
|
103
|
-
|
9
|
+
attributes[self.class.primary_key].nil?
|
104
10
|
end
|
105
11
|
|
106
|
-
# Return `true` if
|
107
|
-
def
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
# Delegate to the == method
|
112
|
-
def eql?(other)
|
113
|
-
self == other
|
114
|
-
end
|
115
|
-
|
116
|
-
# Delegate to @attributes, allowing models to act correctly in code like:
|
117
|
-
# [ Model.find(1), Model.find(1) ].uniq # => [ Model.find(1) ]
|
118
|
-
def hash
|
119
|
-
attributes.hash
|
12
|
+
# Return `true` if a resource is not `#new?`
|
13
|
+
def persisted?
|
14
|
+
!new?
|
120
15
|
end
|
121
16
|
|
122
17
|
# Return whether the object has been destroyed
|
123
18
|
def destroyed?
|
124
|
-
@destroyed
|
19
|
+
@destroyed == true
|
125
20
|
end
|
126
21
|
|
127
22
|
# Save a resource
|
@@ -141,18 +36,18 @@ module Her
|
|
141
36
|
params = to_params
|
142
37
|
resource = self
|
143
38
|
|
144
|
-
if
|
145
|
-
callback = :update
|
146
|
-
method = :put
|
147
|
-
else
|
39
|
+
if new?
|
148
40
|
callback = :create
|
149
41
|
method = :post
|
42
|
+
else
|
43
|
+
callback = :update
|
44
|
+
method = :put
|
150
45
|
end
|
151
46
|
|
152
47
|
run_callbacks callback do
|
153
48
|
run_callbacks :save do
|
154
49
|
self.class.request(params.merge(:_method => method, :_path => "#{request_path}")) do |parsed_data, response|
|
155
|
-
|
50
|
+
assign_attributes(self.class.parse(parsed_data[:data])) if parsed_data[:data].any?
|
156
51
|
self.metadata = parsed_data[:metadata]
|
157
52
|
self.response_errors = parsed_data[:errors]
|
158
53
|
self.changed_attributes.clear if self.changed_attributes.present?
|
@@ -175,7 +70,7 @@ module Her
|
|
175
70
|
resource = self
|
176
71
|
run_callbacks :destroy do
|
177
72
|
self.class.request(:_method => :delete, :_path => "#{request_path}") do |parsed_data, response|
|
178
|
-
|
73
|
+
assign_attributes(self.class.parse(parsed_data[:data])) if parsed_data[:data].any?
|
179
74
|
self.metadata = parsed_data[:metadata]
|
180
75
|
self.response_errors = parsed_data[:errors]
|
181
76
|
@destroyed = true
|
@@ -184,72 +79,7 @@ module Her
|
|
184
79
|
self
|
185
80
|
end
|
186
81
|
|
187
|
-
# @private
|
188
|
-
def update_attributes(raw_data)
|
189
|
-
@attributes ||= {}
|
190
|
-
# Use setter methods first, then translate attributes of associations
|
191
|
-
# into association instances, then merge the parsed_data into @attributes.
|
192
|
-
unset_attributes = Her::Model::ORM.use_setter_methods(self, raw_data)
|
193
|
-
parsed_attributes = self.class.parse_associations(unset_attributes)
|
194
|
-
attributes.update(parsed_attributes)
|
195
|
-
end
|
196
|
-
|
197
|
-
# Convert into a hash of request parameters
|
198
|
-
#
|
199
|
-
# @example
|
200
|
-
# @user.to_params
|
201
|
-
# # => { :id => 1, :name => 'John Smith' }
|
202
|
-
def to_params
|
203
|
-
if self.class.include_root_in_json
|
204
|
-
{ (self.class.include_root_in_json == true ? self.class.root_element : self.class.include_root_in_json) => attributes.dup }
|
205
|
-
else
|
206
|
-
attributes.dup
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
82
|
module ClassMethods
|
211
|
-
# Initialize a collection of resources with raw data from an HTTP request
|
212
|
-
#
|
213
|
-
# @param [Array] parsed_data
|
214
|
-
def new_collection(parsed_data)
|
215
|
-
Her::Model::ORM.initialize_collection(self, parsed_data)
|
216
|
-
end
|
217
|
-
|
218
|
-
# Define the attributes that will be used to track dirty attributes and validations
|
219
|
-
#
|
220
|
-
# @param [Array] attributes
|
221
|
-
def attributes(*attributes)
|
222
|
-
define_attribute_methods attributes
|
223
|
-
|
224
|
-
attributes.each do |attribute|
|
225
|
-
attribute = attribute.to_sym
|
226
|
-
|
227
|
-
define_method "#{attribute}".to_sym do
|
228
|
-
@attributes.include?(attribute) ? @attributes[attribute] : nil
|
229
|
-
end
|
230
|
-
|
231
|
-
define_method "#{attribute}=".to_sym do |value|
|
232
|
-
self.send("#{attribute}_will_change!".to_sym) if @attributes[attribute] != value
|
233
|
-
@attributes[attribute] = value
|
234
|
-
end
|
235
|
-
|
236
|
-
define_method "#{attribute}?".to_sym do
|
237
|
-
@attributes.include?(attribute) && @attributes[attribute].present?
|
238
|
-
end
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
# Parse data before assigning it to a resource
|
243
|
-
#
|
244
|
-
# @param [Hash] data
|
245
|
-
def parse(data)
|
246
|
-
if parse_root_in_json
|
247
|
-
parse_root_in_json == true ? data[root_element.to_sym] : data[parse_root_in_json]
|
248
|
-
else
|
249
|
-
data
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
83
|
# Fetch specific resource(s) by their ID
|
254
84
|
#
|
255
85
|
# @example
|
@@ -263,7 +93,7 @@ module Her
|
|
263
93
|
params = ids.last.is_a?(Hash) ? ids.pop : {}
|
264
94
|
results = ids.flatten.compact.uniq.map do |id|
|
265
95
|
resource = nil
|
266
|
-
request(params.merge(:_method => :get, :_path => "#{build_request_path(params.merge(
|
96
|
+
request(params.merge(:_method => :get, :_path => "#{build_request_path(params.merge(primary_key => id))}")) do |parsed_data, response|
|
267
97
|
if response.success?
|
268
98
|
resource = new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:metadata], :_errors => parsed_data[:errors])
|
269
99
|
resource.run_callbacks :find
|
@@ -304,7 +134,7 @@ module Her
|
|
304
134
|
request(params.merge(:_method => :post, :_path => "#{build_request_path(params)}")) do |parsed_data, response|
|
305
135
|
data = parse(parsed_data[:data])
|
306
136
|
resource.instance_eval do
|
307
|
-
|
137
|
+
assign_attributes(data)
|
308
138
|
@metadata = parsed_data[:metadata]
|
309
139
|
@response_errors = parsed_data[:errors]
|
310
140
|
@changed_attributes.clear if @changed_attributes.present?
|
@@ -321,7 +151,7 @@ module Her
|
|
321
151
|
# @user = User.save_existing(1, { :fullname => "Tobias Fünke" })
|
322
152
|
# # Called via PUT "/users/1"
|
323
153
|
def save_existing(id, params)
|
324
|
-
resource = new(params.merge(
|
154
|
+
resource = new(params.merge(primary_key => id))
|
325
155
|
resource.save
|
326
156
|
resource
|
327
157
|
end
|
@@ -332,30 +162,10 @@ module Her
|
|
332
162
|
# User.destroy_existing(1)
|
333
163
|
# # Called via DELETE "/users/1"
|
334
164
|
def destroy_existing(id, params={})
|
335
|
-
request(params.merge(:_method => :delete, :_path => "#{build_request_path(params.merge(
|
165
|
+
request(params.merge(:_method => :delete, :_path => "#{build_request_path(params.merge(primary_key => id))}")) do |parsed_data, response|
|
336
166
|
new(parse(parsed_data[:data]).merge(:_destroyed => true))
|
337
167
|
end
|
338
168
|
end
|
339
|
-
|
340
|
-
# @private
|
341
|
-
def setter_method_names
|
342
|
-
@setter_method_names ||= instance_methods.inject(Set.new) do |memo, method_name|
|
343
|
-
memo << method_name.to_s if method_name.to_s.end_with?('=')
|
344
|
-
memo
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
# Return or change the value of `include_root_in_json`
|
349
|
-
def include_root_in_json(value=nil)
|
350
|
-
return @include_root_in_json if value.nil?
|
351
|
-
@include_root_in_json = value
|
352
|
-
end
|
353
|
-
|
354
|
-
# Return or change the value of `parse_root_in`
|
355
|
-
def parse_root_in_json(value=nil)
|
356
|
-
return @parse_root_in_json if value.nil?
|
357
|
-
@parse_root_in_json = value
|
358
|
-
end
|
359
169
|
end
|
360
170
|
end
|
361
171
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Her
|
2
|
+
module Model
|
3
|
+
# This module handles resource data parsing at the model level (after the parsing middleware)
|
4
|
+
module Parse
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
# Convert into a hash of request parameters, based on `include_root_in_json`.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# @user.to_params
|
11
|
+
# # => { :id => 1, :name => 'John Smith' }
|
12
|
+
def to_params
|
13
|
+
self.class.include_root_in_json? ? { self.class.included_root_element => attributes.dup } : attributes.dup
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
# Parse data before assigning it to a resource, based on `parse_root_in_json`.
|
18
|
+
#
|
19
|
+
# @param [Hash] data
|
20
|
+
def parse(data)
|
21
|
+
parse_root_in_json? ? data[parsed_root_element] : data
|
22
|
+
end
|
23
|
+
|
24
|
+
# Return or change the value of `include_root_in_json`
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# class User
|
28
|
+
# include Her::Model
|
29
|
+
# include_root_in_json true
|
30
|
+
# end
|
31
|
+
def include_root_in_json(value=nil)
|
32
|
+
return @include_root_in_json if value.nil?
|
33
|
+
@include_root_in_json = value
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return or change the value of `parse_root_in`
|
37
|
+
#
|
38
|
+
# @example
|
39
|
+
# class User
|
40
|
+
# include Her::Model
|
41
|
+
# parse_root_in_json true
|
42
|
+
# end
|
43
|
+
def parse_root_in_json(value=nil)
|
44
|
+
return @parse_root_in_json if value.nil?
|
45
|
+
@parse_root_in_json = value
|
46
|
+
end
|
47
|
+
|
48
|
+
# Return or change the value of `root_element`
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# class User
|
52
|
+
# include Her::Model
|
53
|
+
# parse_root_in_json true
|
54
|
+
# root_element :huh
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# user = User.find(1) # { :huh => { :id => 1, :name => "Tobias" } }
|
58
|
+
# user.name # => "Tobias"
|
59
|
+
def root_element(value=nil)
|
60
|
+
return @root_element if value.nil?
|
61
|
+
@root_element = value
|
62
|
+
end
|
63
|
+
|
64
|
+
# @private
|
65
|
+
def parse_root_in_json?
|
66
|
+
@parse_root_in_json
|
67
|
+
end
|
68
|
+
|
69
|
+
# @private
|
70
|
+
def include_root_in_json?
|
71
|
+
@include_root_in_json
|
72
|
+
end
|
73
|
+
|
74
|
+
# @private
|
75
|
+
def included_root_element
|
76
|
+
include_root_in_json == true ? root_element.to_sym : include_root_in_json
|
77
|
+
end
|
78
|
+
|
79
|
+
# @private
|
80
|
+
def parsed_root_element
|
81
|
+
parse_root_in_json == true ? root_element.to_sym : parse_root_in_json
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/her/model/paths.rb
CHANGED
@@ -11,12 +11,29 @@ module Her
|
|
11
11
|
# end
|
12
12
|
#
|
13
13
|
# User.find(1) # Fetched via GET /utilisateurs/1
|
14
|
-
|
15
|
-
|
14
|
+
#
|
15
|
+
# @param [Hash] params An optional set of additional parameters for
|
16
|
+
# path construction. These will not override attributes of the resource.
|
17
|
+
def request_path(params = {})
|
18
|
+
self.class.build_request_path(params.merge(attributes.dup))
|
16
19
|
end
|
17
20
|
|
18
21
|
module ClassMethods
|
19
22
|
|
23
|
+
# Define the primary key field that will be used to find and save records
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# class User
|
27
|
+
# include Her::Model
|
28
|
+
# primary_key 'UserId'
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# @param [Symbol] field
|
32
|
+
def primary_key(field = nil)
|
33
|
+
return @her_primary_key if field.nil?
|
34
|
+
@her_primary_key = field.to_sym
|
35
|
+
end
|
36
|
+
|
20
37
|
# Defines a custom collection path for the resource
|
21
38
|
#
|
22
39
|
# @example
|
@@ -25,13 +42,13 @@ module Her
|
|
25
42
|
# collection_path "/users"
|
26
43
|
# end
|
27
44
|
def collection_path(path=nil)
|
28
|
-
@
|
45
|
+
@_her_collection_path ||= begin
|
29
46
|
superclass.collection_path.dup if superclass.respond_to?(:collection_path)
|
30
47
|
end
|
31
48
|
|
32
|
-
return @
|
33
|
-
@
|
34
|
-
@
|
49
|
+
return @_her_collection_path unless path
|
50
|
+
@_her_resource_path = "#{path}/:id"
|
51
|
+
@_her_collection_path = path
|
35
52
|
end
|
36
53
|
|
37
54
|
# Defines a custom resource path for the resource
|
@@ -41,13 +58,29 @@ module Her
|
|
41
58
|
# include Her::Model
|
42
59
|
# resource_path "/users/:id"
|
43
60
|
# end
|
61
|
+
#
|
62
|
+
# Note that, if used in combination with resource_path, you may specify
|
63
|
+
# either the real primary key or the string ':id'. For example:
|
64
|
+
#
|
65
|
+
# @example
|
66
|
+
# class User
|
67
|
+
# include Her::Model
|
68
|
+
# primary_key 'user_id'
|
69
|
+
#
|
70
|
+
# # This works because we'll have a user_id attribute
|
71
|
+
# resource_path '/users/:user_id'
|
72
|
+
#
|
73
|
+
# # This works because we replace :id with :user_id
|
74
|
+
# resource_path '/users/:id'
|
75
|
+
# end
|
76
|
+
#
|
44
77
|
def resource_path(path=nil)
|
45
|
-
@
|
78
|
+
@_her_resource_path ||= begin
|
46
79
|
superclass.resource_path.dup if superclass.respond_to?(:resource_path)
|
47
80
|
end
|
48
81
|
|
49
|
-
return @
|
50
|
-
@
|
82
|
+
return @_her_resource_path unless path
|
83
|
+
@_her_resource_path = path
|
51
84
|
end
|
52
85
|
|
53
86
|
# Return a custom path based on the collection path and variable parameters
|
@@ -62,7 +95,15 @@ module Her
|
|
62
95
|
def build_request_path(path=nil, parameters={})
|
63
96
|
unless path.is_a?(String)
|
64
97
|
parameters = path || {}
|
65
|
-
path =
|
98
|
+
path =
|
99
|
+
if parameters.include?(primary_key) && parameters[primary_key]
|
100
|
+
resource_path.dup
|
101
|
+
else
|
102
|
+
collection_path.dup
|
103
|
+
end
|
104
|
+
|
105
|
+
# Replace :id with our actual primary key
|
106
|
+
path.gsub!(/(\A|\/):id(\Z|\/)/, "\\1:#{primary_key}\\2")
|
66
107
|
end
|
67
108
|
|
68
109
|
path.gsub(/:([\w_]+)/) do
|
@@ -71,10 +112,9 @@ module Her
|
|
71
112
|
end
|
72
113
|
end
|
73
114
|
|
74
|
-
#
|
75
|
-
def
|
76
|
-
|
77
|
-
@root_element = value
|
115
|
+
# @private
|
116
|
+
def build_request_path_from_string_or_symbol(path, attrs={})
|
117
|
+
path.is_a?(Symbol) ? "#{build_request_path(attrs)}/#{path}" : path
|
78
118
|
end
|
79
119
|
end
|
80
120
|
end
|