Add database support and model for tips
This commit is contained in:
@ -24,6 +24,8 @@ class Exercise < ApplicationRecord
|
|||||||
has_many :tags, through: :exercise_tags
|
has_many :tags, through: :exercise_tags
|
||||||
accepts_nested_attributes_for :exercise_tags
|
accepts_nested_attributes_for :exercise_tags
|
||||||
has_many :user_exercise_feedbacks
|
has_many :user_exercise_feedbacks
|
||||||
|
has_many :exercise_tips
|
||||||
|
has_many :tips, through: :exercise_tips
|
||||||
|
|
||||||
has_many :external_users, source: :user, source_type: 'ExternalUser', through: :submissions
|
has_many :external_users, source: :user, source_type: 'ExternalUser', through: :submissions
|
||||||
has_many :internal_users, source: :user, source_type: 'InternalUser', through: :submissions
|
has_many :internal_users, source: :user, source_type: 'InternalUser', through: :submissions
|
||||||
|
18
app/models/exercise_tip.rb
Normal file
18
app/models/exercise_tip.rb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ExerciseTip < ApplicationRecord
|
||||||
|
belongs_to :exercise
|
||||||
|
belongs_to :tip
|
||||||
|
belongs_to :parent_exercise_tip, class_name: 'ExerciseTip', optional: true
|
||||||
|
attr_accessor :children
|
||||||
|
|
||||||
|
# Ensure no parent tip is set if current tip has rank == 1
|
||||||
|
validates :rank, exclusion: {in: [1]}, if: :parent_exercise_tip_id?
|
||||||
|
|
||||||
|
validate :tip_chain?, if: :parent_exercise_tip_id?
|
||||||
|
|
||||||
|
def tip_chain?
|
||||||
|
# Ensure each referenced parent exercise tip is set for this exercise
|
||||||
|
errors.add :parent_exercise_tip, I18n.t('activerecord.errors.messages.together', attribute: I18n.t('activerecord.attributes.exercise_tip.tip')) unless ExerciseTip.exists?(exercise: exercise, tip: parent_exercise_tip)
|
||||||
|
end
|
||||||
|
end
|
23
app/models/tip.rb
Normal file
23
app/models/tip.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Tip < ApplicationRecord
|
||||||
|
include Creation
|
||||||
|
|
||||||
|
has_many :exercise_tips
|
||||||
|
has_many :exercises, through: :exercise_tips
|
||||||
|
belongs_to :file_type, optional: true
|
||||||
|
validates_presence_of :file_type, if: :example?
|
||||||
|
validate :content?
|
||||||
|
|
||||||
|
def content?
|
||||||
|
errors.add :description, I18n.t('activerecord.errors.messages.at_least', attribute: I18n.t('activerecord.attributes.tip.example')) unless [description?, example?].include?(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
if title?
|
||||||
|
"#{I18n.t('activerecord.models.tip.one')}: #{title} (#{id})"
|
||||||
|
else
|
||||||
|
"#{I18n.t('activerecord.models.tip.one')} #{id}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -121,6 +121,10 @@ de:
|
|||||||
name: Name
|
name: Name
|
||||||
usage: Verwendet
|
usage: Verwendet
|
||||||
difficulty: Anteil an der Aufgabe
|
difficulty: Anteil an der Aufgabe
|
||||||
|
tip:
|
||||||
|
title: Titel
|
||||||
|
description: Beschreibung
|
||||||
|
example: Beispiel
|
||||||
file_template:
|
file_template:
|
||||||
name: "Name"
|
name: "Name"
|
||||||
file_type: "Dateityp"
|
file_type: "Dateityp"
|
||||||
@ -215,6 +219,7 @@ de:
|
|||||||
errors:
|
errors:
|
||||||
messages:
|
messages:
|
||||||
together: 'muss zusammen mit %{attribute} definiert werden'
|
together: 'muss zusammen mit %{attribute} definiert werden'
|
||||||
|
at_least: 'oder %{attribute} muss definiert sein'
|
||||||
models:
|
models:
|
||||||
exercise:
|
exercise:
|
||||||
at_most_one_main_file: dürfen höchstens eine Hauptdatei enthalten
|
at_most_one_main_file: dürfen höchstens eine Hauptdatei enthalten
|
||||||
|
@ -121,6 +121,10 @@ en:
|
|||||||
name: Name
|
name: Name
|
||||||
usage: Used
|
usage: Used
|
||||||
difficulty: Share on the Exercise
|
difficulty: Share on the Exercise
|
||||||
|
tip:
|
||||||
|
title: title
|
||||||
|
description: description
|
||||||
|
example: example
|
||||||
file_template:
|
file_template:
|
||||||
name: "Name"
|
name: "Name"
|
||||||
file_type: "File Type"
|
file_type: "File Type"
|
||||||
@ -215,6 +219,7 @@ en:
|
|||||||
errors:
|
errors:
|
||||||
messages:
|
messages:
|
||||||
together: 'has to be set along with %{attribute}'
|
together: 'has to be set along with %{attribute}'
|
||||||
|
at_least: 'or %{attribute} must be defined'
|
||||||
models:
|
models:
|
||||||
exercise:
|
exercise:
|
||||||
at_most_one_main_file: must include at most one main file
|
at_most_one_main_file: must include at most one main file
|
||||||
|
22
db/migrate/20201007104221_create_tips.rb
Normal file
22
db/migrate/20201007104221_create_tips.rb
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CreateTips < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
create_table :tips do |t|
|
||||||
|
t.string :title
|
||||||
|
t.text :description
|
||||||
|
t.text :example
|
||||||
|
t.references :file_type, foreign_key: true
|
||||||
|
t.references :user, polymorphic: true, null: false
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :exercise_tips do |t|
|
||||||
|
t.references :exercise, null: false
|
||||||
|
t.references :tip, null: false
|
||||||
|
t.integer :rank, null: false
|
||||||
|
t.references :parent_exercise_tip, foreign_key: {to_table: :exercise_tips}
|
||||||
|
t.index %i[exercise_id tip_id rank], unique: true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
27
db/schema.rb
27
db/schema.rb
@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2020_05_06_093054) do
|
ActiveRecord::Schema.define(version: 2020_10_07_104221) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@ -137,6 +137,17 @@ ActiveRecord::Schema.define(version: 2020_05_06_093054) do
|
|||||||
t.integer "factor", default: 1
|
t.integer "factor", default: 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "exercise_tips", force: :cascade do |t|
|
||||||
|
t.bigint "exercise_id", null: false
|
||||||
|
t.bigint "tip_id", null: false
|
||||||
|
t.integer "rank", null: false
|
||||||
|
t.bigint "parent_exercise_tip_id"
|
||||||
|
t.index ["exercise_id", "tip_id", "rank"], name: "index_exercise_tips_on_exercise_id_and_tip_id_and_rank", unique: true
|
||||||
|
t.index ["exercise_id"], name: "index_exercise_tips_on_exercise_id"
|
||||||
|
t.index ["parent_exercise_tip_id"], name: "index_exercise_tips_on_parent_exercise_tip_id"
|
||||||
|
t.index ["tip_id"], name: "index_exercise_tips_on_tip_id"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "exercises", id: :serial, force: :cascade do |t|
|
create_table "exercises", id: :serial, force: :cascade do |t|
|
||||||
t.text "description"
|
t.text "description"
|
||||||
t.integer "execution_environment_id"
|
t.integer "execution_environment_id"
|
||||||
@ -389,6 +400,19 @@ ActiveRecord::Schema.define(version: 2020_05_06_093054) do
|
|||||||
t.index ["submission_id"], name: "index_testruns_on_submission_id"
|
t.index ["submission_id"], name: "index_testruns_on_submission_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "tips", force: :cascade do |t|
|
||||||
|
t.string "title"
|
||||||
|
t.text "description"
|
||||||
|
t.text "example"
|
||||||
|
t.bigint "file_type_id"
|
||||||
|
t.string "user_type", null: false
|
||||||
|
t.bigint "user_id", null: false
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["file_type_id"], name: "index_tips_on_file_type_id"
|
||||||
|
t.index ["user_type", "user_id"], name: "index_tips_on_user_type_and_user_id"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "user_exercise_feedbacks", id: :serial, force: :cascade do |t|
|
create_table "user_exercise_feedbacks", id: :serial, force: :cascade do |t|
|
||||||
t.integer "exercise_id", null: false
|
t.integer "exercise_id", null: false
|
||||||
t.integer "user_id", null: false
|
t.integer "user_id", null: false
|
||||||
@ -427,4 +451,5 @@ ActiveRecord::Schema.define(version: 2020_05_06_093054) do
|
|||||||
|
|
||||||
add_foreign_key "request_for_comments", "submissions", name: "request_for_comments_submissions_id_fk"
|
add_foreign_key "request_for_comments", "submissions", name: "request_for_comments_submissions_id_fk"
|
||||||
add_foreign_key "submissions", "study_groups"
|
add_foreign_key "submissions", "study_groups"
|
||||||
|
add_foreign_key "tips", "file_types"
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user