caprese 0.3.19.3 → 0.3.20

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 52dc5d95f51d80297a0e75ced5e685de0596c360
4
- data.tar.gz: dd5682687744ecf3c6effa11ca8e3474c53d0f8e
3
+ metadata.gz: f20459249bd9aa768296fff0603eacaec3d53c99
4
+ data.tar.gz: 667f7a0cd853d8f69099a78ecfaa76c48d15f5de
5
5
  SHA512:
6
- metadata.gz: f5ab75ad8385ba8bb431d2de68e13cb7c324975bf5a7c4f9f32bc88d52ce831f4ef15be010d573217995ff9cf9be876a7381e2ffbc40a9ee6a60ccbbe7a798ae
7
- data.tar.gz: e4dc0068ec675cd58827d1f8222fc75a624fc38922befbf979859aea1bae472868a797577712d347438e8f525d1ec33bf868068ac866746989a42e3da803ed7e
6
+ metadata.gz: 17f2e85ce1abeddd71ee15ce76c68e425b7f6cc8a4e2f71732cdebcd37df424dd8927716a6927cdb05ed861bd09cc3b1fdddb0ad8f8f39ba18b7cf1b905e6a17
7
+ data.tar.gz: f936557de63859192d37419ba50df905949835df4359e0ccfde5ea058b7093f4a7b4f538a5e76496accc17e8dfc55ff1f169a56950685fe47bddb7254cd76b79
data/CHANGELOG.md CHANGED
@@ -111,3 +111,9 @@
111
111
  ## 0.3.19.3
112
112
 
113
113
  * Fix use of `ActiveRecord::Validations::AssociatedValidator` in `Caprese::AssociatedValidator`
114
+
115
+ ## 0.3.20
116
+
117
+ * Add `Caprese::Controller#resource_type_aliases` method that returns object mapping type aliases to actual types for the application
118
+ * Add `Caprese::Record.caprese_field_aliases` method that returns object mapping field aliases to actual fields for the record
119
+ * Add `Caprese::Record.caprese_type` method that returns singular symbol indicating the type to use when serializing the record. (`Caprese::Serializer.json_api_key` now uses this.)
@@ -425,7 +425,8 @@ module Caprese
425
425
  allow_wildcard: true
426
426
  )
427
427
  serializer.associations(include_directive).each_with_object({}) do |association, hash|
