Class: JSONAPI::Resource

Inherits:
Object
  • Object
show all
Defined in:
lib/json_api/resources/resource.rb

Direct Known Subclasses

ActiveStorageBlobResource

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(record = nil, context = {}) ⇒ Resource

Instance method to initialize resource with model instance This allows the serializer to instantiate resources directly



221
222
223
224
225
# File 'lib/json_api/resources/resource.rb', line 221

def initialize(record = nil, context = {})
  @record = record
  @context = context
  @transformed_params = {}
end

Instance Attribute Details

#recordObject (readonly) Also known as: resource

Accessor for the underlying model instance



229
230
231
# File 'lib/json_api/resources/resource.rb', line 229

def record
  @record
end

Class Method Details

.attributes(*attrs) ⇒ Object



13
14
15
16
17
# File 'lib/json_api/resources/resource.rb', line 13

def attributes(*attrs)
  @attributes ||= []
  @attributes.concat(attrs.map(&:to_sym))
  @attributes.uniq!
end

.belongs_to(name, meta: nil, **options) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/json_api/resources/resource.rb', line 93

def belongs_to(name, meta: nil, **options)
  @relationships ||= []

  unless options.key?(:polymorphic)
    model_klass = reflection_model_class
    if model_klass.respond_to?(:reflect_on_association)
      reflection = model_klass.reflect_on_association(name)
      options[:polymorphic] = reflection&.polymorphic?
    end
  end

  @relationships << { name: name.to_sym, type: :belongs_to, meta:, options: }
end

.creatable_fields(*fields) ⇒ Object



19
20
21
22
23
# File 'lib/json_api/resources/resource.rb', line 19

def creatable_fields(*fields)
  @creatable_fields ||= []
  @creatable_fields.concat(fields.map(&:to_sym))
  @creatable_fields.uniq!
end

.filters(*filter_names) ⇒ Object



31
32
33
34
35
# File 'lib/json_api/resources/resource.rb', line 31

def filters(*filter_names)
  @filters ||= []
  @filters.concat(filter_names.map(&:to_sym))
  @filters.uniq!
end

.has_many(name, meta: nil, **options) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/json_api/resources/resource.rb', line 73

def has_many(name, meta: nil, **options)
  @relationships ||= []

  if options[:append_only] && options[:purge_on_nil] == true
    raise ArgumentError, "Cannot use append_only: true with purge_on_nil: true"
  end

  options[:purge_on_nil] = false if options[:append_only] && !options.key?(:purge_on_nil)

  unless options.key?(:polymorphic)
    model_klass = reflection_model_class
    if model_klass.respond_to?(:reflect_on_association)
      reflection = model_klass.reflect_on_association(name)
      options[:polymorphic] = reflection&.polymorphic?
    end
  end

  @relationships << { name: name.to_sym, type: :has_many, meta:, options: }
end

.has_one(name, meta: nil, **options) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/json_api/resources/resource.rb', line 59

def has_one(name, meta: nil, **options)
  @relationships ||= []

  unless options.key?(:polymorphic)
    model_klass = reflection_model_class
    if model_klass.respond_to?(:reflect_on_association)
      reflection = model_klass.reflect_on_association(name)
      options[:polymorphic] = reflection&.polymorphic?
    end
  end

  @relationships << { name: name.to_sym, type: :has_one, meta:, options: }
end

.meta(hash = nil, &block) ⇒ Object



47
48
49
# File 'lib/json_api/resources/resource.rb', line 47

def meta(hash = nil, &block)
  @meta = hash || block
end

.model_classObject



197
198
199
# File 'lib/json_api/resources/resource.rb', line 197

def model_class
  name.sub(/Resource$/, "").classify.constantize
end

.permitted_attributesObject



107
108
109
110
111
112
113
114
115
116
117
# File 'lib/json_api/resources/resource.rb', line 107

def permitted_attributes
  # For STI subclasses, merge with parent class attributes unless the subclass declares its own
  declared_attributes = instance_variable_defined?(:@attributes)
  attrs = @attributes || []
  if !declared_attributes &&
     superclass != JSONAPI::Resource &&
     superclass.respond_to?(:permitted_attributes)
    attrs = superclass.permitted_attributes + attrs
  end
  attrs.uniq
end

.permitted_creatable_fieldsObject



119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/json_api/resources/resource.rb', line 119

def permitted_creatable_fields
  if instance_variable_defined?(:@creatable_fields)
    fields = @creatable_fields || []
  elsif superclass != JSONAPI::Resource &&
        superclass.respond_to?(:permitted_creatable_fields) &&
        superclass.instance_variable_defined?(:@creatable_fields)
    parent_fields = superclass.permitted_creatable_fields
    fields = parent_fields
  else
    fields = permitted_attributes
  end

  fields.uniq
end

.permitted_filtersObject



149
150
151
152
153
154
155
156
157
158
159
# File 'lib/json_api/resources/resource.rb', line 149

