Module: Caprese::Relationships
- Extended by:
- ActiveSupport::Concern
- Included in:
- Controller
- Defined in:
- lib/caprese/controller/concerns/relationships.rb
Instance Method Summary collapse
-
#get_relationship_data ⇒ Object
Retrieves the data for a relationship, not just the definition/resource identifier @note Resource Identifier = { id: ‘…’, type: ‘.…’ } @note Resource = Resource Identifier + { attributes: { … } }.
-
#get_relationship_definition ⇒ Object
Returns relationship data for a resource.
-
#relationship_scope(name, scope) ⇒ Object
Applies further scopes to a collection association.
-
#relationship_serializer(name) ⇒ Serializer, Nil
Allows selection of serializer for any relationship serialized by get_relationship_data.
-
#update_relationship_definition ⇒ Object
Updates a relationship for a resource.
Instance Method Details
#get_relationship_data ⇒ Object
Adds a links link to this endpoint itself, to be JSON API compliant
When returning single resource, adds a related endpoint URL that points to the root resource URL
Retrieves the data for a relationship, not just the definition/resource identifier
@note Resource Identifier = { id: '...', type: '....' }
@note Resource = Resource Identifier + { attributes: { ... } }
GET /api/v1/:controller/:id/:relationship(/:relation_primary_key_value)
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/caprese/controller/concerns/relationships.rb', line 63 def get_relationship_data target = if queried_association.reflection.collection? scope = relationship_scope(params[:relationship].to_sym, queried_association.reader) if params[:relation_primary_key_value].present? get_record!(scope, self.class.config.resource_primary_key, params[:relation_primary_key_value]) else apply_sorting_pagination_to_scope(scope) end else queried_association.reader end links = { self: request.original_url } if target.respond_to?(:to_ary) serializer_type = :each_serializer else serializer_type = :serializer if url_helpers.respond_to?( = version_name("#{params[:relationship].singularize}_url")) links[:related] = url_helpers.send( , target.read_attribute(self.config.resource_primary_key), host: ) end end render( serializer_type => relationship_serializer(params[:relationship].to_sym), json: target, fields: query_params[:fields], include: query_params[:include], links: links ) end |
#get_relationship_definition ⇒ Object
Returns relationship data for a resource
-
Find resource we are updating relationship for
-
Check relationship exists *or respond with error*
-
Add self/related links for relationship
-
Respond with relationship data
GET /api/v1/:controller/:id/relationships/:relationship
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/caprese/controller/concerns/relationships.rb', line 139 def get_relationship_definition links = { self: request.original_url } # Add related link for this relationship if it exists if url_helpers .respond_to?( = "relationship_data_#{version_name(unnamespace(params[:controller]).singularize)}_url") links[:related] = url_helpers.send( , params[:id], params[:relationship], host: ) end target = queried_association.reader if queried_association.reflection.collection? target = relationship_scope(params[:relationship], target) end render( json: target, fields: {}, include: query_params[:include], links: links ) end |
#relationship_scope(name, scope) ⇒ Object
Can be overridden to customize scoping at a per-relationship level
Applies further scopes to a collection association
23 24 25 |
# File 'lib/caprese/controller/concerns/relationships.rb', line 23 def relationship_scope(name, scope) scope end |
#relationship_serializer(name) ⇒ Serializer, Nil
Returns nil by default because Caprese::Controller#render will determine the serializer if nil
Allows selection of serializer for any relationship serialized by get_relationship_data
42 43 44 |
# File 'lib/caprese/controller/concerns/relationships.rb', line 42 def relationship_serializer(name) nil end |
#update_relationship_definition ⇒ Object
Updates a relationship for a resource
-
Find resource we are updating relationship for
-
Check relationship exists *or respond with error*
-
Find each potential relationship resource corresponding to the resource identifiers passed in
-
Modify relationship based on relationship type (one-to-many, one-to-one) and HTTP verb (PATCH, POST, DELETE)
-
Check if update was successful
* If successful, return 204 No Content
* If unsuccessful, return 403 Forbidden
PATCH/POST/DELETE /api/v1/:controller/:id/relationships/:relationship
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/caprese/controller/concerns/relationships.rb', line 230 def update_relationship_definition successful = false if queried_association && flattened_keys_for(permitted_params_for(:update)).include?(params[:relationship].to_sym) relationship_name = queried_association.reflection.name relationship_resources = [] begin relationship_resources = Array.wrap(records_for_relationship( queried_record, [], relationship_name, data_params )) rescue ActionController::ParameterMissing => e # Only PATCH requests are allowed to have no :data (when clearing relationship) raise e unless request.patch? rescue Caprese::RecordNotFoundError => e raise RequestDocumentInvalidError.new(field: :base, code: :not_found, t: e.t.slice(:value)) end # Validate that if we assign queried_record as the inverse of the relationship, the relationship records are # still valid if !request.delete? && (inverse_reflection = queried_record.class.reflect_on_association(relationship_name).inverse_of) relationship_resources.each { |r| r.send("#{inverse_reflection.name}=", queried_record) } end if relationship_resources.all?(&:valid?) successful = case queried_association.reflection.macro when :has_many if request.patch? queried_record.send("#{relationship_name}=", relationship_resources) elsif request.post? queried_record.send(relationship_name).push relationship_resources elsif request.delete? queried_record.send(relationship_name).delete relationship_resources end true when :has_one if request.patch? queried_record.send("#{relationship_name}=", relationship_resources[0]) relationship_resources[0].save if relationship_resources[0].present? end when :belongs_to if request.patch? queried_record.send("#{relationship_name}=", relationship_resources[0]) queried_record.save end end end end if successful head :no_content else fail ActionForbiddenError.new end end |