Add relation between Goal and LocalTarget

This is similar to what we do with investments, which belong to a heading
but also belong to a budget. In our case, the reason is we've been asked
to add local targets which belong to a goal but are not related to any
existing target.
Even though we're not implementing that case right now, we're adding the
relation so we don't have to add data migrations in the future.
This commit is contained in:
taitus
2021-01-23 13:45:36 +01:00
parent cb57a4696d
commit 0a3de68206
6 changed files with 28 additions and 4 deletions

View File

@@ -4,6 +4,7 @@ class SDG::Goal < ApplicationRecord
validates :code, presence: true, uniqueness: true, inclusion: { in: 1..17 } validates :code, presence: true, uniqueness: true, inclusion: { in: 1..17 }
has_many :targets, dependent: :destroy has_many :targets, dependent: :destroy
has_many :local_targets, dependent: :destroy
def title def title
I18n.t("sdg.goals.goal_#{code}.title") I18n.t("sdg.goals.goal_#{code}.title")

View File

@@ -2,8 +2,6 @@ class SDG::LocalTarget < ApplicationRecord
include Comparable include Comparable
include SDG::Related include SDG::Related
delegate :goal, to: :target
translates :title, touch: true translates :title, touch: true
translates :description, touch: true translates :description, touch: true
include Globalizable include Globalizable
@@ -14,8 +12,12 @@ class SDG::LocalTarget < ApplicationRecord
validates :code, presence: true, uniqueness: true, validates :code, presence: true, uniqueness: true,
format: ->(local_target) { /\A#{local_target.target&.code}\.\d+/ } format: ->(local_target) { /\A#{local_target.target&.code}\.\d+/ }
validates :target, presence: true validates :target, presence: true
validates :goal, presence: true
belongs_to :target belongs_to :target
belongs_to :goal
before_validation :set_related_goal
def self.[](code) def self.[](code)
find_by!(code: code) find_by!(code: code)
@@ -40,4 +42,8 @@ class SDG::LocalTarget < ApplicationRecord
def subcode def subcode
code.split(".").last code.split(".").last
end end
def set_related_goal
self.goal ||= target&.goal
end
end end

View File

@@ -0,0 +1,5 @@
class AddGoalsToLocalTargets < ActiveRecord::Migration[5.2]
def change
add_reference :sdg_local_targets, :goal
end
end

View File

@@ -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: 2021_01_07_125458) do ActiveRecord::Schema.define(version: 2021_01_23_100638) 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 "pg_trgm" enable_extension "pg_trgm"
@@ -1322,7 +1322,9 @@ ActiveRecord::Schema.define(version: 2021_01_07_125458) do
t.string "code" t.string "code"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.bigint "goal_id"
t.index ["code"], name: "index_sdg_local_targets_on_code", unique: true t.index ["code"], name: "index_sdg_local_targets_on_code", unique: true
t.index ["goal_id"], name: "index_sdg_local_targets_on_goal_id"
t.index ["target_id"], name: "index_sdg_local_targets_on_target_id" t.index ["target_id"], name: "index_sdg_local_targets_on_target_id"
end end

View File

@@ -13,6 +13,7 @@ FactoryBot.define do
sequence(:description) { |n| "Help for Local Target #{n}" } sequence(:description) { |n| "Help for Local Target #{n}" }
target { SDG::Target[code.rpartition(".").first] } target { SDG::Target[code.rpartition(".").first] }
goal { SDG::Goal[code.split(".")[0]] }
end end
factory :sdg_phase, class: "SDG::Phase" do factory :sdg_phase, class: "SDG::Phase" do

View File

@@ -18,7 +18,7 @@ describe SDG::LocalTarget do
end end
it "is not valid without a code" do it "is not valid without a code" do
expect(build(:sdg_local_target, code: nil, target: SDG::Target[1.1])).not_to be_valid expect(build(:sdg_local_target, code: nil, target: SDG::Target[1.1], goal: SDG::Goal[1])).not_to be_valid
end end
it "is not valid when code does not include associated target code" do it "is not valid when code does not include associated target code" do
@@ -47,6 +47,15 @@ describe SDG::LocalTarget do
expect(build(:sdg_local_target, target: nil)).not_to be_valid expect(build(:sdg_local_target, target: nil)).not_to be_valid
end end
describe "#set_related_goal" do
it "before validation set related goal" do
local_target = build(:sdg_local_target, code: "1.1.1", target: SDG::Target["1.1"], goal: nil)
expect(local_target).to be_valid
expect(local_target.goal).to eq(SDG::Goal[1])
end
end
describe "#goal" do describe "#goal" do
it "returns the target goal" do it "returns the target goal" do
local_target = create(:sdg_local_target, code: "1.1.1") local_target = create(:sdg_local_target, code: "1.1.1")