def permitted_filters
  # For STI subclasses, merge with parent class filters unless the subclass declares its own
  declared_filters = instance_variable_defined?(:@filters)
  filter_list = @filters || []
  if !declared_filters &&
     superclass != JSONAPI::Resource &&
     superclass.respond_to?(:permitted_filters)
    filter_list = superclass.permitted_filters + filter_list
  end
  filter_list.uniq
end

.permitted_filters_throughObject



37
38
39
# File 'lib/json_api/resources/resource.rb', line 37

def permitted_filters_through
  relationship_names
end

.permitted_sortable_fieldsObject



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/json_api/resources/resource.rb', line 161

def permitted_sortable_fields
  # Include both attributes (which are sortable) and sort-only fields
  # For STI subclasses, merge with parent class sortable fields when no subclass DSL is declared
  declared_sortable = instance_variable_defined?(:@sortable_fields)
  declared_attributes = instance_variable_defined?(:@attributes)
  sort_fields = @sortable_fields || []
  if !declared_sortable &&
     !declared_attributes &&
     superclass != JSONAPI::Resource &&
     superclass.respond_to?(:permitted_sortable_fields)
    parent_sort_fields = superclass.permitted_sortable_fields
    # Only merge parent's sort-only fields, not attributes (attributes are already included via permitted_attributes)
    parent_attributes = superclass.permitted_attributes
    parent_sort_only = parent_sort_fields - parent_attributes
    sort_fields = parent_sort_only + sort_fields
  end
  # Combine with attributes (all attributes are sortable)
  (permitted_attributes + sort_fields).uniq
end

.permitted_updatable_fieldsObject



134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/json_api/resources/resource.rb', line 134

def permitted_updatable_fields
  if instance_variable_defined?(:@updatable_fields)
    fields = @updatable_fields || []
  elsif superclass != JSONAPI::Resource &&
        superclass.respond_to?(:permitted_updatable_fields) &&
        superclass.instance_variable_defined?(:@updatable_fields)
    parent_fields = superclass.permitted_updatable_fields
    fields = parent_fields
  else
    fields = permitted_attributes
  end

  fields.uniq
end

.reflection_model_classObject



210
211
212
213
214
215
216
# File 'lib/json_api/resources/resource.rb', line 210

def reflection_model_class
  model_class
rescue NameError
  safe_model_class
rescue StandardError
  safe_model_class
end

.relationship_definitionsObject



181
182
183
184
185
186
187
188
189
190
191
# File 'lib/json_api/resources/resource.rb', line 181

def relationship_definitions
  # For STI subclasses, merge with parent class relationships
  declared_relationships = instance_variable_defined?(:@relationships)
  rels = @relationships || []
  if !declared_relationships &&
     superclass != JSONAPI::Resource &&
     superclass.respond_to?(:relationship_definitions)
    rels = superclass.relationship_definitions + rels
  end
  rels.uniq { |r| r[:name] }
end

.relationship_namesObject



193
194
195
# File 'lib/json_api/resources/resource.rb', line 193

def relationship_names
  relationship_definitions.map { |r| r[:name] }
end

.resource_for_model(model_class) ⇒ Object



6
7
8
9
10
11
# File 'lib/json_api/resources/resource.rb', line 6

def resource_for_model(model_class)
  resource_const = "#{model_class.name}Resource"
  resource_const.safe_constantize if resource_const.respond_to?(:safe_constantize) || defined?(ActiveSupport)
rescue NameError
  nil
end

.resource_metaObject



51
52
53
54
55
56
57
# File 'lib/json_api/resources/resource.rb', line 51

def resource_meta
  if instance_variable_defined?(:@meta)
    @meta
  elsif superclass != JSONAPI::Resource && superclass.respond_to?(:resource_meta)
    superclass.resource_meta
  end
end

.safe_model_classObject



201
202
203
204
205
206
207
208
# File 'lib/json_api/resources/resource.rb', line 201

def safe_model_class
  return nil unless respond_to?(:name) && name
  return nil unless defined?(ActiveSupport)

  name.sub(/Resource$/, "").classify.safe_constantize
rescue NoMethodError
  nil
end

.sortable_fields(*field_names) ⇒ Object



41
42
43
44
45
# File 'lib/json_api/resources/resource.rb', line 41

def sortable_fields(*field_names)
  @sortable_fields ||= []
  @sortable_fields.concat(field_names.map(&:to_sym))
  @sortable_fields.uniq!
end

.updatable_fields(*fields) ⇒ Object



25
26
27
28
29
# File 'lib/json_api/resources/resource.rb', line 25

def updatable_fields(*fields)
  @updatable_fields ||= []
  @updatable_fields.concat(fields.map(&:to_sym))
  @updatable_fields.uniq!
end

Instance Method Details

#transformed_paramsObject

Returns transformed params accumulated by resource setters during deserialization Resources can override this method or use the default implementation



234
235
236
# File 'lib/json_api/resources/resource.rb', line 234

def transformed_params
  @transformed_params || {}
end