linked_rails 0.0.4.pre.gfe77aae19 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +674 -21
- data/app/controllers/linked_rails/bulk_controller.rb +16 -81
- data/app/models/linked_rails/actions/item.rb +30 -23
- data/app/models/linked_rails/actions/list.rb +6 -0
- data/app/models/linked_rails/collection/filter_field.rb +3 -16
- data/app/models/linked_rails/collection/filterable.rb +4 -6
- data/app/models/linked_rails/collection/infinite.rb +6 -17
- data/app/models/linked_rails/collection/iri.rb +2 -25
- data/app/models/linked_rails/collection/iri_mapping.rb +1 -1
- data/app/models/linked_rails/collection/paginated.rb +3 -4
- data/app/models/linked_rails/collection/view.rb +10 -38
- data/app/models/linked_rails/collection.rb +25 -27
- data/app/models/linked_rails/enum_value.rb +1 -1
- data/app/models/linked_rails/form/field/association_input.rb +1 -7
- data/app/models/linked_rails/form/field/file_input.rb +0 -1
- data/app/models/linked_rails/form/field.rb +5 -31
- data/app/models/linked_rails/form/field_factory.rb +16 -29
- data/app/models/linked_rails/form/group.rb +4 -2
- data/app/models/linked_rails/form/page.rb +0 -4
- data/app/models/linked_rails/form.rb +6 -4
- data/app/models/linked_rails/manifest.rb +20 -94
- data/app/models/linked_rails/menus/item.rb +13 -10
- data/app/models/linked_rails/menus/list.rb +5 -13
- data/app/models/linked_rails/ontology/base.rb +0 -2
- data/app/models/linked_rails/ontology.rb +0 -1
- data/app/models/linked_rails/property_query.rb +0 -2
- data/app/models/linked_rails/sequence.rb +11 -2
- data/app/models/linked_rails/web_page.rb +4 -0
- data/app/models/linked_rails/web_site.rb +4 -0
- data/app/models/linked_rails/widget.rb +10 -3
- data/app/policies/linked_rails/collection_policy.rb +2 -2
- data/app/serializers/linked_rails/actions/item_serializer.rb +4 -3
- data/app/serializers/linked_rails/collection/filter_field_serializer.rb +2 -3
- data/app/serializers/linked_rails/collection/filter_option_serializer.rb +1 -1
- data/app/serializers/linked_rails/collection/filter_serializer.rb +1 -1
- data/app/serializers/linked_rails/collection/sorting_serializer.rb +1 -1
- data/app/serializers/linked_rails/collection/view_serializer.rb +3 -3
- data/app/serializers/linked_rails/collection_serializer.rb +13 -9
- data/app/serializers/linked_rails/condition_serializer.rb +3 -3
- data/app/serializers/linked_rails/entry_point_serializer.rb +2 -2
- data/app/serializers/linked_rails/enum_value_serializer.rb +0 -1
- data/app/serializers/linked_rails/form/field/association_input_serializer.rb +0 -1
- data/app/serializers/linked_rails/form/field_serializer.rb +1 -3
- data/app/serializers/linked_rails/form/group_serializer.rb +1 -1
- data/app/serializers/linked_rails/form/page_serializer.rb +1 -1
- data/app/serializers/linked_rails/menus/item_serializer.rb +3 -3
- data/app/serializers/linked_rails/menus/list_serializer.rb +1 -1
- data/app/serializers/linked_rails/sequence_serializer.rb +5 -2
- data/app/serializers/linked_rails/shacl/node_shape_serializer.rb +1 -1
- data/app/serializers/linked_rails/shacl/property_shape_serializer.rb +1 -1
- data/app/serializers/linked_rails/shacl/shape_serializer.rb +5 -5
- data/app/serializers/linked_rails/web_page_serializer.rb +3 -3
- data/app/serializers/linked_rails/web_site_serializer.rb +1 -1
- data/app/serializers/linked_rails/widget_serializer.rb +3 -3
- data/lib/generators/linked_rails/install/templates/locales.yml +0 -4
- data/lib/generators/linked_rails/install/templates/rdf_serializers_initializer.rb +1 -1
- data/lib/generators/linked_rails/model/templates/form.rb.tt +1 -1
- data/lib/generators/linked_rails/model/templates/policy.rb.tt +1 -1
- data/lib/generators/linked_rails/model/templates/serializer.rb.tt +1 -5
- data/lib/linked_rails/active_response/controller/collections.rb +1 -1
- data/lib/linked_rails/active_response/controller/crud_defaults.rb +1 -1
- data/lib/linked_rails/active_response/controller/params.rb +6 -6
- data/lib/linked_rails/active_response/controller.rb +22 -1
- data/lib/linked_rails/collection_params_parser.rb +1 -1
- data/lib/linked_rails/controller/actionable.rb +2 -5
- data/lib/linked_rails/controller/default_actions/create.rb +2 -2
- data/lib/linked_rails/controller/error_handling.rb +7 -12
- data/lib/linked_rails/controller.rb +1 -4
- data/lib/linked_rails/helpers/delta_helper.rb +58 -4
- data/lib/linked_rails/helpers/resource_helper.rb +1 -13
- data/lib/linked_rails/iri_mapper.rb +1 -1
- data/lib/linked_rails/middleware/linked_data_params.rb +27 -26
- data/lib/linked_rails/model/actionable.rb +8 -7
- data/lib/linked_rails/model/collections.rb +4 -10
- data/lib/linked_rails/model/dirty.rb +18 -6
- data/lib/linked_rails/model/filtering.rb +2 -2
- data/lib/linked_rails/model/indexable.rb +1 -1
- data/lib/linked_rails/model/iri.rb +2 -14
- data/lib/linked_rails/model/iri_mapping.rb +3 -3
- data/lib/linked_rails/model/menuable.rb +7 -1
- data/lib/linked_rails/model/serialization.rb +6 -2
- data/lib/linked_rails/model/singularable.rb +5 -7
- data/lib/linked_rails/model/tables.rb +1 -1
- data/lib/linked_rails/model.rb +2 -5
- data/lib/linked_rails/params_parser.rb +47 -48
- data/lib/linked_rails/policy.rb +30 -21
- data/lib/linked_rails/renderers.rb +0 -1
- data/lib/linked_rails/routes.rb +0 -1
- data/lib/linked_rails/serializer/singularable.rb +1 -1
- data/lib/linked_rails/serializer.rb +2 -6
- data/lib/linked_rails/translate.rb +0 -12
- data/lib/linked_rails/vocab.rb +0 -1
- data/lib/linked_rails.rb +3 -16
- data/lib/rdf/query_fix.rb +1 -1
- metadata +10 -59
- data/app/controllers/linked_rails/actions/objects_controller.rb +0 -9
- data/app/models/linked_rails/actions/object.rb +0 -38
- data/app/models/linked_rails/form/field/url_input.rb +0 -10
- data/app/policies/linked_rails/actions/object_policy.rb +0 -11
- data/app/policies/linked_rails/form_policy.rb +0 -13
- data/app/policies/linked_rails/ontology_policy.rb +0 -13
- data/app/serializers/linked_rails/actions/object_serializer.rb +0 -9
- data/app/serializers/linked_rails/form/field/file_input_serializer.rb +0 -11
- data/app/serializers/linked_rails/property_query_serializer.rb +0 -7
- data/app/workers/linked_rails/invalidation_stream_worker.rb +0 -16
- data/lib/linked_rails/controller/delta.rb +0 -58
- data/lib/linked_rails/controller/rendering.rb +0 -48
- data/lib/linked_rails/errors/forbidden.rb +0 -37
- data/lib/linked_rails/errors.rb +0 -3
- data/lib/linked_rails/middleware/error_handling.rb +0 -51
- data/lib/linked_rails/model/cacheable.rb +0 -45
- data/lib/linked_rails/railtie.rb +0 -11
- data/lib/linked_rails/storage.rb +0 -32
- data/lib/linked_rails/types/iri_type.rb +0 -37
- data/lib/linked_rails/url.rb +0 -11
- data/lib/rdf/list.rb +0 -9
@@ -7,7 +7,9 @@ module LinkedRails
|
|
7
7
|
include ActiveSupport::Rescuable
|
8
8
|
|
9
9
|
included do
|
10
|
-
rescue_from
|
10
|
+
rescue_from StandardError, with: :handle_and_report_error
|
11
|
+
rescue_from ActiveRecord::RecordNotFound, with: :handle_error
|
12
|
+
rescue_from Pundit::NotAuthorizedError, with: :handle_error
|
11
13
|
end
|
12
14
|
|
13
15
|
private
|
@@ -20,14 +22,7 @@ module LinkedRails
|
|
20
22
|
!%w[GET HEAD].include?(request.method)
|
21
23
|
end
|
22
24
|
|
23
|
-
def handle_and_report_error(error)
|
24
|
-
report_error(error) if error_status(error) == 500
|
25
|
-
handle_error(error)
|
26
|
-
end
|
27
|
-
|
28
25
|
def handle_error(error)
|
29
|
-
raise(error) if response_body
|
30
|
-
|
31
26
|
respond_to do |format|
|
32
27
|
(LinkedRails::Renderers.rdf_content_types + [:json]).each do |type|
|
33
28
|
format.send(type) { error_response_serializer(error, type) }
|
@@ -35,10 +30,11 @@ module LinkedRails
|
|
35
30
|
end
|
36
31
|
end
|
37
32
|
|
38
|
-
def
|
39
|
-
raise
|
33
|
+
def handle_and_report_error(error)
|
34
|
+
raise if Rails.env.development? || Rails.env.test?
|
35
|
+
raise if response_body
|
40
36
|
|
41
|
-
|
37
|
+
handle_error(error)
|
42
38
|
end
|
43
39
|
|
44
40
|
def error_mode(exception)
|
@@ -73,7 +69,6 @@ module LinkedRails
|
|
73
69
|
'Doorkeeper::Errors::InvalidGrantReuse' => 422,
|
74
70
|
'LinkedRails::Auth::Errors::Expired' => 410,
|
75
71
|
'LinkedRails::Auth::Errors::Unauthorized' => 401,
|
76
|
-
'LinkedRails::Errors::Forbidden' => 403,
|
77
72
|
'Pundit::NotAuthorizedError' => 403
|
78
73
|
}
|
79
74
|
end
|
@@ -4,8 +4,6 @@ require_relative 'active_response/controller'
|
|
4
4
|
require_relative 'controller/actionable'
|
5
5
|
require_relative 'controller/authorization'
|
6
6
|
require_relative 'controller/error_handling'
|
7
|
-
require_relative 'controller/delta'
|
8
|
-
require_relative 'controller/rendering'
|
9
7
|
|
10
8
|
module LinkedRails
|
11
9
|
module Controller
|
@@ -22,9 +20,8 @@ module LinkedRails
|
|
22
20
|
include LinkedRails::Controller::Actionable
|
23
21
|
include LinkedRails::Controller::Authorization
|
24
22
|
include LinkedRails::Controller::ErrorHandling
|
25
|
-
include LinkedRails::Controller::Rendering
|
26
|
-
include LinkedRails::Controller::Delta
|
27
23
|
include LinkedRails::Helpers::OntolaActionsHelper
|
24
|
+
include LinkedRails::Helpers::DeltaHelper
|
28
25
|
include LinkedRails::Helpers::ResourceHelper
|
29
26
|
|
30
27
|
before_action :set_manifest_header
|
@@ -3,8 +3,64 @@
|
|
3
3
|
module LinkedRails
|
4
4
|
module Helpers
|
5
5
|
module DeltaHelper
|
6
|
+
def changed_relation_triples(predicate, destructed, resources)
|
7
|
+
related_resource_invalidations = resources.map(&method(:invalidate_resource_delta))
|
8
|
+
|
9
|
+
return related_resource_invalidations unless predicate
|
10
|
+
|
11
|
+
if destructed
|
12
|
+
return related_resource_invalidations + [
|
13
|
+
[current_resource.iri, predicate, Vocab.sp[:Variable], delta_iri(:remove)]
|
14
|
+
]
|
15
|
+
end
|
16
|
+
|
17
|
+
related_resource_invalidations + resources.map do |resource|
|
18
|
+
[current_resource.iri, predicate, resource.iri, delta_iri(:replace)]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def changed_relations_triples # rubocop:disable Metrics/AbcSize
|
23
|
+
current_resource.previously_changed_relations.flat_map do |key, value|
|
24
|
+
if key.to_s.ends_with?('_collection')
|
25
|
+
[invalidate_collection_delta(current_resource.send(key))]
|
26
|
+
else
|
27
|
+
destructed = current_resource.send(:association_has_destructed?, key)
|
28
|
+
many = value.relationship_type == :has_many
|
29
|
+
relation = current_resource.send(key)
|
30
|
+
changed_relation_triples(value.predicate, destructed, many ? relation : [relation])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def change_triple(predicate, value)
|
36
|
+
if value.nil?
|
37
|
+
RDF::Statement.new(current_resource.iri, predicate, Vocab.sp[:Variable], graph_name: delta_iri(:remove))
|
38
|
+
else
|
39
|
+
RDF::Statement.new(current_resource.iri, predicate, value, graph_name: delta_iri(:replace))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def changes_triples # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
44
|
+
serializer_class = RDF::Serializers.serializer_for(current_resource)
|
45
|
+
return [] if serializer_class.blank?
|
46
|
+
|
47
|
+
serializer = serializer_class.new(current_resource)
|
48
|
+
|
49
|
+
current_resource.previous_changes_by_predicate.map do |predicate, (_old_value, _new_value)|
|
50
|
+
serializer_attributes = current_resource.class.predicate_mapping[predicate]
|
51
|
+
next if serializer_attributes.is_a?(FastJsonapi::Relationship)
|
52
|
+
|
53
|
+
attr_name = serializer_attributes.key
|
54
|
+
serialized_value =
|
55
|
+
serializer.class.attributes_to_serialize[attr_name]&.serialize(current_resource, serializer_params, {})
|
56
|
+
(serialized_value.is_a?(Array) ? serialized_value : [serialized_value]).map do |value|
|
57
|
+
change_triple(predicate, value)
|
58
|
+
end
|
59
|
+
end.compact.flatten
|
60
|
+
end
|
61
|
+
|
6
62
|
def delta_iri(delta)
|
7
|
-
%i[remove replace invalidate].include?(delta) ? Vocab.ontola[delta] : Vocab.
|
63
|
+
%i[remove replace invalidate].include?(delta) ? Vocab.ontola[delta] : Vocab.ll[delta]
|
8
64
|
end
|
9
65
|
|
10
66
|
def invalidate_collection_delta(collection)
|
@@ -12,9 +68,7 @@ module LinkedRails
|
|
12
68
|
end
|
13
69
|
|
14
70
|
def invalidate_parent_collections_delta(resource)
|
15
|
-
|
16
|
-
|
17
|
-
resource&.parent_collections(context)&.map(&method(:invalidate_collection_delta)) || []
|
71
|
+
resource&.parent_collections(try(:user_context))&.map(&method(:invalidate_collection_delta)) || []
|
18
72
|
end
|
19
73
|
|
20
74
|
def invalidate_resource_delta(resource)
|
@@ -41,28 +41,16 @@ module LinkedRails
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def requested_resource_parent
|
44
|
-
requested_resource
|
44
|
+
requested_resource&.parent
|
45
45
|
end
|
46
46
|
|
47
47
|
private
|
48
48
|
|
49
|
-
def request_path_to_url(path)
|
50
|
-
return path unless path.present? && URI(path).relative?
|
51
|
-
|
52
|
-
port = [80, 443].include?(request.port) ? nil : request.port
|
53
|
-
URI::Generic.new(request.scheme, nil, request.host, port, nil, path, nil, nil, nil).to_s
|
54
|
-
end
|
55
|
-
|
56
49
|
def build_new_resource
|
57
50
|
controller_class.build_new(user_context: user_context)
|
58
51
|
end
|
59
52
|
|
60
53
|
def new_resource_from_parent
|
61
|
-
if requested_resource.is_a?(LinkedRails.collection_class) ||
|
62
|
-
requested_resource.is_a?(LinkedRails.collection_view_class)
|
63
|
-
return requested_resource.child_resource
|
64
|
-
end
|
65
|
-
|
66
54
|
parent_resource.build_child(
|
67
55
|
controller_class,
|
68
56
|
user_context: user_context
|
@@ -38,7 +38,7 @@ module LinkedRails
|
|
38
38
|
params = Rails.application.routes.recognize_path(iri.to_s, method: method)
|
39
39
|
|
40
40
|
route_params_to_opts(params.merge(query), iri.to_s)
|
41
|
-
rescue ActionController::RoutingError
|
41
|
+
rescue ActionController::RoutingError
|
42
42
|
EMPTY_IRI_OPTS.dup
|
43
43
|
end
|
44
44
|
|
@@ -1,13 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# require 'empathy/emp_json'
|
4
|
-
|
5
3
|
module LinkedRails
|
6
4
|
module Middleware
|
7
5
|
class LinkedDataParams
|
8
|
-
include ::Empathy::EmpJson::Helpers::Slices
|
9
|
-
include ::Empathy::EmpJson::Helpers::Parsing
|
10
|
-
|
11
6
|
def initialize(app)
|
12
7
|
@app = app
|
13
8
|
end
|
@@ -15,7 +10,7 @@ module LinkedRails
|
|
15
10
|
def call(env)
|
16
11
|
req = Rack::Request.new(env)
|
17
12
|
params_from_query(req)
|
18
|
-
|
13
|
+
params_from_graph(req)
|
19
14
|
|
20
15
|
@app.call(env)
|
21
16
|
end
|
@@ -36,32 +31,38 @@ module LinkedRails
|
|
36
31
|
request.update_param(class_key, data) if data.present?
|
37
32
|
end
|
38
33
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
body = request.body.read
|
34
|
+
def graph_from_request(request)
|
35
|
+
request_graph = request.delete_param("<#{Vocab.ll[:graph].value}>")
|
36
|
+
return if request_graph.blank?
|
43
37
|
|
44
|
-
|
38
|
+
RDF::Graph.load(
|
39
|
+
request_graph[:tempfile].path,
|
40
|
+
content_type: request_graph[:type],
|
41
|
+
canonicalize: true,
|
42
|
+
intern: false
|
43
|
+
)
|
45
44
|
end
|
46
45
|
|
47
|
-
# Converts a
|
46
|
+
# Converts a serialized graph from a multipart request body to a nested
|
47
|
+
# attributes hash.
|
48
48
|
#
|
49
|
-
# The
|
49
|
+
# The graph sent to the server should be sent under the `ll:graph` form name.
|
50
|
+
# The entrypoint for the graph is the `ll:targetResource` subject, which is
|
50
51
|
# assumed to be the resource intended to be targeted by the request (i.e. the
|
51
52
|
# resource to be created, updated, or deleted).
|
52
53
|
#
|
53
54
|
# @return [Hash] A hash of attributes, empty if no statements were given.
|
54
|
-
def
|
55
|
-
|
55
|
+
def params_from_graph(request)
|
56
|
+
graph = graph_from_request(request)
|
56
57
|
|
57
|
-
return unless
|
58
|
+
return unless graph
|
58
59
|
|
59
|
-
request.
|
60
|
+
request.update_param(:body_graph, graph)
|
60
61
|
target_class = target_class_from_path(request)
|
61
62
|
return if target_class.blank?
|
62
63
|
|
63
|
-
update_actor_param(request,
|
64
|
-
update_target_params(request,
|
64
|
+
update_actor_param(request, graph)
|
65
|
+
update_target_params(request, graph, target_class)
|
65
66
|
end
|
66
67
|
|
67
68
|
def params_from_query(request)
|
@@ -82,19 +83,19 @@ module LinkedRails
|
|
82
83
|
opts[:class]
|
83
84
|
end
|
84
85
|
|
85
|
-
def update_actor_param(request,
|
86
|
-
actor =
|
87
|
-
|
86
|
+
def update_actor_param(request, graph)
|
87
|
+
actor = graph.query([Vocab.ll[:targetResource], Vocab.schema.creator]).first
|
88
88
|
return if actor.blank?
|
89
89
|
|
90
|
-
request.update_param(:actor_iri,
|
90
|
+
request.update_param(:actor_iri, actor.object)
|
91
|
+
graph.delete(actor)
|
91
92
|
end
|
92
93
|
|
93
|
-
def update_target_params(request,
|
94
|
+
def update_target_params(request, graph, target_class)
|
94
95
|
key = target_class.to_s.demodulize.underscore
|
95
96
|
|
96
|
-
parser = ParamsParser.new(
|
97
|
-
from_body = parser.parse_resource(
|
97
|
+
parser = ParamsParser.new(graph: graph, params: request.params)
|
98
|
+
from_body = parser.parse_resource(Vocab.ll[:targetResource], target_class)
|
98
99
|
|
99
100
|
request.update_param(key, from_body.merge(request.params[key] || {}))
|
100
101
|
end
|
@@ -45,7 +45,9 @@ module LinkedRails
|
|
45
45
|
|
46
46
|
module ClassMethods
|
47
47
|
def action_list
|
48
|
-
@action_list
|
48
|
+
return @action_list if @action_list.try(:actionable_class) == self
|
49
|
+
|
50
|
+
@action_list = defined_action_list || define_action_list
|
49
51
|
end
|
50
52
|
|
51
53
|
private
|
@@ -54,13 +56,12 @@ module LinkedRails
|
|
54
56
|
superclass.try(:action_list) || LinkedRails.action_list_parent_class
|
55
57
|
end
|
56
58
|
|
59
|
+
def defined_action_list
|
60
|
+
'ActionList'.safe_constantize
|
61
|
+
end
|
62
|
+
|
57
63
|
def define_action_list
|
58
|
-
|
59
|
-
actionable_class = self
|
60
|
-
klass.define_singleton_method(:actionable_class) do
|
61
|
-
actionable_class
|
62
|
-
end
|
63
|
-
klass
|
64
|
+
const_set('ActionList', Class.new(action_superclass))
|
64
65
|
end
|
65
66
|
end
|
66
67
|
end
|
@@ -37,8 +37,6 @@ module LinkedRails
|
|
37
37
|
association_class: nil,
|
38
38
|
# association_scope [Sym] The scope applied to the collection.
|
39
39
|
association_scope: nil,
|
40
|
-
# call_to_action [String] The label shown as call to action.
|
41
|
-
call_to_action: nil,
|
42
40
|
# collection_class [Class] The base class of the collection.
|
43
41
|
# If you want to use a class other than LinkedRails.collection_class.
|
44
42
|
collection_class: nil,
|
@@ -46,8 +44,6 @@ module LinkedRails
|
|
46
44
|
default_filters: {},
|
47
45
|
# collection_class [Array<Hash>] The default sortings applied to the collection.
|
48
46
|
default_sortings: [{key: Vocab.schema.dateCreated, direction: :desc}],
|
49
|
-
# include_members [Boolean] Whether to include the members of this collection.
|
50
|
-
include_members: false,
|
51
47
|
# iri_template_keys [Array<Sym>] Custom query keys for the iri template
|
52
48
|
iri_template_keys: [],
|
53
49
|
# joins [Array<Sym>, Sym] The associations to join
|
@@ -62,9 +58,7 @@ module LinkedRails
|
|
62
58
|
# Set to false to skip scoping
|
63
59
|
policy_scope: -> { policy ? policy::Scope : Pundit::PolicyFinder.new(filtered_association).scope! },
|
64
60
|
# route_key [Symbol, String] The route key for the association
|
65
|
-
route_key: nil
|
66
|
-
# view [IRI] The view to use for rendering the members
|
67
|
-
view: nil
|
61
|
+
route_key: nil
|
68
62
|
}.freeze
|
69
63
|
COLLECTION_OPTIONS = COLLECTION_CUSTOMIZABLE_OPTIONS.merge(COLLECTION_STATIC_OPTIONS)
|
70
64
|
|
@@ -85,7 +79,7 @@ module LinkedRails
|
|
85
79
|
|
86
80
|
_default_collection_opts[key] = value
|
87
81
|
end
|
88
|
-
_default_collection_opts[:iri_template] =
|
82
|
+
_default_collection_opts[:iri_template] = LinkedRails.collection_class.generate_iri_template(
|
89
83
|
_default_collection_opts[:iri_template_keys]
|
90
84
|
)
|
91
85
|
_default_collection_opts
|
@@ -121,7 +115,7 @@ module LinkedRails
|
|
121
115
|
options[:association] ||= name.to_sym
|
122
116
|
options[:association_class] ||= name.to_s.classify.constantize
|
123
117
|
merged_options = options[:association_class].default_collection_options.merge(options)
|
124
|
-
merged_options[:iri_template] =
|
118
|
+
merged_options[:iri_template] = LinkedRails.collection_class.generate_iri_template(
|
125
119
|
merged_options[:iri_template_keys]
|
126
120
|
)
|
127
121
|
collections_add(name: name, options: merged_options)
|
@@ -153,7 +147,7 @@ module LinkedRails
|
|
153
147
|
|
154
148
|
_default_collection_opts[:collection_class] ||= LinkedRails.collection_class
|
155
149
|
_default_collection_opts[:association_class] = self
|
156
|
-
_default_collection_opts[:iri_template] =
|
150
|
+
_default_collection_opts[:iri_template] = LinkedRails.collection_class.generate_iri_template(
|
157
151
|
_default_collection_opts[:iri_template_keys]
|
158
152
|
)
|
159
153
|
|
@@ -22,28 +22,40 @@ module LinkedRails
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
25
|
+
def previous_changes_by_predicate
|
26
|
+
serializer_class = RDF::Serializers.serializer_for(self)
|
27
|
+
return {} unless respond_to?(:previous_changes) && serializer_class
|
28
|
+
|
29
|
+
Hash[
|
30
|
+
previous_changes
|
31
|
+
.map { |k, v| [self.class.predicate_for_key(k.to_sym), v] }
|
32
|
+
.select { |k, _v| k.present? }
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
def previously_changed_relations
|
26
37
|
serializer_class = RDF::Serializers.serializer_for(self)
|
27
38
|
return {} unless serializer_class.try(:relationships_to_serialize)
|
28
39
|
|
29
40
|
serializer_class.relationships_to_serialize.select do |key, _value|
|
30
41
|
if respond_to?(key)
|
31
42
|
association_key = key.to_s.ends_with?('_collection') ? send(key).association : key
|
32
|
-
association_has_destructed?(association_key) || association_changed?(association_key
|
43
|
+
association_has_destructed?(association_key) || association_changed?(association_key)
|
33
44
|
end
|
34
45
|
end.with_indifferent_access
|
35
46
|
end
|
36
47
|
|
37
48
|
private
|
38
49
|
|
39
|
-
def association_changed?(association
|
50
|
+
def association_changed?(association) # rubocop:disable Metrics/AbcSize
|
40
51
|
ids_method = "#{association.to_s.singularize}_ids"
|
41
52
|
return true if previous_changes.include?("#{association}_id") || previous_changes.include?(ids_method)
|
42
53
|
return false unless try(:association_cached?, association)
|
43
|
-
records = self.class.reflect_on_association(association).collection? ? send(association) : [send(association)]
|
44
54
|
|
45
|
-
|
46
|
-
|
55
|
+
if self.class.reflect_on_association(association).collection?
|
56
|
+
send(association).any? { |a| a.previous_changes.present? }
|
57
|
+
else
|
58
|
+
send(association)&.previous_changes&.present?
|
47
59
|
end
|
48
60
|
end
|
49
61
|
|
@@ -17,7 +17,7 @@ module LinkedRails
|
|
17
17
|
def filterable(**options)
|
18
18
|
initialize_filter_options
|
19
19
|
|
20
|
-
self.filter_options =
|
20
|
+
self.filter_options = HashWithIndifferentAccess.new(options).merge(filter_options)
|
21
21
|
|
22
22
|
options.map { |k, filter| define_filter_method(k, filter) }
|
23
23
|
end
|
@@ -34,7 +34,7 @@ module LinkedRails
|
|
34
34
|
def initialize_filter_options
|
35
35
|
return if filter_options && method(:filter_options).owner == singleton_class
|
36
36
|
|
37
|
-
self.filter_options = superclass.try(:filter_options)&.dup ||
|
37
|
+
self.filter_options = superclass.try(:filter_options)&.dup || {}
|
38
38
|
end
|
39
39
|
|
40
40
|
def define_filter_method(key, filter)
|
@@ -27,7 +27,7 @@ module LinkedRails
|
|
27
27
|
private
|
28
28
|
|
29
29
|
def collection_from_parent_name(parent, _params)
|
30
|
-
collection_name = "#{name.
|
30
|
+
collection_name = "#{name.underscore}_collection"
|
31
31
|
|
32
32
|
collection_name if parent.respond_to?(collection_name, true)
|
33
33
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module LinkedRails
|
4
4
|
module Model
|
5
|
-
module
|
5
|
+
module Iri
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
def anonymous_iri
|
@@ -62,7 +62,6 @@ module LinkedRails
|
|
62
62
|
iri = root_relative_iri.dup
|
63
63
|
iri.scheme = LinkedRails.scheme
|
64
64
|
iri.host = LinkedRails.host
|
65
|
-
iri.path = iri.path.presence || '/'
|
66
65
|
iri
|
67
66
|
end
|
68
67
|
|
@@ -109,22 +108,11 @@ module LinkedRails
|
|
109
108
|
@iri_template ||= LinkedRails::URITemplate.new("/#{route_key}{/id}{#fragment}")
|
110
109
|
end
|
111
110
|
|
112
|
-
def iris_from_scope(scope)
|
113
|
-
ids = ids_for_iris(scope).uniq
|
114
|
-
ids.map { |id| LinkedRails.iri(path: iri_template.expand(id: id)) }
|
115
|
-
end
|
116
|
-
|
117
|
-
def ids_for_iris(scope)
|
118
|
-
scope.pluck(:id)
|
119
|
-
end
|
120
|
-
|
121
111
|
def linked_rails_module?
|
122
112
|
(Rails.version < '6' ? parents : module_parents).include?(LinkedRails)
|
123
113
|
end
|
124
114
|
|
125
|
-
|
126
|
-
try(:model_name)&.route_key || to_s.tableize
|
127
|
-
end
|
115
|
+
delegate :route_key, to: :model_name
|
128
116
|
end
|
129
117
|
end
|
130
118
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module LinkedRails
|
4
4
|
module Model
|
5
|
-
module
|
5
|
+
module IriMapping
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
module ClassMethods
|
@@ -51,7 +51,7 @@ module LinkedRails
|
|
51
51
|
if self < ActiveRecord::Base
|
52
52
|
find_by(primary_key => params[:id]) if params.key?(:id)
|
53
53
|
else
|
54
|
-
new(params
|
54
|
+
new(params)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -85,7 +85,7 @@ module LinkedRails
|
|
85
85
|
|
86
86
|
def iri_without_action(url)
|
87
87
|
iri = RDF::URI(url)
|
88
|
-
iri.path = iri.path.split('/')[0...-1].join('/')
|
88
|
+
iri.path = iri.path.split('/')[0...-1].join('/')
|
89
89
|
iri.to_s
|
90
90
|
end
|
91
91
|
|
@@ -14,7 +14,7 @@ module LinkedRails
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def menu_list(user_context = nil)
|
17
|
-
@menu_list
|
17
|
+
@menu_list = {}
|
18
18
|
@menu_list[user_context] ||= self.class.menu_class.new(resource: self, user_context: user_context)
|
19
19
|
end
|
20
20
|
|
@@ -22,6 +22,12 @@ module LinkedRails
|
|
22
22
|
def menu_class
|
23
23
|
@menu_class ||= "#{name}MenuList".safe_constantize || "#{superclass.name}MenuList".safe_constantize
|
24
24
|
end
|
25
|
+
|
26
|
+
def preview_includes
|
27
|
+
return super if menu_class.blank?
|
28
|
+
|
29
|
+
super + menu_class.defined_menus.keys.map { |tag| "#{tag}_menu" }
|
30
|
+
end
|
25
31
|
end
|
26
32
|
end
|
27
33
|
end
|
@@ -16,6 +16,10 @@ module LinkedRails
|
|
16
16
|
end
|
17
17
|
|
18
18
|
module ClassMethods
|
19
|
+
def include_in_collection?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
19
23
|
def input_select_property
|
20
24
|
Vocab.schema.name
|
21
25
|
end
|
@@ -55,7 +59,7 @@ module LinkedRails
|
|
55
59
|
serializer
|
56
60
|
.attributes_to_serialize
|
57
61
|
.values
|
58
|
-
.select { |attr| attr.predicate.present?
|
62
|
+
.select { |attr| attr.predicate.present? }
|
59
63
|
.map { |attr| [attr.predicate, attr] }
|
60
64
|
end
|
61
65
|
|
@@ -66,7 +70,7 @@ module LinkedRails
|
|
66
70
|
serializer
|
67
71
|
.relationships_to_serialize
|
68
72
|
.values
|
69
|
-
.select { |value| value.predicate.present?
|
73
|
+
.select { |value| value.predicate.present? }
|
70
74
|
.map { |value| [value.predicate, value] }
|
71
75
|
end
|
72
76
|
end
|
@@ -14,7 +14,7 @@ module LinkedRails
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def root_relative_iri(**opts)
|
17
|
-
return super unless
|
17
|
+
return super unless anonymous_iri?
|
18
18
|
|
19
19
|
root_relative_singular_iri(**opts)
|
20
20
|
end
|
@@ -25,10 +25,6 @@ module LinkedRails
|
|
25
25
|
@singular_iri ||= iri_with_root(root_relative_singular_iri)
|
26
26
|
end
|
27
27
|
|
28
|
-
def singular_iri?
|
29
|
-
anonymous_iri?
|
30
|
-
end
|
31
|
-
|
32
28
|
def singular_iri_opts
|
33
29
|
{}
|
34
30
|
end
|
@@ -42,8 +38,6 @@ module LinkedRails
|
|
42
38
|
end
|
43
39
|
|
44
40
|
class_methods do
|
45
|
-
delegate :singular_route_key, to: :model_name
|
46
|
-
|
47
41
|
def requested_singular_resource(_params, _user_context)
|
48
42
|
raise(NotImplementedError)
|
49
43
|
end
|
@@ -51,6 +45,10 @@ module LinkedRails
|
|
51
45
|
def singular_iri_template
|
52
46
|
@singular_iri_template ||= LinkedRails::URITemplate.new("{/parent_iri*}/#{singular_route_key}{#fragment}")
|
53
47
|
end
|
48
|
+
|
49
|
+
def singular_route_key
|
50
|
+
name.underscore
|
51
|
+
end
|
54
52
|
end
|
55
53
|
end
|
56
54
|
end
|
@@ -18,7 +18,7 @@ module LinkedRails
|
|
18
18
|
def initialize_columns
|
19
19
|
return if defined_columns && method(:defined_columns).owner == singleton_class
|
20
20
|
|
21
|
-
self.defined_columns = superclass.try(:defined_columns)&.dup || {}
|
21
|
+
self.defined_columns = superclass.try(:defined_columns)&.dup || {}
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
data/lib/linked_rails/model.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'model/actionable'
|
4
|
-
require_relative 'model/cacheable'
|
5
4
|
require_relative 'model/collections'
|
6
5
|
require_relative 'model/dirty'
|
7
6
|
require_relative 'model/enhancements'
|
@@ -24,8 +23,8 @@ module LinkedRails
|
|
24
23
|
include Enhancements
|
25
24
|
include Filtering
|
26
25
|
include Indexable
|
27
|
-
include
|
28
|
-
include
|
26
|
+
include Iri
|
27
|
+
include IriMapping
|
29
28
|
include Menuable
|
30
29
|
include Serialization
|
31
30
|
include Singularable
|
@@ -38,8 +37,6 @@ module LinkedRails
|
|
38
37
|
|
39
38
|
module ClassMethods
|
40
39
|
def build_new(parent: nil, user_context: nil)
|
41
|
-
raise(ActiveRecord::RecordNotFound) if try(:abstract_class?)
|
42
|
-
|
43
40
|
new(**attributes_for_new(parent: parent, user_context: user_context))
|
44
41
|
end
|
45
42
|
|