test_track_rails_client 0.9.7 → 0.9.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +11 -8
- data/lib/test_track_rails_client/version.rb +1 -1
- data/vendor/gems/fakeable_her/fakeable_her.gemspec +22 -0
- data/vendor/gems/fakeable_her/lib/fakeable_her/model.rb +148 -0
- data/vendor/gems/fakeable_her/lib/fakeable_her/version.rb +3 -0
- data/vendor/gems/fakeable_her/lib/fakeable_her.rb +5 -0
- data/vendor/gems/her/CONTRIBUTING.md +26 -0
- data/vendor/gems/her/Gemfile +10 -0
- data/vendor/gems/her/LICENSE +7 -0
- data/vendor/gems/her/README.md +1023 -0
- data/vendor/gems/her/Rakefile +11 -0
- data/vendor/gems/her/UPGRADE.md +101 -0
- data/vendor/gems/her/gemfiles/Gemfile.activemodel-3.2.x +7 -0
- data/vendor/gems/her/gemfiles/Gemfile.activemodel-4.0 +7 -0
- data/vendor/gems/her/gemfiles/Gemfile.activemodel-4.1 +7 -0
- data/vendor/gems/her/gemfiles/Gemfile.activemodel-4.2 +7 -0
- data/vendor/gems/her/her.gemspec +31 -0
- data/vendor/gems/her/lib/her/api.rb +119 -0
- data/vendor/gems/her/lib/her/collection.rb +12 -0
- data/vendor/gems/her/lib/her/error_collection.rb +15 -0
- data/vendor/gems/her/lib/her/errors.rb +40 -0
- data/vendor/gems/her/lib/her/json_api/model.rb +46 -0
- data/vendor/gems/her/lib/her/middleware/accept_json.rb +17 -0
- data/vendor/gems/her/lib/her/middleware/first_level_parse_json.rb +36 -0
- data/vendor/gems/her/lib/her/middleware/json_api_parser.rb +36 -0
- data/vendor/gems/her/lib/her/middleware/parse_json.rb +21 -0
- data/vendor/gems/her/lib/her/middleware/second_level_parse_json.rb +36 -0
- data/vendor/gems/her/lib/her/middleware.rb +12 -0
- data/vendor/gems/her/lib/her/model/active_model_overrides.rb +13 -0
- data/vendor/gems/her/lib/her/model/associations/association.rb +106 -0
- data/vendor/gems/her/lib/her/model/associations/association_proxy.rb +46 -0
- data/vendor/gems/her/lib/her/model/associations/belongs_to_association.rb +96 -0
- data/vendor/gems/her/lib/her/model/associations/has_many_association.rb +100 -0
- data/vendor/gems/her/lib/her/model/associations/has_one_association.rb +79 -0
- data/vendor/gems/her/lib/her/model/associations.rb +141 -0
- data/vendor/gems/her/lib/her/model/attributes.rb +304 -0
- data/vendor/gems/her/lib/her/model/base.rb +33 -0
- data/vendor/gems/her/lib/her/model/deprecated_methods.rb +61 -0
- data/vendor/gems/her/lib/her/model/http.rb +117 -0
- data/vendor/gems/her/lib/her/model/introspection.rb +65 -0
- data/vendor/gems/her/lib/her/model/nested_attributes.rb +45 -0
- data/vendor/gems/her/lib/her/model/orm.rb +219 -0
- data/vendor/gems/her/lib/her/model/parse.rb +215 -0
- data/vendor/gems/her/lib/her/model/paths.rb +126 -0
- data/vendor/gems/her/lib/her/model/relation.rb +251 -0
- data/vendor/gems/her/lib/her/model.rb +81 -0
- data/vendor/gems/her/lib/her/version.rb +3 -0
- data/vendor/gems/her/lib/her.rb +20 -0
- data/vendor/gems/her/spec/api_spec.rb +114 -0
- data/vendor/gems/her/spec/collection_spec.rb +26 -0
- data/vendor/gems/her/spec/error_collection_spec.rb +33 -0
- data/vendor/gems/her/spec/json_api/model_spec.rb +168 -0
- data/vendor/gems/her/spec/middleware/accept_json_spec.rb +10 -0
- data/vendor/gems/her/spec/middleware/first_level_parse_json_spec.rb +62 -0
- data/vendor/gems/her/spec/middleware/json_api_parser_spec.rb +32 -0
- data/vendor/gems/her/spec/middleware/second_level_parse_json_spec.rb +35 -0
- data/vendor/gems/her/spec/model/associations/association_proxy_spec.rb +31 -0
- data/vendor/gems/her/spec/model/associations_spec.rb +504 -0
- data/vendor/gems/her/spec/model/attributes_spec.rb +404 -0
- data/vendor/gems/her/spec/model/callbacks_spec.rb +145 -0
- data/vendor/gems/her/spec/model/dirty_spec.rb +110 -0
- data/vendor/gems/her/spec/model/http_spec.rb +165 -0
- data/vendor/gems/her/spec/model/introspection_spec.rb +76 -0
- data/vendor/gems/her/spec/model/nested_attributes_spec.rb +134 -0
- data/vendor/gems/her/spec/model/orm_spec.rb +791 -0
- data/vendor/gems/her/spec/model/parse_spec.rb +372 -0
- data/vendor/gems/her/spec/model/paths_spec.rb +347 -0
- data/vendor/gems/her/spec/model/relation_spec.rb +226 -0
- data/vendor/gems/her/spec/model/validations_spec.rb +42 -0
- data/vendor/gems/her/spec/model_spec.rb +31 -0
- data/vendor/gems/her/spec/spec_helper.rb +27 -0
- data/vendor/gems/her/spec/support/extensions/array.rb +5 -0
- data/vendor/gems/her/spec/support/extensions/hash.rb +5 -0
- data/vendor/gems/her/spec/support/macros/her_macros.rb +17 -0
- data/vendor/gems/her/spec/support/macros/model_macros.rb +36 -0
- data/vendor/gems/her/spec/support/macros/request_macros.rb +27 -0
- data/vendor/gems/publicsuffix-ruby/CHANGELOG.md +236 -0
- data/vendor/gems/publicsuffix-ruby/Gemfile +3 -0
- data/vendor/gems/publicsuffix-ruby/LICENSE.txt +22 -0
- data/vendor/gems/publicsuffix-ruby/README.md +151 -0
- data/vendor/gems/publicsuffix-ruby/Rakefile +109 -0
- data/vendor/gems/publicsuffix-ruby/lib/definitions.txt +11467 -0
- data/vendor/gems/publicsuffix-ruby/lib/public_suffix/domain.rb +387 -0
- data/vendor/gems/publicsuffix-ruby/lib/public_suffix/errors.rb +53 -0
- data/vendor/gems/publicsuffix-ruby/lib/public_suffix/list.rb +302 -0
- data/vendor/gems/publicsuffix-ruby/lib/public_suffix/rule.rb +373 -0
- data/vendor/gems/publicsuffix-ruby/lib/public_suffix/version.rb +23 -0
- data/vendor/gems/publicsuffix-ruby/lib/public_suffix.rb +131 -0
- data/vendor/gems/publicsuffix-ruby/public_suffix.gemspec +39 -0
- data/vendor/gems/publicsuffix-ruby/test/acceptance_test.rb +42 -0
- data/vendor/gems/publicsuffix-ruby/test/test_helper.rb +6 -0
- data/vendor/gems/publicsuffix-ruby/test/unit/domain_test.rb +170 -0
- data/vendor/gems/publicsuffix-ruby/test/unit/errors_test.rb +23 -0
- data/vendor/gems/publicsuffix-ruby/test/unit/list_test.rb +179 -0
- data/vendor/gems/publicsuffix-ruby/test/unit/public_suffix_test.rb +115 -0
- data/vendor/gems/publicsuffix-ruby/test/unit/rule_test.rb +307 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/capybara_configuration.rb +98 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/matchers.rb +151 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/rspec_configuration.rb +34 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/rubocop/cop/betterment/html_safe.rb +15 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/rubocop/cop/betterment/raw.rb +15 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/rubocop/cop/betterment/safe_concat.rb +15 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/rubocop.rb +3 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/shared_examples/betterment_application_examples.rb +47 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/shared_examples.rb +1 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/site_prism_configuration.rb +42 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/site_prism_dropdown.rb +17 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/version.rb +3 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers/webmock_configuration.rb +8 -0
- data/vendor/gems/ruby_spec_helpers/lib/ruby_spec_helpers.rb +2 -0
- data/vendor/gems/ruby_spec_helpers/ruby_spec_helpers.gemspec +25 -0
- metadata +110 -1
@@ -0,0 +1,219 @@
|
|
1
|
+
module Her
|
2
|
+
module Model
|
3
|
+
# This module adds ORM-like capabilities to the model
|
4
|
+
module ORM
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
# Return `true` if a resource was not saved yet
|
8
|
+
def new?
|
9
|
+
id.nil?
|
10
|
+
end
|
11
|
+
alias new_record? new?
|
12
|
+
|
13
|
+
# Return `true` if a resource is not `#new?`
|
14
|
+
def persisted?
|
15
|
+
!new?
|
16
|
+
end
|
17
|
+
|
18
|
+
# Return whether the object has been destroyed
|
19
|
+
def destroyed?
|
20
|
+
@destroyed == true
|
21
|
+
end
|
22
|
+
|
23
|
+
# Save a resource and return `false` if the response is not a successful one or
|
24
|
+
# if there are errors in the resource. Otherwise, return the newly updated resource
|
25
|
+
#
|
26
|
+
# @example Save a resource after fetching it
|
27
|
+
# @user = User.find(1)
|
28
|
+
# # Fetched via GET "/users/1"
|
29
|
+
# @user.fullname = "Tobias Fünke"
|
30
|
+
# @user.save
|
31
|
+
# # Called via PUT "/users/1"
|
32
|
+
#
|
33
|
+
# @example Save a new resource by creating it
|
34
|
+
# @user = User.new({ :fullname => "Tobias Fünke" })
|
35
|
+
# @user.save
|
36
|
+
# # Called via POST "/users"
|
37
|
+
def save
|
38
|
+
callback = new? ? :create : :update
|
39
|
+
method = self.class.method_for(callback)
|
40
|
+
|
41
|
+
run_callbacks callback do
|
42
|
+
run_callbacks :save do
|
43
|
+
params = to_params
|
44
|
+
self.class.request(to_params.merge(:_method => method, :_path => request_path, :_headers => request_headers, :_options => request_options)) do |parsed_data, response|
|
45
|
+
assign_attributes(self.class.parse(parsed_data[:data])) if parsed_data[:data].any?
|
46
|
+
@metadata = parsed_data[:metadata]
|
47
|
+
@response_errors = parsed_data[:errors]
|
48
|
+
self.assign_attributes(status_code: response.status)
|
49
|
+
|
50
|
+
return false if !response.success? || @response_errors.any?
|
51
|
+
if self.changed_attributes.present?
|
52
|
+
@previously_changed = self.changed_attributes.clone
|
53
|
+
self.changed_attributes.clear
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
# Similar to save(), except that ResourceInvalid is raised if the save fails
|
63
|
+
def save!
|
64
|
+
if !self.save
|
65
|
+
raise Her::Errors::ResponseError.for(status_code).new("Remote validation of #{self.class.name} failed with a #{status_code}: #{full_error_messages}")
|
66
|
+
end
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
# Destroy a resource
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# @user = User.find(1)
|
74
|
+
# @user.destroy
|
75
|
+
# # Called via DELETE "/users/1"
|
76
|
+
def destroy
|
77
|
+
method = self.class.method_for(:destroy)
|
78
|
+
run_callbacks :destroy do
|
79
|
+
self.class.request(:_method => method, :_path => request_path, :_headers => request_headers, :_options => request_options) do |parsed_data, response|
|
80
|
+
raise Her::Errors::ResponseError.for(response.status).new("Request against #{self.class} returned a #{response.status}") if response.status >= 400
|
81
|
+
assign_attributes(self.class.parse(parsed_data[:data])) if parsed_data[:data].any?
|
82
|
+
@metadata = parsed_data[:metadata]
|
83
|
+
@response_errors = parsed_data[:errors]
|
84
|
+
@destroyed = true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
90
|
+
def full_error_messages
|
91
|
+
self.response_errors.map do |field, messages|
|
92
|
+
"#{field} #{messages.join(', ')}"
|
93
|
+
end.join('. ')
|
94
|
+
end
|
95
|
+
|
96
|
+
module ClassMethods
|
97
|
+
# Create a new chainable scope
|
98
|
+
#
|
99
|
+
# @example
|
100
|
+
# class User
|
101
|
+
# include Her::Model
|
102
|
+
#
|
103
|
+
# scope :admins, lambda { where(:admin => 1) }
|
104
|
+
# scope :page, lambda { |page| where(:page => page) }
|
105
|
+
# enc
|
106
|
+
#
|
107
|
+
# User.admins # Called via GET "/users?admin=1"
|
108
|
+
# User.page(2).all # Called via GET "/users?page=2"
|
109
|
+
def scope(name, code)
|
110
|
+
# Add the scope method to the class
|
111
|
+
(class << self; self end).send(:define_method, name) do |*args|
|
112
|
+
instance_exec(*args, &code)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Add the scope method to the Relation class
|
116
|
+
Relation.instance_eval do
|
117
|
+
define_method(name) { |*args| instance_exec(*args, &code) }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# @private
|
122
|
+
def scoped
|
123
|
+
@_her_default_scope || blank_relation
|
124
|
+
end
|
125
|
+
|
126
|
+
# Define the default scope for the model
|
127
|
+
#
|
128
|
+
# @example
|
129
|
+
# class User
|
130
|
+
# include Her::Model
|
131
|
+
#
|
132
|
+
# default_scope lambda { where(:admin => 1) }
|
133
|
+
# enc
|
134
|
+
#
|
135
|
+
# User.all # Called via GET "/users?admin=1"
|
136
|
+
# User.new.admin # => 1
|
137
|
+
def default_scope(block=nil)
|
138
|
+
@_her_default_scope ||= (!respond_to?(:default_scope) && superclass.respond_to?(:default_scope)) ? superclass.default_scope : scoped
|
139
|
+
@_her_default_scope = @_her_default_scope.instance_exec(&block) unless block.nil?
|
140
|
+
@_her_default_scope
|
141
|
+
end
|
142
|
+
|
143
|
+
# Delegate the following methods to `scoped`
|
144
|
+
[:all, :where, :create, :build, :find, :find_by, :first, :first_or_create, :first_or_initialize].each do |method|
|
145
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
146
|
+
def #{method}(*params)
|
147
|
+
scoped.send(#{method.to_sym.inspect}, *params)
|
148
|
+
end
|
149
|
+
RUBY
|
150
|
+
end
|
151
|
+
|
152
|
+
delegate :with_request_headers, :request_headers, :with_request_options, :request_options, to: :scoped
|
153
|
+
|
154
|
+
# Save an existing resource and return it
|
155
|
+
#
|
156
|
+
# @example
|
157
|
+
# @user = User.save_existing(1, { :fullname => "Tobias Fünke" })
|
158
|
+
# # Called via PUT "/users/1"
|
159
|
+
def save_existing(id, params, headers = {}, options = {})
|
160
|
+
resource = new(params.merge(primary_key => id))
|
161
|
+
resource.request_headers = headers
|
162
|
+
resource.request_options = options
|
163
|
+
resource.save
|
164
|
+
resource
|
165
|
+
end
|
166
|
+
|
167
|
+
# Destroy an existing resource
|
168
|
+
#
|
169
|
+
# @example
|
170
|
+
# User.destroy_existing(1)
|
171
|
+
# # Called via DELETE "/users/1"
|
172
|
+
def destroy_existing(id, params = {}, headers = {}, options = {})
|
173
|
+
request(params.merge(:_method => method_for(:destroy), :_headers => headers, :_options => options, :_path => build_request_path(params.merge(primary_key => id)))) do |parsed_data, response|
|
174
|
+
raise Her::Errors::ResponseError.for(response.status).new("Request against #{name} returned a #{response.status}") if response.status >= 400
|
175
|
+
new(parse(parsed_data[:data]).merge(:_destroyed => true))
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Return or change the HTTP method used to create or update records
|
180
|
+
#
|
181
|
+
# @param [Symbol, String] action The behavior in question (`:create` or `:update`)
|
182
|
+
# @param [Symbol, String] method The HTTP method to use (`'PUT'`, `:post`, etc.)
|
183
|
+
def method_for(action = nil, method = nil)
|
184
|
+
@method_for ||= (superclass.respond_to?(:method_for) ? superclass.method_for : {})
|
185
|
+
return @method_for if action.nil?
|
186
|
+
|
187
|
+
action = action.to_s.downcase.to_sym
|
188
|
+
|
189
|
+
return @method_for[action] if method.nil?
|
190
|
+
@method_for[action] = method.to_s.downcase.to_sym
|
191
|
+
end
|
192
|
+
|
193
|
+
# Build a new resource with the given attributes.
|
194
|
+
# If the request_new_object_on_build flag is set, the new object is requested via API.
|
195
|
+
def build(attributes = {})
|
196
|
+
params = attributes
|
197
|
+
return self.new(params) unless self.request_new_object_on_build?
|
198
|
+
|
199
|
+
path = self.build_request_path(params.merge(self.primary_key => 'new'))
|
200
|
+
method = self.method_for(:new)
|
201
|
+
|
202
|
+
resource = nil
|
203
|
+
self.request(params.merge(:_method => method, :_path => path, :_headers => request_headers)) do |parsed_data, response|
|
204
|
+
if response.success?
|
205
|
+
resource = self.new_from_parsed_data(parsed_data)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
resource
|
209
|
+
end
|
210
|
+
|
211
|
+
private
|
212
|
+
# @private
|
213
|
+
def blank_relation
|
214
|
+
@blank_relation ||= Relation.new(self)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
@@ -0,0 +1,215 @@
|
|
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.to_params(self.attributes, self.changes)
|
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
|
+
# @private
|
21
|
+
def parse(data)
|
22
|
+
if parse_root_in_json? && root_element_included?(data)
|
23
|
+
if json_api_format?
|
24
|
+
data.fetch(parsed_root_element).first
|
25
|
+
else
|
26
|
+
data.fetch(parsed_root_element) { data }
|
27
|
+
end
|
28
|
+
else
|
29
|
+
data
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# @private
|
34
|
+
def to_params(attributes, changes={})
|
35
|
+
filtered_attributes = attributes.dup.symbolize_keys
|
36
|
+
filtered_attributes.merge!(embeded_params(attributes))
|
37
|
+
if her_api.options[:send_only_modified_attributes]
|
38
|
+
filtered_attributes = changes.symbolize_keys.keys.inject({}) do |hash, attribute|
|
39
|
+
hash[attribute] = filtered_attributes[attribute]
|
40
|
+
hash
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
if include_root_in_json?
|
45
|
+
if json_api_format?
|
46
|
+
{ included_root_element => [filtered_attributes] }
|
47
|
+
else
|
48
|
+
{ included_root_element => filtered_attributes }
|
49
|
+
end
|
50
|
+
else
|
51
|
+
filtered_attributes
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
# @private
|
57
|
+
# TODO: Handle has_one
|
58
|
+
def embeded_params(attributes)
|
59
|
+
associations[:has_many].select { |a| attributes.include?(a[:data_key])}.compact.inject({}) do |hash, association|
|
60
|
+
params = attributes[association[:data_key]].map(&:to_params)
|
61
|
+
if association[:class_name].constantize.include_root_in_json?
|
62
|
+
root = association[:class_name].constantize.root_element
|
63
|
+
hash[association[:data_key]] = params.map { |n| n[root] }
|
64
|
+
else
|
65
|
+
hash[association[:data_key]] = params
|
66
|
+
end
|
67
|
+
hash
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return or change the value of `include_root_in_json`
|
72
|
+
#
|
73
|
+
# @example
|
74
|
+
# class User
|
75
|
+
# include Her::Model
|
76
|
+
# include_root_in_json true
|
77
|
+
# end
|
78
|
+
def include_root_in_json(value, options = {})
|
79
|
+
@_her_include_root_in_json = value
|
80
|
+
@_her_include_root_in_json_format = options[:format]
|
81
|
+
end
|
82
|
+
|
83
|
+
# Return or change the value of `parse_root_in_json`
|
84
|
+
#
|
85
|
+
# @example
|
86
|
+
# class User
|
87
|
+
# include Her::Model
|
88
|
+
# parse_root_in_json true
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# class User
|
92
|
+
# include Her::Model
|
93
|
+
# parse_root_in_json true, format: :active_model_serializers
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
# class User
|
97
|
+
# include Her::Model
|
98
|
+
# parse_root_in_json true, format: :json_api
|
99
|
+
# end
|
100
|
+
def parse_root_in_json(value, options = {})
|
101
|
+
@_her_parse_root_in_json = value
|
102
|
+
@_her_parse_root_in_json_format = options[:format]
|
103
|
+
end
|
104
|
+
|
105
|
+
# Return or change the value of `request_new_object_on_build`
|
106
|
+
#
|
107
|
+
# @example
|
108
|
+
# class User
|
109
|
+
# include Her::Model
|
110
|
+
# request_new_object_on_build true
|
111
|
+
# end
|
112
|
+
def request_new_object_on_build(value = nil)
|
113
|
+
@_her_request_new_object_on_build = value
|
114
|
+
end
|
115
|
+
|
116
|
+
# Return or change the value of `root_element`. Always defaults to the base name of the class.
|
117
|
+
#
|
118
|
+
# @example
|
119
|
+
# class User
|
120
|
+
# include Her::Model
|
121
|
+
# parse_root_in_json true
|
122
|
+
# root_element :huh
|
123
|
+
# end
|
124
|
+
#
|
125
|
+
# user = User.find(1) # { :huh => { :id => 1, :name => "Tobias" } }
|
126
|
+
# user.name # => "Tobias"
|
127
|
+
def root_element(value = nil)
|
128
|
+
if value.nil?
|
129
|
+
if json_api_format?
|
130
|
+
@_her_root_element ||= self.name.split("::").last.pluralize.underscore.to_sym
|
131
|
+
else
|
132
|
+
@_her_root_element ||= self.name.split("::").last.underscore.to_sym
|
133
|
+
end
|
134
|
+
else
|
135
|
+
@_her_root_element = value.to_sym
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# @private
|
140
|
+
def root_element_included?(data)
|
141
|
+
data.keys.to_s.include? @_her_root_element.to_s
|
142
|
+
end
|
143
|
+
|
144
|
+
# @private
|
145
|
+
def included_root_element
|
146
|
+
include_root_in_json? == true ? root_element : include_root_in_json?
|
147
|
+
end
|
148
|
+
|
149
|
+
# Extract an array from the request data
|
150
|
+
#
|
151
|
+
# @example
|
152
|
+
# # with parse_root_in_json true, :format => :active_model_serializers
|
153
|
+
# class User
|
154
|
+
# include Her::Model
|
155
|
+
# parse_root_in_json true, :format => :active_model_serializers
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
# users = User.all # { :users => [ { :id => 1, :name => "Tobias" } ] }
|
159
|
+
# users.first.name # => "Tobias"
|
160
|
+
#
|
161
|
+
# # without parse_root_in_json
|
162
|
+
# class User
|
163
|
+
# include Her::Model
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
# users = User.all # [ { :id => 1, :name => "Tobias" } ]
|
167
|
+
# users.first.name # => "Tobias"
|
168
|
+
#
|
169
|
+
# @private
|
170
|
+
def extract_array(request_data)
|
171
|
+
if request_data[:data].is_a?(Hash) && (active_model_serializers_format? || json_api_format?)
|
172
|
+
request_data[:data][pluralized_parsed_root_element]
|
173
|
+
else
|
174
|
+
request_data[:data]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# @private
|
179
|
+
def pluralized_parsed_root_element
|
180
|
+
parsed_root_element.to_s.pluralize.to_sym
|
181
|
+
end
|
182
|
+
|
183
|
+
# @private
|
184
|
+
def parsed_root_element
|
185
|
+
parse_root_in_json? == true ? root_element : parse_root_in_json?
|
186
|
+
end
|
187
|
+
|
188
|
+
# @private
|
189
|
+
def active_model_serializers_format?
|
190
|
+
@_her_parse_root_in_json_format == :active_model_serializers || (superclass.respond_to?(:active_model_serializers_format?) && superclass.active_model_serializers_format?)
|
191
|
+
end
|
192
|
+
|
193
|
+
# @private
|
194
|
+
def json_api_format?
|
195
|
+
@_her_parse_root_in_json_format == :json_api || (superclass.respond_to?(:json_api_format?) && superclass.json_api_format?)
|
196
|
+
end
|
197
|
+
|
198
|
+
# @private
|
199
|
+
def request_new_object_on_build?
|
200
|
+
@_her_request_new_object_on_build || (superclass.respond_to?(:request_new_object_on_build?) && superclass.request_new_object_on_build?)
|
201
|
+
end
|
202
|
+
|
203
|
+
# @private
|
204
|
+
def include_root_in_json?
|
205
|
+
@_her_include_root_in_json || (superclass.respond_to?(:include_root_in_json?) && superclass.include_root_in_json?)
|
206
|
+
end
|
207
|
+
|
208
|
+
# @private
|
209
|
+
def parse_root_in_json?
|
210
|
+
@_her_parse_root_in_json || (superclass.respond_to?(:parse_root_in_json?) && superclass.parse_root_in_json?)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Her
|
2
|
+
module Model
|
3
|
+
module Paths
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
# Return a path based on the collection path and a resource data
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# class User
|
9
|
+
# include Her::Model
|
10
|
+
# collection_path "/utilisateurs"
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# User.find(1) # Fetched via GET /utilisateurs/1
|
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))
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
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] value
|
32
|
+
def primary_key(value = nil)
|
33
|
+
@_her_primary_key ||= begin
|
34
|
+
superclass.primary_key if superclass.respond_to?(:primary_key)
|
35
|
+
end
|
36
|
+
|
37
|
+
return @_her_primary_key unless value
|
38
|
+
@_her_primary_key = value.to_sym
|
39
|
+
end
|
40
|
+
|
41
|
+
# Defines a custom collection path for the resource
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# class User
|
45
|
+
# include Her::Model
|
46
|
+
# collection_path "/users"
|
47
|
+
# end
|
48
|
+
def collection_path(path = nil)
|
49
|
+
if path.nil?
|
50
|
+
@_her_collection_path ||= root_element.to_s.pluralize
|
51
|
+
else
|
52
|
+
@_her_collection_path = path
|
53
|
+
@_her_resource_path = "#{path}/:id"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Defines a custom resource path for the resource
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
# class User
|
61
|
+
# include Her::Model
|
62
|
+
# resource_path "/users/:id"
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# Note that, if used in combination with resource_path, you may specify
|
66
|
+
# either the real primary key or the string ':id'. For example:
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# class User
|
70
|
+
# include Her::Model
|
71
|
+
# primary_key 'user_id'
|
72
|
+
#
|
73
|
+
# # This works because we'll have a user_id attribute
|
74
|
+
# resource_path '/users/:user_id'
|
75
|
+
#
|
76
|
+
# # This works because we replace :id with :user_id
|
77
|
+
# resource_path '/users/:id'
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
def resource_path(path = nil)
|
81
|
+
if path.nil?
|
82
|
+
@_her_resource_path ||= "#{root_element.to_s.pluralize}/:id"
|
83
|
+
else
|
84
|
+
@_her_resource_path = path
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Return a custom path based on the collection path and variable parameters
|
89
|
+
#
|
90
|
+
# @private
|
91
|
+
def build_request_path(path=nil, parameters={})
|
92
|
+
parameters = parameters.try(:with_indifferent_access)
|
93
|
+
|
94
|
+
unless path.is_a?(String)
|
95
|
+
parameters = path.try(:with_indifferent_access) || parameters
|
96
|
+
path =
|
97
|
+
if parameters.include?(primary_key) && parameters[primary_key] && !parameters[primary_key].kind_of?(Array)
|
98
|
+
resource_path.dup
|
99
|
+
else
|
100
|
+
collection_path.dup
|
101
|
+
end
|
102
|
+
|
103
|
+
# Replace :id with our actual primary key
|
104
|
+
path.gsub!(/(\A|\/):id(\Z|\/)/, "\\1:#{primary_key}\\2")
|
105
|
+
end
|
106
|
+
|
107
|
+
path.gsub(/:([\w_]+)/) do
|
108
|
+
# Look for :key or :_key, otherwise raise an exception
|
109
|
+
key = $1.to_sym
|
110
|
+
value = parameters.delete(key) || parameters.delete(:"_#{key}")
|
111
|
+
if value
|
112
|
+
Faraday::Utils.escape value
|
113
|
+
else
|
114
|
+
raise(Her::Errors::PathError.new("Missing :_#{$1} parameter to build the request path. Path is `#{path}`. Parameters are `#{parameters.symbolize_keys.inspect}`.", $1))
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# @private
|
120
|
+
def build_request_path_from_string_or_symbol(path, params={})
|
121
|
+
path.is_a?(Symbol) ? "#{build_request_path(params)}/#{path}" : path
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|