rails-xapi 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +152 -0
- data/Rakefile +8 -0
- data/app/controllers/rails_xapi/application_controller.rb +7 -0
- data/app/helpers/rails_xapi/application_helper.rb +26 -0
- data/app/jobs/rails_xapi/application_job.rb +4 -0
- data/app/jobs/rails_xapi/create_statement_job.rb +11 -0
- data/app/mailers/rails_xapi/application_mailer.rb +6 -0
- data/app/models/concerns/serializable.rb +14 -0
- data/app/models/rails_xapi/account.rb +27 -0
- data/app/models/rails_xapi/activity_definition.rb +143 -0
- data/app/models/rails_xapi/actor.rb +227 -0
- data/app/models/rails_xapi/application_record.rb +5 -0
- data/app/models/rails_xapi/context.rb +163 -0
- data/app/models/rails_xapi/context_activity.rb +37 -0
- data/app/models/rails_xapi/errors/xapi_error.rb +4 -0
- data/app/models/rails_xapi/extension.rb +29 -0
- data/app/models/rails_xapi/group_member.rb +21 -0
- data/app/models/rails_xapi/interaction_activity.rb +103 -0
- data/app/models/rails_xapi/interaction_component.rb +34 -0
- data/app/models/rails_xapi/object.rb +150 -0
- data/app/models/rails_xapi/result.rb +174 -0
- data/app/models/rails_xapi/statement.rb +62 -0
- data/app/models/rails_xapi/validators/language_map_validator.rb +64 -0
- data/app/models/rails_xapi/verb.rb +260 -0
- data/app/services/application_service.rb +16 -0
- data/app/services/rails_xapi/query.rb +217 -0
- data/app/services/rails_xapi/statement_creator.rb +53 -0
- data/app/views/layouts/rails_xapi/application.html.erb +12 -0
- data/config/locales/rails_xapi.en.yml +43 -0
- data/config/locales/rails_xapi.fr.yml +233 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20240716144226_create_rails_xapi_actors.rb +16 -0
- data/db/migrate/20240716144227_create_rails_xapi_accounts.rb +15 -0
- data/db/migrate/20240716144228_create_rails_xapi_verbs.rb +14 -0
- data/db/migrate/20240716144229_create_rails_xapi_objects.rb +16 -0
- data/db/migrate/20240716144230_create_rails_xapi_activity_definitions.rb +17 -0
- data/db/migrate/20240716144231_create_rails_xapi_extensions.rb +13 -0
- data/db/migrate/20240716144232_create_rails_xapi_statements.rb +19 -0
- data/db/migrate/20240716144233_create_rails_xapi_results.rb +21 -0
- data/db/migrate/20240716144234_create_rails_xapi_contexts.rb +23 -0
- data/db/migrate/20240716144235_create_rails_xapi_context_activities.rb +16 -0
- data/db/migrate/20240716144236_create_rails_xapi_group_members.rb +16 -0
- data/db/migrate/20250522093846_create_rails_xapi_interaction_activities.rb +15 -0
- data/db/migrate/20250522122830_create_rails_xapi_interaction_component.rb +16 -0
- data/lib/rails-xapi/configuration.rb +13 -0
- data/lib/rails-xapi/engine.rb +28 -0
- data/lib/rails-xapi/version.rb +5 -0
- data/lib/rails-xapi.rb +16 -0
- data/lib/tasks/auto_annotate_models.rake +62 -0
- data/lib/tasks/rails-xapi_tasks.rake +4 -0
- metadata +122 -0
@@ -0,0 +1,163 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The optional property context.
|
4
|
+
# See: https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#246-context
|
5
|
+
class RailsXapi::Context < ApplicationRecord
|
6
|
+
include Serializable
|
7
|
+
|
8
|
+
belongs_to :instructor, class_name: "RailsXapi::Actor", optional: true
|
9
|
+
belongs_to :team, class_name: "RailsXapi::Actor", optional: true
|
10
|
+
belongs_to :statement, class_name: "RailsXapi::Statement", dependent: :destroy
|
11
|
+
belongs_to :statement_ref,
|
12
|
+
class_name: "RailsXapi::Statement",
|
13
|
+
foreign_key: :statement_ref,
|
14
|
+
optional: true
|
15
|
+
has_many :context_activities, dependent: :destroy
|
16
|
+
has_many :extensions, as: :extendable, dependent: :destroy
|
17
|
+
|
18
|
+
before_validation :validate_platform
|
19
|
+
|
20
|
+
def contextActivities=(context_activities_hash)
|
21
|
+
context_activities_hash.each do |activity_type, activities|
|
22
|
+
activities.each do |activity|
|
23
|
+
# Create the object and update it if necessary.
|
24
|
+
object =
|
25
|
+
RailsXapi::Object.find_or_create(activity) do
|
26
|
+
object.activity_definition = activity[:definition] if activity[
|
27
|
+
:definition
|
28
|
+
].present?
|
29
|
+
end
|
30
|
+
|
31
|
+
object.update(activity)
|
32
|
+
# Create the ContextActivity object.
|
33
|
+
context_activity =
|
34
|
+
RailsXapi::ContextActivity.new(
|
35
|
+
activity_type: activity_type.to_s,
|
36
|
+
object: object
|
37
|
+
)
|
38
|
+
context_activities << context_activity
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Set the instructor value and create the actor if provided.
|
44
|
+
def instructor=(value)
|
45
|
+
return if value.blank?
|
46
|
+
|
47
|
+
actor = find_or_create_actor_with_account(value)
|
48
|
+
super(actor) if actor.present?
|
49
|
+
end
|
50
|
+
|
51
|
+
# Set the team value and create the actor if provided.
|
52
|
+
def team=(value)
|
53
|
+
return if value.blank?
|
54
|
+
|
55
|
+
actor = find_or_create_actor_with_account(value, "Group")
|
56
|
+
super(actor) if actor.present?
|
57
|
+
end
|
58
|
+
|
59
|
+
# Set the statement_ref value if provided.
|
60
|
+
# RailsXapi::Context needs a setter to save the "statement" data. However, it also
|
61
|
+
# belongs to a RailsXapi::Statement. Therefore, we use the attribute :statement_ref.
|
62
|
+
def statement=(value)
|
63
|
+
return unless value.is_a?(Hash) && value[:objectType] == "StatementRef"
|
64
|
+
|
65
|
+
id = value[:id]
|
66
|
+
return if id.nil?
|
67
|
+
|
68
|
+
statement_row = RailsXapi::Statement.find_by(id: id)
|
69
|
+
self[:statement_ref] = statement_row.id if statement_row&.id.present?
|
70
|
+
end
|
71
|
+
|
72
|
+
def extensions=(extensions_data)
|
73
|
+
unless extensions_data.is_a?(Hash)
|
74
|
+
raise RailsXapi::Errors::XapiError,
|
75
|
+
I18n.t(
|
76
|
+
"rails_xapi.errors.attribute_must_be_a_hash",
|
77
|
+
name: "extensions"
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
extensions_data.each do |iri, data|
|
82
|
+
extensions.build(iri: iri, value: serialized_value(data))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def as_json
|
87
|
+
context_attributes = {}
|
88
|
+
context_attributes[:registration] = registration if registration.present?
|
89
|
+
context_attributes[:instructor] = instructor if instructor.present?
|
90
|
+
context_attributes[:team] = team if team.present?
|
91
|
+
|
92
|
+
if context_activities.present?
|
93
|
+
grouped = context_activities.group_by(&:activity_type)
|
94
|
+
# convert string keys to symbols
|
95
|
+
context_attributes[:contextActivities] = grouped
|
96
|
+
.transform_keys(&:to_sym)
|
97
|
+
.transform_values { |activities| activities.map(&:as_json) }
|
98
|
+
end
|
99
|
+
|
100
|
+
context_attributes[
|
101
|
+
:statement
|
102
|
+
] = statement_ref.id if statement_ref&.id.present?
|
103
|
+
|
104
|
+
context_attributes
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def find_or_create_actor_with_account(value, object_type = nil)
|
110
|
+
home_page = value.dig(:account, :homePage)
|
111
|
+
existing_account =
|
112
|
+
RailsXapi::Account.find_by(home_page: home_page) if home_page.present?
|
113
|
+
|
114
|
+
# Set the params to search an existing row.
|
115
|
+
actor_params = {
|
116
|
+
mbox: value[:mbox],
|
117
|
+
mbox_sha1sum: value[:mbox_sha1sum],
|
118
|
+
openid: value[:openid]
|
119
|
+
}
|
120
|
+
actor_params[:account] = existing_account if existing_account.present?
|
121
|
+
|
122
|
+
RailsXapi::Actor.find_or_create_by(actor_params) do |actor|
|
123
|
+
actor.name = value[:name] if value[:name].present?
|
124
|
+
actor.object_type = object_type if object_type.present?
|
125
|
+
actor.account = RailsXapi::Account.new(value[:account]) if value[
|
126
|
+
:account
|
127
|
+
].present?
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# The "platform" property MUST only be used if the Statement's Object is an Activity.
|
132
|
+
# See: https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#requirements-10
|
133
|
+
def validate_platform
|
134
|
+
ref_statement =
|
135
|
+
statement_ref ? RailsXapi::Statement.find_by(id: statement_ref) : nil
|
136
|
+
|
137
|
+
ref_statement ||= statement_ref
|
138
|
+
|
139
|
+
self[:platform] = nil if !ref_statement&.object&.activity?
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# == Schema Information
|
144
|
+
#
|
145
|
+
# Table name: rails_xapi_contexts
|
146
|
+
#
|
147
|
+
# id :integer not null, primary key
|
148
|
+
# language :string
|
149
|
+
# platform :string
|
150
|
+
# registration :string
|
151
|
+
# revision :string
|
152
|
+
# statement_ref :bigint
|
153
|
+
# instructor_id :bigint
|
154
|
+
# statement_id :bigint not null
|
155
|
+
# team_id :bigint
|
156
|
+
#
|
157
|
+
# Indexes
|
158
|
+
#
|
159
|
+
# index_rails_xapi_contexts_on_instructor_id (instructor_id)
|
160
|
+
# index_rails_xapi_contexts_on_statement_id (statement_id)
|
161
|
+
# index_rails_xapi_contexts_on_statement_ref (statement_ref)
|
162
|
+
# index_rails_xapi_contexts_on_team_id (team_id)
|
163
|
+
#
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The optional context activity.
|
4
|
+
# See: https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#246-context
|
5
|
+
class RailsXapi::ContextActivity < ApplicationRecord
|
6
|
+
belongs_to :context, class_name: "RailsXapi::Context"
|
7
|
+
belongs_to :object, class_name: "RailsXapi::Object"
|
8
|
+
|
9
|
+
validates :activity_type,
|
10
|
+
presence: true,
|
11
|
+
inclusion: {
|
12
|
+
in: %w[parent grouping category other]
|
13
|
+
}
|
14
|
+
|
15
|
+
def as_json
|
16
|
+
{ id: object_id, objectType: object&.object_type }.tap do |hash|
|
17
|
+
hash[
|
18
|
+
:definition
|
19
|
+
] = object&.definition&.as_json if object&.definition.present?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# == Schema Information
|
25
|
+
#
|
26
|
+
# Table name: rails_xapi_context_activities
|
27
|
+
#
|
28
|
+
# id :integer not null, primary key
|
29
|
+
# activity_type :string not null
|
30
|
+
# context_id :bigint not null
|
31
|
+
# object_id :string not null
|
32
|
+
#
|
33
|
+
# Indexes
|
34
|
+
#
|
35
|
+
# index_rails_xapi_context_activities_on_context_id (context_id)
|
36
|
+
# index_rails_xapi_context_activities_on_object_id (object_id)
|
37
|
+
#
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The object optional activity definition's extensions.
|
4
|
+
# See: https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#41-extensions
|
5
|
+
class RailsXapi::Extension < ApplicationRecord
|
6
|
+
belongs_to :extendable, polymorphic: true
|
7
|
+
|
8
|
+
validates :iri, presence: true
|
9
|
+
validates :value, presence: true
|
10
|
+
|
11
|
+
def as_json
|
12
|
+
{ iri => value }.compact
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# == Schema Information
|
17
|
+
#
|
18
|
+
# Table name: rails_xapi_extensions
|
19
|
+
#
|
20
|
+
# id :integer not null, primary key
|
21
|
+
# extendable_type :string
|
22
|
+
# iri :string not null
|
23
|
+
# value :text not null
|
24
|
+
# extendable_id :integer
|
25
|
+
#
|
26
|
+
# Indexes
|
27
|
+
#
|
28
|
+
# index_rails_xapi_extensions_on_extendable (extendable_type,extendable_id)
|
29
|
+
#
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class RailsXapi::GroupMember < ApplicationRecord
|
4
|
+
belongs_to :group, class_name: "RailsXapi::Actor", dependent: :destroy
|
5
|
+
belongs_to :actor, class_name: "RailsXapi::Actor", dependent: :destroy
|
6
|
+
end
|
7
|
+
|
8
|
+
# == Schema Information
|
9
|
+
#
|
10
|
+
# Table name: rails_xapi_group_members
|
11
|
+
#
|
12
|
+
# id :integer not null, primary key
|
13
|
+
# created_at :datetime not null
|
14
|
+
# actor_id :bigint not null
|
15
|
+
# group_id :bigint not null
|
16
|
+
#
|
17
|
+
# Indexes
|
18
|
+
#
|
19
|
+
# index_rails_xapi_group_members_on_actor_id (actor_id)
|
20
|
+
# index_rails_xapi_group_members_on_group_id (group_id)
|
21
|
+
#
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The optional structure for interactions or assessments.
|
4
|
+
# See: https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#interaction-activities
|
5
|
+
class RailsXapi::InteractionActivity < ApplicationRecord
|
6
|
+
belongs_to :activity_definition, class_name: "RailsXapi::ActivityDefinition"
|
7
|
+
has_many :interaction_components,
|
8
|
+
foreign_key: :interaction_activity_id,
|
9
|
+
dependent: :destroy
|
10
|
+
|
11
|
+
INTERACTION_COMPONENT_TYPES = %w[scale choices source target steps]
|
12
|
+
INTERACTION_KEYS =
|
13
|
+
%w[interactionType correctResponsesPattern] + INTERACTION_COMPONENT_TYPES
|
14
|
+
|
15
|
+
validates :interaction_type,
|
16
|
+
presence: true,
|
17
|
+
inclusion: {
|
18
|
+
in: %w[
|
19
|
+
true-false
|
20
|
+
choice
|
21
|
+
fill-in
|
22
|
+
long-fill-in
|
23
|
+
matching
|
24
|
+
performance
|
25
|
+
sequencing
|
26
|
+
likert
|
27
|
+
numeric
|
28
|
+
other
|
29
|
+
]
|
30
|
+
}
|
31
|
+
|
32
|
+
attribute :correct_responses_pattern, :string, default: -> { [].to_json }
|
33
|
+
|
34
|
+
def assign_interaction_components(interaction_attrs)
|
35
|
+
return unless interaction_attrs.present?
|
36
|
+
|
37
|
+
interaction_components.where(
|
38
|
+
component_type: INTERACTION_COMPONENT_TYPES
|
39
|
+
).destroy_all
|
40
|
+
|
41
|
+
INTERACTION_COMPONENT_TYPES.each do |component_type|
|
42
|
+
Array(interaction_attrs[component_type]).each do |data|
|
43
|
+
interaction_components.build(
|
44
|
+
component_type: component_type,
|
45
|
+
component_id: data["id"],
|
46
|
+
description: data["description"].to_json,
|
47
|
+
interaction_activity: self
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def correct_responses_pattern
|
54
|
+
JSON.parse(super || "[]")
|
55
|
+
end
|
56
|
+
|
57
|
+
def correct_responses_pattern=(value)
|
58
|
+
super(value.to_json)
|
59
|
+
end
|
60
|
+
|
61
|
+
def components_by_interaction_type
|
62
|
+
case interaction_type
|
63
|
+
when "likert"
|
64
|
+
{ "scale" => component_hash }
|
65
|
+
when "choice"
|
66
|
+
{ "choice" => component_hash }
|
67
|
+
else
|
68
|
+
{}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def as_json
|
73
|
+
{
|
74
|
+
interactionType: interaction_type,
|
75
|
+
correctResponsesPattern: correct_responses_pattern
|
76
|
+
}.merge(components_by_interaction_type)
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def component_hash
|
82
|
+
interaction_components.map do |component|
|
83
|
+
{
|
84
|
+
"id" => component.component_id,
|
85
|
+
"description" => component.parsed_description
|
86
|
+
}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# == Schema Information
|
92
|
+
#
|
93
|
+
# Table name: rails_xapi_interaction_activities
|
94
|
+
#
|
95
|
+
# id :integer not null, primary key
|
96
|
+
# correct_responses_pattern :text
|
97
|
+
# interaction_type :string not null
|
98
|
+
# activity_definition_id :bigint not null
|
99
|
+
#
|
100
|
+
# Indexes
|
101
|
+
#
|
102
|
+
# idx_on_activity_definition_id_0cc615114b (activity_definition_id)
|
103
|
+
#
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The optional structure for interactions or assessments.
|
4
|
+
# See: https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#interaction-components
|
5
|
+
class RailsXapi::InteractionComponent < ApplicationRecord
|
6
|
+
belongs_to :interaction_activity, class_name: "RailsXapi::InteractionActivity"
|
7
|
+
|
8
|
+
validates_with RailsXapi::Validators::LanguageMapValidator,
|
9
|
+
attributes: %i[description]
|
10
|
+
|
11
|
+
def parsed_description
|
12
|
+
return {} unless description.present?
|
13
|
+
begin
|
14
|
+
JSON.parse(description)
|
15
|
+
rescue StandardError
|
16
|
+
{}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# == Schema Information
|
22
|
+
#
|
23
|
+
# Table name: rails_xapi_interaction_components
|
24
|
+
#
|
25
|
+
# id :integer not null, primary key
|
26
|
+
# component_type :string not null
|
27
|
+
# description :text
|
28
|
+
# component_id :string not null
|
29
|
+
# interaction_activity_id :bigint not null
|
30
|
+
#
|
31
|
+
# Indexes
|
32
|
+
#
|
33
|
+
# idx_on_interaction_activity_id_863e21bede (interaction_activity_id)
|
34
|
+
#
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The Object defines the thing that was acted on.
|
4
|
+
# See: https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#244-object
|
5
|
+
# The Object of a Statement can be an Activity, Agent/Group, SubStatement, or Statement Reference.
|
6
|
+
class RailsXapi::Object < ApplicationRecord
|
7
|
+
OBJECT_TYPES = %w[Activity Agent Group SubStatement StatementRef]
|
8
|
+
|
9
|
+
attr_accessor :objectType,
|
10
|
+
:actor,
|
11
|
+
:verb,
|
12
|
+
:object,
|
13
|
+
:result,
|
14
|
+
:context,
|
15
|
+
:timestamp
|
16
|
+
|
17
|
+
has_one :definition,
|
18
|
+
class_name: "RailsXapi::ActivityDefinition",
|
19
|
+
dependent: :destroy
|
20
|
+
has_many :statements, class_name: "RailsXapi::Statement", dependent: :nullify
|
21
|
+
belongs_to :statement, class_name: "RailsXapi::Statement", optional: true
|
22
|
+
|
23
|
+
validates :id, presence: true
|
24
|
+
validates :object_type, presence: true, inclusion: { in: OBJECT_TYPES }
|
25
|
+
validates :statement, presence: true, if: -> { object_type == "SubStatement" }
|
26
|
+
validates :actor, presence: true, if: -> { object_type == "SubStatement" }
|
27
|
+
validates :object, presence: true, if: -> { object_type == "SubStatement" }
|
28
|
+
validates :verb, presence: true, if: -> { object_type == "SubStatement" }
|
29
|
+
|
30
|
+
before_validation :set_defaults, :create_statement_for_substatement
|
31
|
+
|
32
|
+
accepts_nested_attributes_for :definition
|
33
|
+
|
34
|
+
def definition=(definition_hash)
|
35
|
+
return unless definition_hash.present?
|
36
|
+
|
37
|
+
# Build or create the associated object.
|
38
|
+
build_definition if definition.nil?
|
39
|
+
definition.assign_from_json_definition(definition_hash)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Find an Object by its id or create a new one.
|
43
|
+
#
|
44
|
+
# @param [Hash] attributes The attributes of the requested object.
|
45
|
+
# @return [RailsXapi::Object] The found or created object.
|
46
|
+
def self.find_or_create(attributes)
|
47
|
+
find_by(id: attributes[:id]) || create(attributes)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Update the ActivityDefinition if it's existing.
|
51
|
+
def update_definition(definition_data)
|
52
|
+
return unless definition_data.present?
|
53
|
+
|
54
|
+
definition = self.definition || create_definition
|
55
|
+
definition.assign_from_json_definition(definition_data)
|
56
|
+
definition.save!
|
57
|
+
end
|
58
|
+
|
59
|
+
def activity?
|
60
|
+
return true if object_type == "Activity"
|
61
|
+
|
62
|
+
false
|
63
|
+
end
|
64
|
+
|
65
|
+
def as_json
|
66
|
+
{ id: id, objectType: object_type }.tap do |hash|
|
67
|
+
hash[:definition] = definition.as_json if definition.present?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def set_defaults
|
74
|
+
self.object_type ||= objectType.presence || "Activity"
|
75
|
+
|
76
|
+
if new_record? && object_type == "SubStatement"
|
77
|
+
self.actor = actor
|
78
|
+
self.verb = verb
|
79
|
+
self.object = object
|
80
|
+
self.result = result
|
81
|
+
self.context = context
|
82
|
+
self.timestamp = timestamp
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_statement_for_substatement
|
87
|
+
return unless object_type == "SubStatement" && statement.nil?
|
88
|
+
|
89
|
+
# Generate a random primary key in place of the object ID
|
90
|
+
self.id = Digest::SHA1.hexdigest([Time.zone.now, rand(111..999)].join)
|
91
|
+
|
92
|
+
# Then, create the substatement
|
93
|
+
substatement_actor = create_or_find_actor
|
94
|
+
substatement_verb = create_or_find_verb
|
95
|
+
substatement_object = create_or_find_object
|
96
|
+
substatement_result = create_result
|
97
|
+
substatement_context = create_context
|
98
|
+
|
99
|
+
self.statement =
|
100
|
+
RailsXapi::Statement.create!(
|
101
|
+
actor: substatement_actor,
|
102
|
+
verb: substatement_verb,
|
103
|
+
object: substatement_object,
|
104
|
+
result: substatement_result,
|
105
|
+
context: substatement_context,
|
106
|
+
timestamp: timestamp
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_or_find_actor
|
111
|
+
if actor.blank?
|
112
|
+
raise RailsXapi::Errors::XapiError,
|
113
|
+
I18n.t("rails_xapi.errors.missing_actor")
|
114
|
+
end
|
115
|
+
|
116
|
+
RailsXapi::Actor.by_iri_or_create(actor)
|
117
|
+
end
|
118
|
+
|
119
|
+
def create_or_find_verb
|
120
|
+
RailsXapi::Verb.find_or_create_by(id: verb[:id]) { |v| v.attributes = verb }
|
121
|
+
end
|
122
|
+
|
123
|
+
def create_or_find_object
|
124
|
+
RailsXapi::Object.find_or_create_by(id: object[:id]) do |o|
|
125
|
+
o.attributes = object
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def create_result
|
130
|
+
RailsXapi::Result.new(result) if result.present?
|
131
|
+
end
|
132
|
+
|
133
|
+
def create_context
|
134
|
+
RailsXapi::Context.new(context)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# == Schema Information
|
139
|
+
#
|
140
|
+
# Table name: rails_xapi_objects
|
141
|
+
#
|
142
|
+
# id :string not null, primary key
|
143
|
+
# object_type :string not null
|
144
|
+
# statement_id :bigint
|
145
|
+
#
|
146
|
+
# Indexes
|
147
|
+
#
|
148
|
+
# index_rails_xapi_objects_on_id (id) UNIQUE
|
149
|
+
# index_rails_xapi_objects_on_statement_id (statement_id)
|
150
|
+
#
|