428
- hash[association.key] = Relationship.new(
428
+ aliased_key = serializer.object.class.caprese_alias_field(association.key)
429
+ hash[aliased_key] = Relationship.new(
429
430
  serializer,
430
431
  instance_options,
431
432
  association,
@@ -0,0 +1,65 @@
1
+ require 'active_support/concern'
2
+ require 'caprese/errors'
3
+
4
+ module Caprese
5
+ module Aliasing
6
+ extend ActiveSupport::Concern
7
+
8
+ # Specifies specific resource models that have types that are aliased.
9
+ # @note The `caprese_type` class variable of the model should also be set to the new type
10
+ # @example
11
+ # {
12
+ # questions: attributes
13
+ # }
14
+ def resource_type_aliases
15
+ {}
16
+ end
17
+
18
+ # Checks resource_type_aliases for a type alias, or returns the type already stated
19
+ #
20
+ # @param [Symbol] type the type to search for an alias for
21
+ # @return [Symbol] the actual type for the type alias
22
+ def actual_type(type)
23
+ resource_type_aliases[type] || type
24
+ end
25
+
26
+ # Gets the actual field name for the controller_record_class for any given field requested
27
+ #
28
+ # @param [Symbol,String] field the field that was requested
29
+ # @param [Class] klass the klass to get field aliases for
30
+ # @return [Symbol] the actual field name for the field requested
31
+ def actual_field(field, klass = controller_record_class)
32
+ klass.caprese_unalias_field(field.to_sym)
33
+ end
34
+
35
+ # Takes in a set of possibly aliased includes and converts them to their actual names
36
+ #
37
+ # @param [String] the CSV string of possibly aliased includes
38
+ # @return [Array<String>] the actual includes
39
+ def actual_includes(includes)
40
+ includes.split(',').map do |i|
41
+ if(i = i.split('.')).size > 1
42
+ klass = nil
43
+ i.map do |i2|
44
+ actual = actual_field(i2, klass)
45
+ klass = klass.reflections[actual].klass
46
+ actual
47
+ end.join('.')
48
+ else
49
+ actual_field(i)
50
+ end
51
+ end
52
+ end
53
+
54
+ # Takes in a set of possibly aliased fields with types and converts them to their actual
55
+ # types and fields
56
+ #
57
+ # @param [Hash<Array>] the hash of possibly aliased resource types with their possibly aliased field specifier arrays
58
+ # @return [Hash<Array>] the actual resource type and fields
59
+ def actual_fields(fields)
60
+ Hash[*fields.each do |type, fields|
61
+ [actual_type(type), fields.map { |f| actual_field(f, record_class(type)) }]
62
+ end]
63
+ end
64
+ end
65
+ end
@@ -220,12 +220,20 @@ module Caprese
220
220
  # @param [Array] permitted_params the permitted params for the action
221
221
  # @param [Parameters] data the data sent to the server to construct and assign to the record
222
222
  def assign_record_attributes(record, permitted_params, data)
223
- attributes = data[:attributes].try(:permit, *permitted_params) || {}
223
+ attributes = data[:attributes].try(:permit, *permitted_params).try(:inject, {}) do |out, (attr, val)|
224
+ out[actual_field(attr, record.class)] = val
225
+ out
226
+ end || {}
224
227
 
225
228
  data[:relationships]
226
229
  .try(:slice, *flattened_keys_for(permitted_params))
227
230
  .try(:each) do |relationship_name, relationship_data|
228
- attributes[relationship_name] = records_for_relationship(
231
+ actual_relationship_name = actual_field(relationship_name, record.class)
232
+
233
+ # TODO: Add checkme for relationship_name to ensure that format is correct (not Array when actually Record, vice versa)
234
+ # No relationship exists as well
235
+
236
+ attributes[actual_relationship_name] = records_for_relationship(
229
237
  record,
230
238
  nested_params_for(relationship_name, permitted_params),
231
239
  relationship_name,
@@ -134,9 +134,9 @@ module Caprese
134
134
  query_params[:sort].each do |sort_field|
135
135
  ordering = ordering.merge(
136
136
  if sort_field[0] == '-' # EX: -created_at, sort by created_at descending
137
- { sort_field[1..-1] => :desc }
137
+ { actual_field(sort_field[1..-1]) => :desc }
138
138
  else
139
- { sort_field => :asc }
139
+ { actual_field(sort_field) => :asc }
140
140
  end
141
141
  )
142
142
  end
@@ -172,9 +172,9 @@ module Caprese
172
172
  scope = record_scope(unversion(params[:controller]).to_sym)
173
173
 
174
174
  if scope.any? && query_params[:filter].try(:any?)
175
- if (valid_filters = query_params[:filter].select { |k, _| scope.column_names.include? k }).present?
175
+ if (valid_filters = query_params[:filter].select { |k, _| scope.column_names.include? actual_field(k).to_s }).present?
176
176
  valid_filters.each do |k, v|
177
- scope = scope.where(k => v)
177
+ scope = scope.where(actual_field(k) => v)
178
178
  end
179
179
  end
180
180
  end
@@ -207,24 +207,26 @@ module Caprese
207
207
  )
208
208
  end
209
209
 
210
+ relationship_name = queried_association.reflection.name
211
+
210
212
  successful =
211
213
  case queried_association.reflection.macro
212
214
  when :has_many
213
215
  if request.patch?
214
- queried_record.send("#{params[:relationship]}=", relationship_resources)
216
+ queried_record.send("#{relationship_name}=", relationship_resources)
215
217
  elsif request.post?
216
- queried_record.send(params[:relationship]).push relationship_resources
218
+ queried_record.send(relationship_name).push relationship_resources
217
219
  elsif request.delete?
218
- queried_record.send(params[:relationship]).delete relationship_resources
220
+ queried_record.send(relationship_name).delete relationship_resources
219
221
  end
220
222
  when :has_one
221
223
  if request.patch?
222
- queried_record.send("#{params[:relationship]}=", relationship_resources[0])
224
+ queried_record.send("#{relationship_name}=", relationship_resources[0])
223
225
  objects[0].save
224
226
  end
225
227
  when :belongs_to
226
228
  if request.patch?
227
- queried_record.send("#{params[:relationship]}=", relationship_resources[0])
229
+ queried_record.send("#{relationship_name}=", relationship_resources[0])
228
230
  queried_record.save
229
231
  end
230
232
  end
@@ -247,7 +249,7 @@ module Caprese
247
249
  def queried_association
248
250
  unless @queried_association
249
251
  begin
250
- @queried_association = queried_record.association(params[:relationship])
252
+ @queried_association = queried_record.association(actual_field(params[:relationship]))
251
253
  rescue ActiveRecord::AssociationNotFoundError => e
252
254
  fail AssociationNotFoundError.new(params[:relationship])
253
255
  end
@@ -16,7 +16,15 @@ module Caprese
16
16
  # @param [Symbol] type the record type to get the class for
17
17
  # @return [Class] the class for a given record type
18
18
  def record_class(type)
19
- type.to_s.classify.constantize
19
+ begin
20
+ type.to_s.classify.constantize
21
+ rescue NameError => e
22
+ if resource_type_aliases[type.to_sym]
23
+ record_class(resource_type_aliases[type.to_sym].to_sym)
24
+ else
25
+ raise e
26
+ end
27
+ end
20
28
  end
21
29
 
22
30
  # Gets the record class for the current controller
@@ -1,6 +1,7 @@
1
1
  require 'action_controller'
2
2
  require 'active_support/configurable'
3
3
  require 'caprese/concerns/versioning'
4
+ require 'caprese/controller/concerns/aliasing'
4
5
  require 'caprese/controller/concerns/callbacks'
5
6
  require 'caprese/controller/concerns/errors'
6
7
  require 'caprese/controller/concerns/persistence'
@@ -13,7 +14,10 @@ module Caprese
13
14
  # TODO: Convert to ActionController::API with Rails 5
14
15
  class Controller < ActionController::Base
15
16
  include ActiveSupport::Configurable
17
+ include Aliasing
16
18
  include Callbacks
19
+ # FIXME: Be careful about including `Errors` in certain order, because it has `rescue_from Exception` and this affects
20
+ # control flow with other rescue handlers if included after their modules
17
21
  include Errors
18
22
  include Persistence
19
23
  include Query
@@ -0,0 +1,59 @@
1
+ require 'active_support/concern'
2
+
3
+ module Caprese
4
+ module Record
5
+ module Aliasing
6
+ extend ActiveSupport::Concern
7
+
8
+ # Provides an intermediary helper method on records that defines non-column attributes for records
9
+ # @note This exists so there is a method by which to state that a non-column attribute should
10
+ # have an error source pointer like `/data/attributes/[name]` instead of `/data/relationships/[name]`
11
+ def caprese_is_attribute?(attribute_name)
12
+ false
13
+ end
14
+
15
+ # Checks that any field provided is either an attribute on the record, or an aliased field, or none
16
+ #
17
+ # @param [String,Symbol] field the field to check for on this record
18
+ # @return [Boolean] whether or not the field is on the record
19
+ def caprese_is_field?(field)
20
+ respond_to?(field = field.to_sym) || caprese_is_attribute?(field) || self.class.caprese_field_aliases[field]
21
+ end
22
+
23
+ module ClassMethods
24
+ # Given an actual field, convert to its appropriate field alias for the class
25
+ # @note The reason this is useful is because ActiveRecord validations must validate the actual field name of a
26
+ # model, but when we add errors they should always have aliased fields
27
+ #
28
+ # @param [String,Symbol] field the actual field name to alias
29
+ # @return [Symbol] the aliased field name, or the original name symbolized
30
+ def caprese_alias_field(field)
31
+ caprese_field_aliases.invert[field = field.to_sym] || field
32
+ end
33
+
34
+ # Given an aliased field, convert to its actual field for the class
35
+ #
36
+ # @param [String,Symbol] field the actual field name to alias
37
+ # @return [Symbol] the aliased field name, or the original name symbolized
38
+ def caprese_unalias_field(field)
39
+ caprese_field_aliases[field = field.to_sym] || field
40
+ end
41
+
42
+ # Provides the ability to display an aliased field name to the consumer of the API, and then map that name
43
+ # to its real name on the server
44
+ # @example
45
+ # {
46
+ # alias: :actual
47
+ # }
48
+ def caprese_field_aliases
49
+ {}
50
+ end
51
+
52
+ # The type that is serialized and responded with for this class
53
+ def caprese_type
54
+ self.name.underscore
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -24,7 +24,7 @@ module Caprese
24
24
 
25
25
  e = Error.new(
26
26
  model: @base.class.name.underscore.downcase,
27
- field: attribute == :base ? nil : attribute,
27
+ field: attribute == :base ? nil : @base.class.caprese_alias_field(attribute),
28
28
  code: code,
29
29
  t: options[:t]
30
30
  )
@@ -3,13 +3,13 @@ require 'active_support/concern'
3
3
  require 'active_support/dependencies'
4
4
  require 'caprese/errors'
5
5
  require 'caprese/record/associated_validator'
6
- require 'caprese/record/attribute_aliasing'
6
+ require 'caprese/record/aliasing'
7
7
  require 'caprese/record/errors'
8
8
 
9
9
  module Caprese
10
10
  module Record
11
11
  extend ActiveSupport::Concern
12
- include AttributeAliasing
12
+ include Aliasing
13
13
 
14
14
  mattr_accessor :caprese_style_errors
15
15
  @@caprese_style_errors = true
@@ -0,0 +1,17 @@
1
+ require 'active_support/concern'
2
+
3
+ module Caprese
4
+ class Serializer < ActiveModel::Serializer
5
+ module Aliasing
6
+ extend ActiveSupport::Concern
7
+
8
+ # Override so we can get the values for serialization of aliased attributes just like unaliased
9
+ #
10
+ # @param [String,Symbol] attribute the attribute (aliased or not) to read for serialization
11
+ # @return [Value] the value of the attribute
12
+ def read_attribute_for_serialization(attribute)
13
+ super(self.object.class.caprese_unalias_field(attribute))
14
+ end
15
+ end
16
+ end
17
+ end
@@ -80,6 +80,8 @@ module Caprese
80
80
  def build_association_block(reflection_name)
81
81
  primary_key = Caprese.config.resource_primary_key
82
82
 
83
+ reflection_name = reflection_name.to_sym
84
+
83
85
  Proc.new do |serializer|
84
86
  link :self do
85
87
  url = "relationship_definition_#{serializer.version_name("#{object.class.name.underscore}_url")}"
@@ -1,5 +1,6 @@
1
1
  require 'active_model_serializers'
2
2
  require 'caprese/concerns/versioning'
3
+ require 'caprese/serializer/concerns/aliasing'
3
4
  require 'caprese/serializer/concerns/links'
4
5
  require 'caprese/serializer/concerns/lookup'
5
6
  require 'caprese/serializer/concerns/relationships'
@@ -8,12 +9,13 @@ module Caprese
8
9
  class Serializer < ActiveModel::Serializer
9
10
  extend Versioning
10
11
  include Versioning
12
+ include Aliasing
11
13
  include Links
12
14
  include Lookup
13
15
  include Relationships
14
16
 
15
17
  def json_key
16
- unversion(self.class.name).gsub('Serializer', '').underscore
18
+ object.class.caprese_type
17
19
  end
18
20
  end
19
21
  end
@@ -1,3 +1,3 @@
1
1
  module Caprese
2
- VERSION = '0.3.19.3'
2
+ VERSION = '0.3.20'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caprese
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.19.3
4
+ version: 0.3.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Landgrebe
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2017-04-05 00:00:00.000000000 Z
13
+ date: 2017-04-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: active_model_serializers
@@ -224,6 +224,7 @@ files:
224
224
  - lib/caprese/adapter/json_api/resource_identifier.rb
225
225
  - lib/caprese/concerns/versioning.rb
226
226
  - lib/caprese/controller.rb
227
+ - lib/caprese/controller/concerns/aliasing.rb
227
228
  - lib/caprese/controller/concerns/callbacks.rb
228
229
  - lib/caprese/controller/concerns/errors.rb
229
230
  - lib/caprese/controller/concerns/persistence.rb
@@ -234,11 +235,12 @@ files:
234
235
  - lib/caprese/error.rb
235
236
  - lib/caprese/errors.rb
236
237
  - lib/caprese/record.rb
238
+ - lib/caprese/record/aliasing.rb
237
239
  - lib/caprese/record/associated_validator.rb
238
- - lib/caprese/record/attribute_aliasing.rb
239
240
  - lib/caprese/record/errors.rb
240
241
  - lib/caprese/routing/caprese_resources.rb
241
242
  - lib/caprese/serializer.rb
243
+ - lib/caprese/serializer/concerns/aliasing.rb
242
244
  - lib/caprese/serializer/concerns/links.rb
243
245
  - lib/caprese/serializer/concerns/lookup.rb
244
246
  - lib/caprese/serializer/concerns/relationships.rb
@@ -1,12 +0,0 @@
1
- module Caprese
2
- module Record
3
- module AttributeAliasing
4
- # Provides an intermediary helper method on records that defines non-column attributes for records
5
- # @note This exists so there is a method by which to state that a non-column attribute should
6
- # have an error source pointer like `/data/attributes/[name]` instead of `/data/relationships/[name]`
7
- def caprese_is_attribute?(attribute_name)
8
- false
9
- end
10
- end
11
- end
12
- end