iqvoc 4.7.0 → 4.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/Gemfile +11 -11
- data/Gemfile.lock +178 -122
- data/README.md +39 -24
- data/{test/performance/browsing_test.rb → app/aides/inline_data_helper.rb} +23 -6
- data/app/aides/maker.rb +139 -0
- data/{lib → app/aides}/multi_logger.rb +0 -0
- data/app/aides/origin.rb +47 -0
- data/app/aides/rdfapi.rb +59 -0
- data/app/aides/skos_exporter.rb +151 -0
- data/app/aides/skos_importer.rb +348 -0
- data/app/assets/javascripts/iqvoc/entityselect.js.erb +7 -9
- data/app/controllers/application_controller.rb +1 -3
- data/app/controllers/collections/versions_controller.rb +1 -3
- data/app/controllers/concepts/versions_controller.rb +9 -3
- data/app/controllers/concerns/controller_extensions.rb +109 -0
- data/app/{concerns → controllers/concerns}/reverse_match_errors.rb +0 -0
- data/app/controllers/hierarchy_controller.rb +7 -3
- data/app/controllers/instance_configuration_controller.rb +1 -1
- data/app/controllers/pages_controller.rb +10 -0
- data/app/controllers/search_results_controller.rb +2 -2
- data/app/controllers/triplestore_sync_controller.rb +2 -4
- data/app/helpers/application_helper.rb +1 -1
- data/app/helpers/widget_helper.rb +3 -3
- data/app/jobs/export_job.rb +1 -3
- data/app/jobs/import_job.rb +1 -3
- data/app/models/ability.rb +59 -0
- data/app/models/abstract_user.rb +1 -1
- data/app/models/collection/base.rb +12 -3
- data/app/models/collection/member/skos/base.rb +1 -1
- data/app/models/concept/base.rb +15 -8
- data/app/models/concept/relation/base.rb +1 -1
- data/app/models/concept/relation/skos/base.rb +1 -1
- data/app/models/concept/skos/scheme.rb +1 -1
- data/app/models/concept/validations.rb +1 -1
- data/app/models/concerns/deep_cloning.rb +92 -0
- data/app/models/concerns/first_level_object_scopes.rb +9 -0
- data/app/{concerns → models/concerns}/first_level_object_validations.rb +9 -2
- data/app/models/concerns/rankable.rb +31 -0
- data/app/models/{search_extension.rb → concerns/search_extension.rb} +0 -0
- data/app/{concerns → models/concerns}/versioning.rb +0 -6
- data/app/models/configuration_setting.rb +1 -1
- data/app/models/labeling/skos/base.rb +2 -2
- data/app/models/match/skos/base.rb +2 -2
- data/app/models/note/skos/base.rb +7 -6
- data/app/models/note/skos/change_note.rb +1 -1
- data/{lib/iqvoc/rdf_sync.rb → app/services/rdf_sync_service.rb} +3 -3
- data/app/view_models/concept_view.rb +1 -1
- data/app/views/collections/_form.html.erb +2 -2
- data/app/views/concepts/scheme/edit.html.erb +1 -1
- data/app/views/pages/components.html.erb +45 -0
- data/app/views/pages/version.html.erb +6 -0
- data/app/views/partials/concept/_reverse_match_notice.html.erb +0 -1
- data/app/views/search_results/_sidebar.html.erb +3 -3
- data/config/application.rb +4 -1
- data/config/boot.rb +1 -2
- data/config/database.yml.postgresql +23 -0
- data/config/engine.rb +0 -2
- data/config/environments/heroku.rb +1 -1
- data/config/initializers/inflections.rb +9 -3
- data/config/initializers/iqvoc.rb +1 -7
- data/config/initializers/mime_types.rb +0 -1
- data/config/locales/de.yml +2 -1
- data/config/locales/en.yml +11 -10
- data/config/routes.rb +2 -0
- data/config/travis/database.yml.mysql +9 -0
- data/config/travis/database.yml.postgresql +7 -0
- data/config/travis/database.yml.sqlite +5 -0
- data/db/migrate/20141204151558_add_foreign_key_constraints.rb +23 -0
- data/iqvoc.gemspec +2 -2
- data/lib/generators/app/template.rb +15 -7
- data/lib/iqvoc.rb +2 -1
- data/lib/iqvoc/configuration/core.rb +18 -4
- data/lib/iqvoc/configuration/instance_configuration.rb +125 -0
- data/lib/iqvoc/configuration/navigation.rb +63 -0
- data/lib/iqvoc/environments/development.rb +4 -0
- data/lib/iqvoc/environments/production.rb +11 -12
- data/lib/iqvoc/environments/test.rb +4 -1
- data/lib/iqvoc/version.rb +2 -2
- data/lib/tasks/exporter.rake +1 -4
- data/lib/tasks/importer.rake +1 -5
- data/lib/tasks/sync.rake +1 -2
- data/test/controllers/concept_movement_test.rb +11 -11
- data/test/controllers/hierarchy_test.rb +83 -79
- data/test/controllers/reverse_match_test.rb +2 -2
- data/test/integration/alphabetical_test.rb +2 -3
- data/test/integration/browse_concepts_and_labels_test.rb +2 -2
- data/test/integration/collection_circularity_test.rb +6 -6
- data/test/integration/concept_scheme_browsing_test.rb +2 -2
- data/test/integration/edit_concepts_test.rb +1 -1
- data/test/integration/export_test.rb +5 -3
- data/test/integration/import_test.rb +4 -1
- data/test/integration/instance_configuration_browsing_test.rb +2 -2
- data/test/integration/navigation_test.rb +2 -2
- data/test/integration/note_annotations_test.rb +12 -11
- data/test/integration/reverse_match_job_test.rb +19 -10
- data/test/integration/search_test.rb +6 -6
- data/test/integration/tree_test.rb +3 -3
- data/test/integration/untranslated_test.rb +1 -1
- data/test/models/concept_test.rb +13 -14
- data/test/models/inline_data_test.rb +9 -9
- data/test/models/instance_configuration_test.rb +7 -3
- data/test/models/origin_test.rb +9 -59
- data/test/models/rdf_sync_test.rb +2 -4
- data/test/models/rdfapi_test.rb +0 -2
- data/test/models/skos_collection_import_test.rb +3 -4
- data/test/models/skos_export_test.rb +3 -5
- data/test/models/skos_import_test.rb +12 -10
- data/test/test_helper.rb +0 -1
- data/vendor/assets/stylesheets/{jquery-ui.css.scss → jquery-ui.scss} +0 -0
- data/vendor/assets/stylesheets/{jquery-ui.structure.css.scss → jquery-ui.structure.scss} +0 -0
- data/vendor/assets/stylesheets/{jquery-ui.theme.css.scss → jquery-ui.theme.scss} +0 -0
- metadata +34 -28
- data/lib/iqvoc/ability.rb +0 -60
- data/lib/iqvoc/controller_extensions.rb +0 -111
- data/lib/iqvoc/deep_cloning.rb +0 -90
- data/lib/iqvoc/inline_data_helper.rb +0 -45
- data/lib/iqvoc/instance_configuration.rb +0 -123
- data/lib/iqvoc/maker.rb +0 -141
- data/lib/iqvoc/navigation.rb +0 -61
- data/lib/iqvoc/origin.rb +0 -111
- data/lib/iqvoc/rankable.rb +0 -33
- data/lib/iqvoc/rdfapi.rb +0 -60
- data/lib/iqvoc/skos_exporter.rb +0 -153
- data/lib/iqvoc/skos_importer.rb +0 -337
File without changes
|
@@ -113,6 +113,7 @@ class HierarchyController < ApplicationController
|
|
113
113
|
|
114
114
|
scope = Iqvoc::Concept.base_class
|
115
115
|
scope = include_unpublished ? scope.editor_selectable : scope.published
|
116
|
+
scope = scope.ordered_by_pref_label
|
116
117
|
|
117
118
|
# validate depth parameter
|
118
119
|
if not depth
|
@@ -176,7 +177,8 @@ class HierarchyController < ApplicationController
|
|
176
177
|
|
177
178
|
rels = scope.where(Concept::Relation::Base.arel_table[:target_id].
|
178
179
|
eq(root_concept.id)).references(:concept_relations)
|
179
|
-
|
180
|
+
|
181
|
+
results = rels.inject({}) do |memo, concept|
|
180
182
|
if include_siblings
|
181
183
|
determine_siblings(concept).each { |sib| memo[sib] = {} }
|
182
184
|
end
|
@@ -184,12 +186,14 @@ class HierarchyController < ApplicationController
|
|
184
186
|
current_depth, include_siblings)
|
185
187
|
memo
|
186
188
|
end
|
189
|
+
|
190
|
+
results
|
187
191
|
end
|
188
192
|
|
189
193
|
# NB: includes support for poly-hierarchies -- XXX: untested
|
190
194
|
def determine_siblings(concept)
|
191
|
-
|
195
|
+
concept.broader_relations.map do |rel|
|
192
196
|
rel.target.narrower_relations.map { |rel| rel.target } # XXX: expensive
|
193
|
-
end.flatten.uniq
|
197
|
+
end.flatten.uniq.sort { |a, b| a.pref_label <=> b.pref_label }
|
194
198
|
end
|
195
199
|
end
|
@@ -69,7 +69,7 @@ class InstanceConfigurationController < ApplicationController
|
|
69
69
|
|
70
70
|
# default value determines value type
|
71
71
|
def serialize(value, default_value)
|
72
|
-
Iqvoc::InstanceConfiguration.validate_value(value)
|
72
|
+
Iqvoc::Configuration::InstanceConfiguration.validate_value(value)
|
73
73
|
if default_value.is_a?(Array)
|
74
74
|
return value.to_csv.strip
|
75
75
|
else # boolean, String, Fixnum / Float
|
@@ -15,7 +15,17 @@
|
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
17
|
class PagesController < ApplicationController
|
18
|
+
def components
|
19
|
+
#authorize! :read, :components
|
20
|
+
@concepts_uri = concepts_path(:format => :json)
|
21
|
+
@concept_uri = concept_path(:id => "{id}")
|
22
|
+
end
|
23
|
+
|
18
24
|
def help
|
19
25
|
authorize! :read, :help
|
20
26
|
end
|
27
|
+
|
28
|
+
def version
|
29
|
+
authorize! :read, :version
|
30
|
+
end
|
21
31
|
end
|
@@ -113,13 +113,13 @@ class SearchResultsController < ApplicationController
|
|
113
113
|
|
114
114
|
if klass.forces_multi_query? || (klass.supports_multi_query? && query_size > 1)
|
115
115
|
@multi_query = true
|
116
|
-
@results = klass.multi_query(params.merge({ languages: languages }))
|
116
|
+
@results = klass.multi_query(params.merge({ languages: languages.flatten }))
|
117
117
|
# TODO: Add a worst case limit here; e.g. when on page 2 (per_page == 50)
|
118
118
|
# each sub-query has to return 100 objects at most.
|
119
119
|
@klass = klass
|
120
120
|
else
|
121
121
|
@multi_query = false
|
122
|
-
@results = klass.single_query(params.merge({ languages: languages }))
|
122
|
+
@results = klass.single_query(params.merge({ languages: languages.flatten }))
|
123
123
|
end
|
124
124
|
|
125
125
|
if @multi_query
|
@@ -14,10 +14,8 @@
|
|
14
14
|
# See the License for the specific language governing permissions and
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
|
-
require 'iqvoc/rdf_sync'
|
18
|
-
|
19
17
|
class TriplestoreSyncController < ApplicationController
|
20
|
-
include
|
18
|
+
include RDFSyncService::Helper
|
21
19
|
|
22
20
|
def index
|
23
21
|
authorize! :use, :dashboard
|
@@ -42,7 +40,7 @@ class TriplestoreSyncController < ApplicationController
|
|
42
40
|
end
|
43
41
|
|
44
42
|
# per-class pagination
|
45
|
-
@candidates =
|
43
|
+
@candidates = RDFSyncService.candidates.map do |records|
|
46
44
|
records.page(params[:page])
|
47
45
|
end
|
48
46
|
end
|
@@ -5,13 +5,13 @@ module WidgetHelper
|
|
5
5
|
|
6
6
|
def widget_values_ranked(concept, relation_class)
|
7
7
|
concepts_with_ranks = concept.concept_relations_by_id_and_rank(relation_class.name.to_relation_name)
|
8
|
-
concepts_with_ranks.map { |concept, rank| "#{concept.origin}:#{rank}" }.join(
|
8
|
+
concepts_with_ranks.map { |concept, rank| "#{concept.origin}:#{rank}" }.join(InlineDataHelper::JOINER)
|
9
9
|
end
|
10
10
|
|
11
11
|
def widget_entities(concept, relation_class)
|
12
12
|
origins = concept.
|
13
13
|
concept_relations_by_id(relation_class.name.to_relation_name).
|
14
|
-
split(
|
14
|
+
split(InlineDataHelper::SPLITTER)
|
15
15
|
|
16
16
|
Iqvoc::Concept.base_class.
|
17
17
|
editor_selectable.
|
@@ -23,7 +23,7 @@ module WidgetHelper
|
|
23
23
|
def widget_entities_ranked(concept, relation_class)
|
24
24
|
origins = concept.
|
25
25
|
concept_relations_by_id(relation_class.name.to_relation_name).
|
26
|
-
split(
|
26
|
+
split(InlineDataHelper::SPLITTER)
|
27
27
|
|
28
28
|
allowed_concepts = Iqvoc::Concept.base_class.
|
29
29
|
editor_selectable.
|
data/app/jobs/export_job.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
-
require 'iqvoc/skos_exporter'
|
2
|
-
|
3
1
|
class ExportJob < Struct.new(:export, :filename, :type, :base_uri)
|
4
2
|
def perform
|
5
3
|
strio = StringIO.new
|
6
4
|
|
7
|
-
exporter =
|
5
|
+
exporter = SkosExporter.new(filename, type, base_uri, Logger.new(strio))
|
8
6
|
exporter.run
|
9
7
|
@messages = strio.string
|
10
8
|
end
|
data/app/jobs/import_job.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
-
require 'iqvoc/skos_importer'
|
2
|
-
|
3
1
|
class ImportJob < Struct.new(:import, :filename, :user, :namespace, :publish)
|
4
2
|
def perform
|
5
3
|
strio = StringIO.new
|
6
4
|
|
7
|
-
importer =
|
5
|
+
importer = SkosImporter.new(filename, namespace, Logger.new(strio), publish)
|
8
6
|
importer.run
|
9
7
|
@messages = strio.string
|
10
8
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class Ability
|
2
|
+
include CanCan::Ability
|
3
|
+
|
4
|
+
@@if_published = lambda { |o| o.published? }
|
5
|
+
|
6
|
+
def initialize(user = nil)
|
7
|
+
can :read, Iqvoc::Concept.root_class.instance
|
8
|
+
can :read, [::Concept::Base, ::Collection::Base, ::Label::Base], &@@if_published
|
9
|
+
|
10
|
+
# static pages
|
11
|
+
can :read, :help
|
12
|
+
can :read, :version
|
13
|
+
|
14
|
+
if user # Every logged in user ...
|
15
|
+
can :use, :dashboard
|
16
|
+
can :destroy, UserSession
|
17
|
+
|
18
|
+
if user.owns_role?(:editor) || user.owns_role?(:publisher) || user.owns_role?(:administrator) # Editors and above ...
|
19
|
+
can :read, [::Concept::Base, ::Collection::Base, ::Label::Base]
|
20
|
+
can :create, [::Concept::Base, ::Collection::Base, ::Label::Base]
|
21
|
+
can [:update, :destroy, :unlock], [::Concept::Base, ::Collection::Base, ::Label::Base], locked_by: user.id, published_at: nil
|
22
|
+
can :lock, [::Concept::Base, ::Collection::Base, ::Label::Base], locked_by: nil, published_at: nil
|
23
|
+
can [:check_consistency, :send_to_review], [::Concept::Base, ::Collection::Base, ::Label::Base], published_at: nil
|
24
|
+
can :branch, [::Concept::Base, ::Collection::Base, ::Label::Base], &@@if_published
|
25
|
+
end
|
26
|
+
|
27
|
+
if user.owns_role?(:match_editor)
|
28
|
+
can :read, ::Concept::Base
|
29
|
+
can :create, ::Concept::Base
|
30
|
+
can [:update, :lock], ::Concept::Base, locked_by: user.id, published_at: nil
|
31
|
+
can :lock, ::Concept::Base, locked_by: nil, published_at: nil
|
32
|
+
can :branch, ::Concept::Base, &@@if_published
|
33
|
+
end
|
34
|
+
|
35
|
+
if user.owns_role?(:publisher) || user.owns_role?(:administrator) # Publishers and above ...
|
36
|
+
can :merge, [::Concept::Base, ::Collection::Base, ::Label::Base], published_at: nil
|
37
|
+
end
|
38
|
+
|
39
|
+
if user.owns_role?(:administrator)
|
40
|
+
can [:update, :destroy, :unlock], [::Concept::Base, ::Label::Base], published_at: nil # Mustn't be locked by myself
|
41
|
+
|
42
|
+
can :manage, User
|
43
|
+
can :manage, Iqvoc.config
|
44
|
+
|
45
|
+
can :full_export, ::Concept::Base
|
46
|
+
can :import, ::Concept::Base
|
47
|
+
can :export, ::Concept::Base
|
48
|
+
|
49
|
+
can :update, Iqvoc::Concept.root_class.instance
|
50
|
+
|
51
|
+
can :use, :administration
|
52
|
+
|
53
|
+
can :reset, :thesaurus
|
54
|
+
end
|
55
|
+
else # no user
|
56
|
+
can :create, UserSession
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/app/models/abstract_user.rb
CHANGED
@@ -34,7 +34,16 @@ class Collection::Base < Concept::Base
|
|
34
34
|
|
35
35
|
include_to_deep_cloning(:members, :collection_members)
|
36
36
|
|
37
|
-
|
37
|
+
# ********** Hooks
|
38
|
+
|
39
|
+
after_initialize do |collection|
|
40
|
+
if collection.origin.blank?
|
41
|
+
collection.origin = Origin.new.to_s
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
after_save :regenerate_concept_members,
|
46
|
+
:regenerate_collection_members
|
38
47
|
|
39
48
|
validate :circular_subcollections
|
40
49
|
|
@@ -90,7 +99,7 @@ class Collection::Base < Concept::Base
|
|
90
99
|
|
91
100
|
def inline_member_concept_origins=(origins)
|
92
101
|
@member_concept_origins = origins.to_s.
|
93
|
-
split(
|
102
|
+
split(InlineDataHelper::SPLITTER).map(&:strip)
|
94
103
|
end
|
95
104
|
|
96
105
|
def inline_member_concept_origins
|
@@ -107,7 +116,7 @@ class Collection::Base < Concept::Base
|
|
107
116
|
|
108
117
|
def inline_member_collection_origins=(origins)
|
109
118
|
@member_collection_origins = origins.to_s.
|
110
|
-
split(
|
119
|
+
split(InlineDataHelper::SPLITTER).map(&:strip)
|
111
120
|
end
|
112
121
|
|
113
122
|
def inline_member_collection_origins
|
@@ -24,7 +24,7 @@ class Collection::Member::SKOS::Base < Collection::Member::Base
|
|
24
24
|
|
25
25
|
member_instance = rdf_subject.members.detect{ |rel| rel.target == rdf_object }
|
26
26
|
if member_instance.nil?
|
27
|
-
predicate_class =
|
27
|
+
predicate_class = RDFAPI::PREDICATE_DICTIONARY[rdf_predicate] || self
|
28
28
|
member_instance = predicate_class.new(target: rdf_object)
|
29
29
|
rdf_subject.members << member_instance
|
30
30
|
end
|
data/app/models/concept/base.rb
CHANGED
@@ -32,9 +32,16 @@ class Concept::Base < ActiveRecord::Base
|
|
32
32
|
include Versioning
|
33
33
|
include Concept::Validations
|
34
34
|
include FirstLevelObjectValidations
|
35
|
+
include FirstLevelObjectScopes
|
35
36
|
|
36
37
|
# ********** Hooks
|
37
38
|
|
39
|
+
after_initialize do |concept|
|
40
|
+
if concept.origin.blank?
|
41
|
+
concept.origin = Origin.new.to_s
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
38
45
|
before_validation do |concept|
|
39
46
|
# Handle save or destruction of inline relations (relations or labelings)
|
40
47
|
# for use with widgets etc.
|
@@ -50,7 +57,7 @@ class Concept::Base < ActiveRecord::Base
|
|
50
57
|
lang_values = { nil => lang_values.first } if lang_values.is_a?(Array) # For language = nil: <input name=bla[labeling_class][]> => Results in an Array! -- XXX: obsolete/dupe (cf `labelings_by_text=`)?
|
51
58
|
lang_values.each do |lang, inline_values|
|
52
59
|
lang = nil if lang.to_s == 'none'
|
53
|
-
|
60
|
+
InlineDataHelper.parse_inline_values(inline_values).each do |value|
|
54
61
|
value.squish!
|
55
62
|
unless value.blank?
|
56
63
|
self.send(relation_name).build(target: labeling_class.label_class.new(value: value, language: lang))
|
@@ -72,7 +79,7 @@ class Concept::Base < ActiveRecord::Base
|
|
72
79
|
# rankable: {'relation_name' => ['origin1:100', 'origin2:90']}
|
73
80
|
(@concept_relations_by_id ||= {}).each do |relation_name, new_origins|
|
74
81
|
# Split comma-separated origins and clean up parameter strings
|
75
|
-
new_origins = new_origins.split(
|
82
|
+
new_origins = new_origins.split(InlineDataHelper::SPLITTER).map(&:squish)
|
76
83
|
|
77
84
|
# Extract embedded ranks (if any) from origin strings (e.g. "origin1:100")
|
78
85
|
# => { 'origin1' => nil, 'origin2' => 90 }
|
@@ -184,7 +191,7 @@ class Concept::Base < ActiveRecord::Base
|
|
184
191
|
unless Iqvoc::Concept.labeling_classes.keys.detect { |klass| labeling_class_name.constantize < klass }
|
185
192
|
# When a Label has only one labeling (the "no skosxl" case) we'll have to
|
186
193
|
# clone the label too.
|
187
|
-
if labeling_class_name.constantize.reflections[
|
194
|
+
if labeling_class_name.constantize.reflections['target'].options[:dependent] == :destroy
|
188
195
|
include_to_deep_cloning(labeling_class_name.to_relation_name => :target)
|
189
196
|
else
|
190
197
|
include_to_deep_cloning(labeling_class_name.to_relation_name)
|
@@ -199,13 +206,13 @@ class Concept::Base < ActiveRecord::Base
|
|
199
206
|
class_name: match_class_name,
|
200
207
|
foreign_key: 'concept_id'
|
201
208
|
|
202
|
-
# Serialized setters and getters (\r\n or , separated) -- TODO: use
|
209
|
+
# Serialized setters and getters (\r\n or , separated) -- TODO: use InlineDataHelper?
|
203
210
|
define_method("inline_#{match_class_name.to_relation_name}".to_sym) do
|
204
|
-
self.send(match_class_name.to_relation_name).map(&:value).join(
|
211
|
+
self.send(match_class_name.to_relation_name).map(&:value).join(InlineDataHelper::JOINER)
|
205
212
|
end
|
206
213
|
|
207
214
|
define_method("inline_#{match_class_name.to_relation_name}=".to_sym) do |value|
|
208
|
-
urls = value.split(
|
215
|
+
urls = value.split(InlineDataHelper::SPLITTER).map(&:strip).reject(&:blank?)
|
209
216
|
self.send(match_class_name.to_relation_name).each do |match|
|
210
217
|
if (urls.include?(match.value))
|
211
218
|
urls.delete(match.value) # We're done with that one
|
@@ -319,7 +326,7 @@ class Concept::Base < ActiveRecord::Base
|
|
319
326
|
def labelings_by_text(relation_name, language)
|
320
327
|
(@labelings_by_text && @labelings_by_text[relation_name] &&
|
321
328
|
@labelings_by_text[relation_name][language]) ||
|
322
|
-
|
329
|
+
InlineDataHelper.generate_inline_values(self.send(relation_name).
|
323
330
|
by_label_language(language).map { |l| l.target.value })
|
324
331
|
end
|
325
332
|
|
@@ -330,7 +337,7 @@ class Concept::Base < ActiveRecord::Base
|
|
330
337
|
def concept_relations_by_id(relation_name)
|
331
338
|
(@concept_relations_by_id && @concept_relations_by_id[relation_name]) ||
|
332
339
|
self.send(relation_name).map { |l| l.target.origin }.
|
333
|
-
join(
|
340
|
+
join(InlineDataHelper::JOINER)
|
334
341
|
end
|
335
342
|
|
336
343
|
def concept_relations_by_id_and_rank(relation_name)
|
@@ -21,7 +21,7 @@ class Concept::Relation::SKOS::Base < Concept::Relation::Base
|
|
21
21
|
raise "#{self.name}#build_from_rdf: Subject (#{rdf_subject}) must be a Concept." unless rdf_subject.is_a? Concept::Base
|
22
22
|
raise "#{self.name}#build_from_rdf: Object (#{rdf_object}) must be a Concept." unless rdf_object.is_a? Concept::Base
|
23
23
|
|
24
|
-
relation_class =
|
24
|
+
relation_class = RDFAPI::PREDICATE_DICTIONARY[rdf_predicate] || self
|
25
25
|
|
26
26
|
relation_instance = rdf_subject.send(self.name.to_relation_name).select{ |rel| rel.target == rdf_object }
|
27
27
|
if relation_instance.empty?
|
@@ -61,7 +61,7 @@ class Concept::SKOS::Scheme < Concept::Base
|
|
61
61
|
|
62
62
|
def inline_top_concept_origins=(origins)
|
63
63
|
@inline_top_concept_origins = origins.to_s.
|
64
|
-
split(
|
64
|
+
split(InlineDataHelper::SPLITTER).map(&:strip)
|
65
65
|
end
|
66
66
|
|
67
67
|
def inline_top_concept_origins
|
@@ -16,7 +16,7 @@ module Concept
|
|
16
16
|
# top term and broader relations are mutually exclusive
|
17
17
|
def exclusive_top_term
|
18
18
|
if validatable_for_publishing?
|
19
|
-
if top_term && broader_relations.any?
|
19
|
+
if top_term? && broader_relations.any?
|
20
20
|
errors.add :base, I18n.t('txt.models.concept.top_term_exclusive_error')
|
21
21
|
end
|
22
22
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Copyright 2011-2013 innoQ Deutschland GmbH
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'active_support/concern'
|
18
|
+
|
19
|
+
module DeepCloning
|
20
|
+
extend ActiveSupport::Concern
|
21
|
+
|
22
|
+
included do #:nodoc:
|
23
|
+
alias_method_chain :dup, :deep_cloning
|
24
|
+
end
|
25
|
+
|
26
|
+
# clones an ActiveRecord model.
|
27
|
+
# if passed the :include option, it will deep clone the given associations
|
28
|
+
# if passed the :except option, it won't clone the given attributes
|
29
|
+
#
|
30
|
+
# === Usage:
|
31
|
+
#
|
32
|
+
# ==== Cloning a model without an attribute
|
33
|
+
# pirate.clone except: :name
|
34
|
+
#
|
35
|
+
# ==== Cloning a model without multiple attributes
|
36
|
+
# pirate.clone except: [:name, :nick_name]
|
37
|
+
# ==== Cloning one single association
|
38
|
+
# pirate.clone include: :mateys
|
39
|
+
#
|
40
|
+
# ==== Cloning multiple associations
|
41
|
+
# pirate.clone include: [:mateys, :treasures]
|
42
|
+
#
|
43
|
+
# ==== Cloning really deep
|
44
|
+
# pirate.clone include: {treasures: :gold_pieces}
|
45
|
+
#
|
46
|
+
# ==== Cloning really deep with multiple associations
|
47
|
+
# pirate.clone include: [:mateys, {treasures: :gold_pieces}]
|
48
|
+
#
|
49
|
+
# ==== Cloning multiple associations - but only the join table entries without cloning the associated objects themselves
|
50
|
+
# pirate.clone include_association: [:matey_ids, :treasure_ids]
|
51
|
+
#
|
52
|
+
def dup_with_deep_cloning(options = {})
|
53
|
+
kopy = dup_without_deep_cloning
|
54
|
+
|
55
|
+
if options[:except]
|
56
|
+
Array(options[:except]).each do |attribute|
|
57
|
+
kopy.write_attribute(attribute, attributes_from_column_definition[attribute.to_s])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
if options[:include_association]
|
62
|
+
Array(options[:include_association]).each do |association_attribute|
|
63
|
+
kopy.send("#{association_attribute}=", self.send("#{association_attribute}"))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
if options[:include]
|
68
|
+
Array(options[:include]).each do |association, deep_associations|
|
69
|
+
if (association.kind_of? Hash)
|
70
|
+
deep_associations = association[association.keys.first]
|
71
|
+
association = association.keys.first
|
72
|
+
end
|
73
|
+
opts = deep_associations.blank? ? {} : { include: deep_associations }
|
74
|
+
association_reflection = self.class.reflect_on_association(association)
|
75
|
+
cloned_object = case association_reflection.macro
|
76
|
+
when :belongs_to, :has_one
|
77
|
+
self.send(association) && self.send(association).dup(opts)
|
78
|
+
when :has_many, :has_and_belongs_to_many
|
79
|
+
fk = association_reflection.options[:foreign_key]# || self.class.to_s.underscore
|
80
|
+
self.send(association).collect do |obj|
|
81
|
+
cloned_obj = obj.dup(opts)
|
82
|
+
cloned_obj.send("#{fk}=", kopy.id) unless fk.blank?
|
83
|
+
cloned_obj
|
84
|
+
end
|
85
|
+
end
|
86
|
+
kopy.send("#{association}=", cloned_object)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
return kopy
|
91
|
+
end
|
92
|
+
end
|