Merge pull request #2641 from betagouv/frederic/type_de_champ_sti
[#1421] Use delegation rather than STI for TypeDeChamp
This commit is contained in:
commit
3445d0b3f7
26 changed files with 82 additions and 65 deletions
|
@ -1,5 +1,5 @@
|
|||
class Champs::LinkedDropDownListChamp < Champ
|
||||
delegate :primary_options, :secondary_options, to: :type_de_champ
|
||||
delegate :primary_options, :secondary_options, to: 'type_de_champ.dynamic_type'
|
||||
|
||||
def primary_value
|
||||
if value.present?
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
class TypeDeChamp < ApplicationRecord
|
||||
# TODO drop next line when `type` column has been dropped from `types_de_champ` table
|
||||
self.inheritance_column = nil
|
||||
|
||||
enum type_champs: {
|
||||
text: 'text',
|
||||
textarea: 'textarea',
|
||||
|
@ -27,6 +30,10 @@ class TypeDeChamp < ApplicationRecord
|
|||
|
||||
belongs_to :procedure
|
||||
|
||||
after_initialize :set_dynamic_type
|
||||
|
||||
attr_reader :dynamic_type
|
||||
|
||||
scope :public_only, -> { where(private: false) }
|
||||
scope :private_only, -> { where(private: true) }
|
||||
scope :ordered, -> { order(order_place: :asc) }
|
||||
|
@ -52,6 +59,15 @@ class TypeDeChamp < ApplicationRecord
|
|||
before_validation :check_mandatory
|
||||
before_save :remove_piece_justificative_template, if: -> { type_champ_changed? }
|
||||
|
||||
def set_dynamic_type
|
||||
@dynamic_type = type_champ.present? ? self.class.type_champ_to_class_name(type_champ).constantize.new(self) : nil
|
||||
end
|
||||
|
||||
def type_champ=(value)
|
||||
super(value)
|
||||
set_dynamic_type
|
||||
end
|
||||
|
||||
def params_for_champ
|
||||
{
|
||||
private: private?,
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
class TypesDeChamp::CheckboxTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::CheckboxTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
class TypesDeChamp::CiviliteTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::CiviliteTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
class TypesDeChamp::DateTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::DateTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
class TypesDeChamp::DatetimeTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::DatetimeTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
class TypesDeChamp::DossierLinkTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::DossierLinkTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
class TypesDeChamp::DropDownListTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::DropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
class TypesDeChamp::HeaderSectionTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::HeaderSectionTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
PRIMARY_PATTERN = /^--(.*)--$/
|
||||
|
||||
delegate :drop_down_list, to: :@type_de_champ
|
||||
|
||||
def primary_options
|
||||
primary_options = unpack_options.map(&:first)
|
||||
if primary_options.present?
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
class TypesDeChamp::MultipleDropDownListTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::MultipleDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
class TypesDeChamp::NumberTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::NumberTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
class TypesDeChamp::PieceJustificativeTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::PieceJustificativeTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
class TypesDeChamp::SiretTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::SiretTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
class TypesDeChamp::TextTypeDeChamp < TypeDeChamp
|
||||
class TypesDeChamp::TextTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
end
|
||||
|
|
5
app/models/types_de_champ/type_de_champ_base.rb
Normal file
5
app/models/types_de_champ/type_de_champ_base.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class TypesDeChamp::TypeDeChampBase
|
||||
def initialize(type_de_champ)
|
||||
@type_de_champ = type_de_champ
|
||||
end
|
||||
end
|
|
@ -19,10 +19,6 @@ class TypesDeChampService
|
|||
|
||||
parameters[attributes].each do |index, param|
|
||||
param[:private] = private
|
||||
if param[:type_champ]
|
||||
param[:type] = TypeDeChamp.type_champ_to_class_name(param[:type_champ])
|
||||
end
|
||||
|
||||
if param[:libelle].empty?
|
||||
parameters[attributes].delete(index.to_s)
|
||||
end
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
|
||||
.form-group
|
||||
= ff.hidden_field :order_place, value: ff.index
|
||||
= ff.hidden_field :type
|
||||
= ff.hidden_field :id
|
||||
|
||||
- if ff.object.id.present?
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace :'2018_05_14_add_annotation_privee_to_procedure' do
|
|||
tdc.update_attribute(:order_place, tdc.order_place + 1)
|
||||
end
|
||||
|
||||
new_tdc = TypesDeChamp::TextTypeDeChamp.create(
|
||||
new_tdc = TypeDeChamp.create(
|
||||
procedure_id: procedure_id,
|
||||
private: true,
|
||||
libelle: 'URL Espace de consultation',
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace :'2018_07_31_nutriscore' do
|
|||
end
|
||||
|
||||
discard_source_champ(
|
||||
TypesDeChamp::TextTypeDeChamp.new(
|
||||
TypeDeChamp.new(
|
||||
type_champ: 'text',
|
||||
order_place: siret_order_place,
|
||||
libelle: 'Numéro SIRET'
|
||||
|
@ -42,7 +42,7 @@ namespace :'2018_07_31_nutriscore' do
|
|||
)
|
||||
|
||||
discard_source_champ(
|
||||
TypesDeChamp::TextTypeDeChamp.new(
|
||||
TypeDeChamp.new(
|
||||
type_champ: 'text',
|
||||
order_place: fonction_order_place,
|
||||
libelle: 'Fonction'
|
||||
|
@ -50,7 +50,7 @@ namespace :'2018_07_31_nutriscore' do
|
|||
)
|
||||
|
||||
compute_destination_champ(
|
||||
TypesDeChamp::TextTypeDeChamp.new(
|
||||
TypeDeChamp.new(
|
||||
type_champ: 'text',
|
||||
order_place: fonction_order_place,
|
||||
libelle: 'Fonction',
|
||||
|
@ -66,7 +66,7 @@ namespace :'2018_07_31_nutriscore' do
|
|||
end
|
||||
|
||||
compute_destination_champ(
|
||||
TypesDeChamp::SiretTypeDeChamp.new(
|
||||
TypeDeChamp.new(
|
||||
type_champ: 'siret',
|
||||
order_place: siret_order_place,
|
||||
libelle: 'Numéro SIRET'
|
||||
|
@ -80,7 +80,7 @@ namespace :'2018_07_31_nutriscore' do
|
|||
end
|
||||
|
||||
compute_destination_champ(
|
||||
TypesDeChamp::HeaderSectionTypeDeChamp.new(
|
||||
TypeDeChamp.new(
|
||||
type_champ: 'header_section',
|
||||
order_place: 18,
|
||||
libelle: 'PARTIE 3 : ZONE GEOGRAPHIQUE'
|
||||
|
@ -90,7 +90,7 @@ namespace :'2018_07_31_nutriscore' do
|
|||
end
|
||||
|
||||
compute_destination_champ(
|
||||
TypesDeChamp::MultipleDropDownListTypeDeChamp.new(
|
||||
TypeDeChamp.new(
|
||||
type_champ: 'multiple_drop_down_list',
|
||||
order_place: 19,
|
||||
libelle: 'Pays de commercialisation',
|
||||
|
|
|
@ -57,7 +57,7 @@ module Tasks
|
|||
|
||||
def type_de_champ_to_expectation(tdc)
|
||||
if tdc.present?
|
||||
expectation = tdc.as_json(only: [:libelle, :type, :type_champ, :mandatory])
|
||||
expectation = tdc.as_json(only: [:libelle, :type_champ, :mandatory])
|
||||
expectation['drop_down'] = tdc.drop_down_list.presence&.options&.presence
|
||||
expectation
|
||||
else
|
||||
|
@ -107,9 +107,6 @@ module Tasks
|
|||
if actual_tdc.libelle != expected_tdc['libelle']
|
||||
errors.append("incorrect libelle #{actual_tdc.libelle} (expected #{expected_tdc['libelle']})")
|
||||
end
|
||||
if actual_tdc.type != expected_tdc['type']
|
||||
errors.append("incorrect type #{actual_tdc.type} (expected #{expected_tdc['type']})")
|
||||
end
|
||||
if actual_tdc.type_champ != expected_tdc['type_champ']
|
||||
errors.append("incorrect type champ #{actual_tdc.type_champ} (expected #{expected_tdc['type_champ']})")
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
FactoryBot.define do
|
||||
factory :type_de_champ, class: 'TypesDeChamp::TextTypeDeChamp' do
|
||||
factory :type_de_champ do
|
||||
private { false }
|
||||
|
||||
# Previous line is kept blank so that rubocop does not complain
|
||||
|
@ -9,79 +9,79 @@ FactoryBot.define do
|
|||
order_place { 1 }
|
||||
mandatory { false }
|
||||
|
||||
factory :type_de_champ_text, class: 'TypesDeChamp::TextTypeDeChamp' do
|
||||
factory :type_de_champ_text do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:text) }
|
||||
end
|
||||
factory :type_de_champ_textarea, class: 'TypesDeChamp::TextareaTypeDeChamp' do
|
||||
factory :type_de_champ_textarea do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:textarea) }
|
||||
end
|
||||
factory :type_de_champ_number, class: 'TypesDeChamp::NumberTypeDeChamp' do
|
||||
factory :type_de_champ_number do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:number) }
|
||||
end
|
||||
factory :type_de_champ_checkbox, class: 'TypesDeChamp::CheckboxTypeDeChamp' do
|
||||
factory :type_de_champ_checkbox do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:checkbox) }
|
||||
end
|
||||
factory :type_de_champ_civilite, class: 'TypesDeChamp::CiviliteTypeDeChamp' do
|
||||
factory :type_de_champ_civilite do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:civilite) }
|
||||
end
|
||||
factory :type_de_champ_email, class: 'TypesDeChamp::EmailTypeDeChamp' do
|
||||
factory :type_de_champ_email do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:email) }
|
||||
end
|
||||
factory :type_de_champ_phone, class: 'TypesDeChamp::PhoneTypeDeChamp' do
|
||||
factory :type_de_champ_phone do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:phone) }
|
||||
end
|
||||
factory :type_de_champ_address, class: 'TypesDeChamp::AddressTypeDeChamp' do
|
||||
factory :type_de_champ_address do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:address) }
|
||||
end
|
||||
factory :type_de_champ_yes_no, class: 'TypesDeChamp::YesNoTypeDeChamp' do
|
||||
factory :type_de_champ_yes_no do
|
||||
libelle { 'Yes/no' }
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:yes_no) }
|
||||
end
|
||||
factory :type_de_champ_date, class: 'TypesDeChamp::DateTypeDeChamp' do
|
||||
factory :type_de_champ_date do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:date) }
|
||||
end
|
||||
factory :type_de_champ_datetime, class: 'TypesDeChamp::DatetimeTypeDeChamp' do
|
||||
factory :type_de_champ_datetime do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:datetime) }
|
||||
end
|
||||
factory :type_de_champ_drop_down_list, class: 'TypesDeChamp::DropDownListTypeDeChamp' do
|
||||
factory :type_de_champ_drop_down_list do
|
||||
libelle { 'Menu déroulant' }
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:drop_down_list) }
|
||||
drop_down_list { create(:drop_down_list) }
|
||||
end
|
||||
factory :type_de_champ_multiple_drop_down_list, class: 'TypesDeChamp::MultipleDropDownListTypeDeChamp' do
|
||||
factory :type_de_champ_multiple_drop_down_list do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:multiple_drop_down_list) }
|
||||
drop_down_list { create(:drop_down_list) }
|
||||
end
|
||||
factory :type_de_champ_linked_drop_down_list, class: 'TypesDeChamp::LinkedDropDownListTypeDeChamp' do
|
||||
factory :type_de_champ_linked_drop_down_list do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:linked_drop_down_list) }
|
||||
drop_down_list { create(:drop_down_list) }
|
||||
end
|
||||
factory :type_de_champ_pays, class: 'TypesDeChamp::PaysTypeDeChamp' do
|
||||
factory :type_de_champ_pays do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:pays) }
|
||||
end
|
||||
factory :type_de_champ_regions, class: 'TypesDeChamp::RegionTypeDeChamp' do
|
||||
factory :type_de_champ_regions do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:regions) }
|
||||
end
|
||||
factory :type_de_champ_departements, class: 'TypesDeChamp::DepartementTypeDeChamp' do
|
||||
factory :type_de_champ_departements do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:departements) }
|
||||
end
|
||||
factory :type_de_champ_engagement, class: 'TypesDeChamp::EngagementTypeDeChamp' do
|
||||
factory :type_de_champ_engagement do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:engagement) }
|
||||
end
|
||||
factory :type_de_champ_header_section, class: 'TypesDeChamp::HeaderSectionTypeDeChamp' do
|
||||
factory :type_de_champ_header_section do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:header_section) }
|
||||
end
|
||||
factory :type_de_champ_explication, class: 'TypesDeChamp::ExplicationTypeDeChamp' do
|
||||
factory :type_de_champ_explication do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:explication) }
|
||||
end
|
||||
factory :type_de_champ_dossier_link, class: 'TypesDeChamp::DossierLinkTypeDeChamp' do
|
||||
factory :type_de_champ_dossier_link do
|
||||
libelle { 'Référence autre dossier' }
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:dossier_link) }
|
||||
end
|
||||
factory :type_de_champ_piece_justificative, class: 'TypesDeChamp::PieceJustificativeTypeDeChamp' do
|
||||
factory :type_de_champ_piece_justificative do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:piece_justificative) }
|
||||
end
|
||||
factory :type_de_champ_siret, class: 'TypesDeChamp::SiretTypeDeChamp' do
|
||||
factory :type_de_champ_siret do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:siret) }
|
||||
end
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ describe '2018_05_14_add_annotation_privee_to_procedure' do
|
|||
let!(:procedure) do
|
||||
procedure = create(:procedure)
|
||||
10.times do |i|
|
||||
TypesDeChamp::NumberTypeDeChamp.create(
|
||||
TypeDeChamp.create(
|
||||
procedure: procedure,
|
||||
private: false,
|
||||
libelle: 'libelle',
|
||||
|
@ -11,7 +11,7 @@ describe '2018_05_14_add_annotation_privee_to_procedure' do
|
|||
type_champ: 'number'
|
||||
)
|
||||
|
||||
TypesDeChamp::NumberTypeDeChamp.create(
|
||||
TypeDeChamp.create(
|
||||
procedure: procedure,
|
||||
private: true,
|
||||
libelle: 'libelle',
|
||||
|
|
|
@ -95,7 +95,7 @@ describe '2018_07_31_nutriscore' do
|
|||
context 'with champ type mismatch' do
|
||||
let!(:type_champ_to) { create(:type_de_champ_text, order_place: 1, libelle: 'texte', procedure: proc_to) }
|
||||
|
||||
it { expect { run_task }.to raise_exception(/incorrect type TypesDeChamp::TextareaTypeDeChamp \(expected TypesDeChamp::TextTypeDeChamp\), incorrect type champ textarea \(expected text\)$/) }
|
||||
it { expect { run_task }.to raise_exception(/incorrect type champ textarea \(expected text\)$/) }
|
||||
end
|
||||
|
||||
context 'with champ mandatoriness mismatch' do
|
||||
|
@ -114,13 +114,13 @@ describe '2018_07_31_nutriscore' do
|
|||
context 'with siret mismatch on source' do
|
||||
let!(:type_champ_siret_from) { create(:type_de_champ_textarea, order_place: 2, libelle: 'Numéro SIRET', procedure: proc_from) }
|
||||
|
||||
it { expect { run_task }.to raise_exception(/incorrect type TypesDeChamp::TextareaTypeDeChamp \(expected TypesDeChamp::TextTypeDeChamp\), incorrect type champ textarea \(expected text\)$/) }
|
||||
it { expect { run_task }.to raise_exception(/incorrect type champ textarea \(expected text\)$/) }
|
||||
end
|
||||
|
||||
context 'with siret mismatch on destination' do
|
||||
let!(:type_champ_siret_to) { create(:type_de_champ_text, order_place: 2, libelle: 'Numéro SIRET', procedure: proc_to) }
|
||||
|
||||
it { expect { run_task }.to raise_exception(/incorrect type TypesDeChamp::TextTypeDeChamp \(expected TypesDeChamp::SiretTypeDeChamp\), incorrect type champ text \(expected siret\)$/) }
|
||||
it { expect { run_task }.to raise_exception(/incorrect type champ text \(expected siret\)$/) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,7 +21,7 @@ shared_examples 'type_de_champ_spec' do
|
|||
type_de_champ = create(:"type_de_champ_#{type_champ}")
|
||||
champ = type_de_champ.champ.create
|
||||
|
||||
expect(type_de_champ.class.name).to match(/^TypesDeChamp::/)
|
||||
expect(type_de_champ.dynamic_type.class.name).to match(/^TypesDeChamp::/)
|
||||
expect(champ.class.name).to match(/^Champs::/)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,12 +3,14 @@ require 'spec_helper'
|
|||
describe TypesDeChamp::LinkedDropDownListTypeDeChamp do
|
||||
describe '#unpack_options' do
|
||||
let(:drop_down_list) { build(:drop_down_list, value: menu_options) }
|
||||
let(:type_de_champ) { described_class.new(drop_down_list: drop_down_list) }
|
||||
let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, drop_down_list: drop_down_list) }
|
||||
|
||||
subject { type_de_champ.dynamic_type }
|
||||
|
||||
context 'with no options' do
|
||||
let(:menu_options) { '' }
|
||||
it { expect(type_de_champ.secondary_options).to eq({}) }
|
||||
it { expect(type_de_champ.primary_options).to eq([]) }
|
||||
it { expect(subject.secondary_options).to eq({}) }
|
||||
it { expect(subject.primary_options).to eq([]) }
|
||||
end
|
||||
|
||||
context 'with two primary options' do
|
||||
|
@ -25,7 +27,7 @@ describe TypesDeChamp::LinkedDropDownListTypeDeChamp do
|
|||
end
|
||||
|
||||
it do
|
||||
expect(type_de_champ.secondary_options).to eq(
|
||||
expect(subject.secondary_options).to eq(
|
||||
{
|
||||
'' => [],
|
||||
'Primary 1' => [ '', 'secondary 1.1', 'secondary 1.2'],
|
||||
|
@ -34,7 +36,7 @@ describe TypesDeChamp::LinkedDropDownListTypeDeChamp do
|
|||
)
|
||||
end
|
||||
|
||||
it { expect(type_de_champ.primary_options).to eq([ '', 'Primary 1', 'Primary 2' ]) }
|
||||
it { expect(subject.primary_options).to eq([ '', 'Primary 1', 'Primary 2' ]) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue