Merge pull request #645 from sgmap/form_with_rails_helper
Form with rails helper
This commit is contained in:
commit
d23816a6b6
25 changed files with 201 additions and 125 deletions
|
@ -8,8 +8,19 @@
|
|||
}
|
||||
|
||||
label {
|
||||
margin-bottom: $default-spacer;
|
||||
display: inline-block;
|
||||
margin-bottom: $default-padding;
|
||||
display: block;
|
||||
|
||||
.mandatory {
|
||||
color: $dark-red;
|
||||
}
|
||||
|
||||
.notice {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
margin-top: $default-spacer;
|
||||
color: $grey;
|
||||
}
|
||||
}
|
||||
|
||||
input[type=text]:not([data-address='true']),
|
||||
|
|
|
@ -32,19 +32,21 @@ class RootController < ApplicationController
|
|||
end
|
||||
|
||||
def patron
|
||||
@all_champs = TypeDeChamp.type_champs
|
||||
.map { |name, _| TypeDeChamp.new(type_champ: name, libelle: name, mandatory: true) }
|
||||
.map { |type_de_champ| Champ.new(type_de_champ: type_de_champ) }
|
||||
description = 'a not so long description'
|
||||
|
||||
all_champs = TypeDeChamp.type_champs
|
||||
.map { |name, _| TypeDeChamp.new(type_champ: name, libelle: name, description: description, mandatory: true) }
|
||||
.map { |type_de_champ| ChampPublic.new(type_de_champ: type_de_champ) }
|
||||
.map.with_index do |champ, i|
|
||||
champ.id = i
|
||||
champ
|
||||
end
|
||||
|
||||
@all_champs
|
||||
all_champs
|
||||
.select { |champ| champ.type_champ == 'header_section' }
|
||||
.each { |champ| champ.type_de_champ.libelle = 'un super titre de section' }
|
||||
|
||||
@all_champs
|
||||
all_champs
|
||||
.select { |champ| %w(drop_down_list multiple_drop_down_list).include?(champ.type_champ) }
|
||||
.each do |champ|
|
||||
champ.type_de_champ.drop_down_list = DropDownList.new(type_de_champ: champ.type_de_champ)
|
||||
|
@ -64,9 +66,11 @@ option C"
|
|||
}
|
||||
|
||||
type_champ_values.each do |(type_champ, value)|
|
||||
@all_champs
|
||||
all_champs
|
||||
.select { |champ| champ.type_champ == type_champ.to_s }
|
||||
.each { |champ| champ.value = value }
|
||||
end
|
||||
|
||||
@dossier = Dossier.new(champs: all_champs)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,6 +6,9 @@ class Champ < ActiveRecord::Base
|
|||
delegate :libelle, :type_champ, :order_place, :mandatory, :description, :drop_down_list, to: :type_de_champ
|
||||
|
||||
before_save :format_date_to_iso, if: Proc.new { type_champ == 'date' }
|
||||
before_save :serialize_datetime_if_needed, if: Proc.new { type_champ == 'datetime' }
|
||||
before_save :multiple_select_to_string, if: Proc.new { type_champ == 'multiple_drop_down_list' }
|
||||
|
||||
after_save :internal_notification, if: Proc.new { !dossier.nil? }
|
||||
|
||||
def mandatory?
|
||||
|
@ -65,9 +68,35 @@ class Champ < ActiveRecord::Base
|
|||
self.value = date
|
||||
end
|
||||
|
||||
def serialize_datetime_if_needed
|
||||
if (value =~ /=>/).present?
|
||||
date = begin
|
||||
hash_date = YAML.safe_load(value.gsub('=>', ': '))
|
||||
year, month, day, hour, minute = hash_date.values_at(1,2,3,4,5)
|
||||
DateTime.new(year, month, day, hour, minute).strftime("%d/%m/%Y %H:%M")
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
self.value = date
|
||||
end
|
||||
end
|
||||
|
||||
def internal_notification
|
||||
unless dossier.state == 'draft'
|
||||
NotificationService.new('champs', self.dossier.id, self.libelle).notify
|
||||
end
|
||||
end
|
||||
|
||||
def multiple_select_to_string
|
||||
if value.present?
|
||||
json = JSON.parse(value)
|
||||
if json == ['']
|
||||
self.value = nil
|
||||
else
|
||||
json = json - ['']
|
||||
self.value = json.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -43,6 +43,8 @@ class Dossier < ActiveRecord::Base
|
|||
belongs_to :procedure
|
||||
belongs_to :user
|
||||
|
||||
accepts_nested_attributes_for :champs
|
||||
|
||||
default_scope { where(hidden_at: nil) }
|
||||
scope :state_brouillon, -> { where(state: BROUILLON) }
|
||||
scope :state_not_brouillon, -> { where.not(state: BROUILLON) }
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
%input{ type: 'text',
|
||||
= form.text_field :value,
|
||||
'data-address': 'true',
|
||||
name: "champs['#{champ.id}']",
|
||||
id: "champs_#{champ.id}",
|
||||
placeholder: champ.libelle,
|
||||
value: champ.value,
|
||||
required: champ.mandatory }
|
||||
required: champ.mandatory
|
||||
|
|
|
@ -1 +1,6 @@
|
|||
%label{ for: :"champs_#{champ.id}" }> #{champ.libelle} #{champ.mandatory ? '*' : nil}
|
||||
= form.label :value do
|
||||
#{champ.libelle}
|
||||
- if champ.mandatory
|
||||
%span.mandatory *
|
||||
- if champ.description.present?
|
||||
%span.notice= champ.description
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
%input{ type: 'checkbox',
|
||||
name: "champs['#{champ.id}']",
|
||||
id: "champs_#{champ.id}",
|
||||
checked: ('checked' if champ.value == 'on'),
|
||||
required: champ.mandatory }
|
||||
= form.check_box :value,
|
||||
{ required: champ.mandatory },
|
||||
'on',
|
||||
'off'
|
||||
|
||||
%br
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
%div
|
||||
%label
|
||||
= radio_button_tag "champs['#{champ.id}']", "M.", champ.value == 'Mme' ? false : true
|
||||
= form.radio_button :value, 'M.'
|
||||
Monsieur
|
||||
|
||||
%label
|
||||
= radio_button_tag "champs['#{champ.id}']", "Mme", champ.value == 'Mme'
|
||||
= form.radio_button :value, 'Mme.'
|
||||
Madame
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
%input{ name: "champs['#{champ.id}']",
|
||||
placeholder: "JJ/MM/AAAA",
|
||||
id: "champs_#{champ.id}",
|
||||
= form.date_field :value,
|
||||
value: champ.value,
|
||||
type: "date",
|
||||
required: champ.mandatory }
|
||||
placeholder: 'JJ/MM/AAAA',
|
||||
required: champ.mandatory
|
||||
|
|
|
@ -1,22 +1,6 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
- parsed_value = champ.value.present? ? DateTime.parse(champ.value) : DateTime.now
|
||||
|
||||
.datetime
|
||||
%input{ name: "champs['#{champ.id}']",
|
||||
placeholder: champ.libelle,
|
||||
id: "champs_#{champ.id}",
|
||||
value: (champ.value.split(/[ ][0-9]*:[0-9]*/).first unless champ.value.nil?),
|
||||
type: 'date',
|
||||
required: champ.mandatory }
|
||||
|
||||
%select{ name: "time_hour['#{champ.id}']", id: "time_hour_#{champ.id}", required: champ.mandatory }
|
||||
- (0..23).each do |num|
|
||||
- num = "%.2i" %num
|
||||
%option{ value: num, selected: (:selected if champ.same_hour?(num)) }
|
||||
= num
|
||||
h
|
||||
%select{ name: "time_minute['#{champ.id}']", id: "time_minute_#{champ.id}", required: champ.mandatory }
|
||||
- (0..55).step(5) do |num|
|
||||
- num = "%.2i" %num
|
||||
%option{ value: num, selected: (:selected if champ.same_minute?(num)) }
|
||||
= num
|
||||
min
|
||||
= form.datetime_select(:value, selected: parsed_value, start_year: 1950, end_year: 2100, minute_step: 5)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
= select_tag("champs['#{champ.id}']",
|
||||
options_for_select(Champ.departements, selected: champ.value))
|
||||
= form.select :value,
|
||||
Champ.departements,
|
||||
required: champ.mandatory
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
- dossier = Dossier.find_by(id: champ.value)
|
||||
- show_text_summary = dossier.present?
|
||||
|
@ -6,14 +6,11 @@
|
|||
- text_summary = dossier.try(:text_summary)
|
||||
|
||||
.dossier-link
|
||||
%input{ name: "champs['#{ champ.id }']",
|
||||
= form.number_field :value,
|
||||
placeholder: "Numéro de dossier",
|
||||
id: "champs_#{ champ.id }",
|
||||
value: champ.value,
|
||||
type: 'number',
|
||||
'autocomplete' => 'off',
|
||||
'data-type' => 'dossier-link',
|
||||
required: champ.mandatory }
|
||||
autocomplete: 'off',
|
||||
'data-type': 'dossier-link',
|
||||
required: champ.mandatory
|
||||
|
||||
.help-block
|
||||
%p.text-info{ style: show_text_summary ? nil : 'display: none;' }
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
- if champ.drop_down_list && champ.drop_down_list.options.any?
|
||||
= select_tag("champs['#{champ.id}']",
|
||||
options_for_select(champ.drop_down_list.options,
|
||||
selected: champ.drop_down_list.selected_options_without_decorator(champ),
|
||||
disabled: champ.drop_down_list.disabled_options),
|
||||
multiple: false)
|
||||
= form.select :value,
|
||||
champ.drop_down_list.options,
|
||||
disabled: champ.drop_down_list.disabled_options,
|
||||
required: champ.mandatory
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
%input{ type: 'email',
|
||||
name: "champs['#{champ.id}']",
|
||||
id: "champs_#{champ.id}",
|
||||
= form.email_field :value,
|
||||
placeholder: champ.libelle,
|
||||
value: champ.value,
|
||||
required: champ.mandatory }
|
||||
required: champ.mandatory
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
%input{ type: 'checkbox',
|
||||
name: "champs['#{champ.id}']",
|
||||
id: "champs_#{champ.id}",
|
||||
checked: ('checked' if champ.value == 'on'),
|
||||
required: champ.mandatory }
|
||||
= form.check_box :value,
|
||||
{ required: champ.mandatory },
|
||||
'on',
|
||||
'off'
|
||||
|
||||
%br
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
- if champ.drop_down_list && champ.drop_down_list.options.any?
|
||||
= select_tag("champs['#{champ.id}']",
|
||||
options_for_select(champ.drop_down_list.options,
|
||||
selected: champ.drop_down_list.selected_options_without_decorator(champ),
|
||||
disabled: champ.drop_down_list.disabled_options),
|
||||
= form.select :value,
|
||||
champ.drop_down_list.options,
|
||||
{ selected: champ.drop_down_list.selected_options_without_decorator(champ),
|
||||
disabled: champ.drop_down_list.disabled_options },
|
||||
multiple: true,
|
||||
class: 'select2')
|
||||
class: 'select2'
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
%input{ type: 'number',
|
||||
name: "champs['#{champ.id}']",
|
||||
id: "champs_#{champ.id}",
|
||||
= form.number_field :value,
|
||||
placeholder: champ.libelle,
|
||||
value: champ.value,
|
||||
required: champ.mandatory }
|
||||
required: champ.mandatory
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
= select_tag("champs['#{champ.id}']",
|
||||
options_for_select(Champ.pays, selected: champ.value))
|
||||
= form.select :value,
|
||||
Champ.pays,
|
||||
required: champ.mandatory
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
%input{ type: 'tel',
|
||||
name: "champs['#{champ.id}']",
|
||||
id: "champs_#{champ.id}",
|
||||
= form.phone_field :value,
|
||||
placeholder: champ.libelle,
|
||||
value: champ.value,
|
||||
required: champ.mandatory }
|
||||
required: champ.mandatory
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
= select_tag("champs['#{champ.id}']",
|
||||
options_for_select(Champ.regions, selected: champ.value))
|
||||
= form.select :value,
|
||||
Champ.regions,
|
||||
required: champ.mandatory
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
%input{ type: 'text',
|
||||
name: "champs['#{champ.id}']",
|
||||
id: "champs_#{champ.id}",
|
||||
= form.text_field :value,
|
||||
placeholder: champ.libelle,
|
||||
value: champ.value,
|
||||
required: champ.mandatory }
|
||||
required: champ.mandatory
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
%textarea{ name: "champs['#{champ.id}']",
|
||||
= form.text_area :value,
|
||||
row: 6,
|
||||
placeholder: champ.description,
|
||||
id: "champs_#{champ.id}",
|
||||
row: '6',
|
||||
required: champ.mandatory }
|
||||
= sanitize(champ.value)
|
||||
required: champ.mandatory,
|
||||
value: sanitize(champ.value)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
|
||||
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { form: form, champ: champ }
|
||||
|
||||
%div
|
||||
%label
|
||||
= radio_button_tag "champs['#{champ.id}']", "true", champ.value == 'true'
|
||||
= form.radio_button :value, true
|
||||
Oui
|
||||
|
||||
%label
|
||||
= radio_button_tag "champs['#{champ.id}']", "false", champ.value == 'false'
|
||||
= form.radio_button :value, false
|
||||
Non
|
||||
|
|
|
@ -11,12 +11,16 @@
|
|||
%h1 Formulaires
|
||||
|
||||
%form.form
|
||||
- @all_champs.each do |champ|
|
||||
= render partial: "new_gestionnaire/dossiers/champs/#{champ.type_champ}", locals: { champ: champ }
|
||||
= form_for @dossier, url: '', html: { class: 'form' } do |f|
|
||||
= f.fields_for :champs do |champ_form|
|
||||
- champ = champ_form.object
|
||||
= render partial: "new_gestionnaire/dossiers/champs/#{champ.type_champ}",
|
||||
locals: { champ: champ, form: champ_form }
|
||||
|
||||
%input{ type: "password", value: "12345678" }
|
||||
.send-wrapper
|
||||
%input.button.send{ type: "submit", value: "Enregistrer un brouillon (formnovalidate)", formnovalidate: true }
|
||||
%input.button.send{ type: "submit", value: "Envoyer" }
|
||||
= f.submit 'Enregistrer un brouillon (formnovalidate)', formnovalidate: true, class: 'button send'
|
||||
= f.submit 'Envoyer', class: 'button send'
|
||||
|
||||
%h1 Boutons
|
||||
|
||||
|
|
|
@ -4,4 +4,63 @@ describe Champ do
|
|||
require 'models/champ_shared_example.rb'
|
||||
|
||||
it_should_behave_like "champ_spec"
|
||||
|
||||
describe '#serialize_datetime_if_needed' do
|
||||
let(:type_de_champ) { TypeDeChamp.new(type_champ: 'datetime') }
|
||||
let(:champ) { Champ.new(type_de_champ: type_de_champ, value: value) }
|
||||
|
||||
before { champ.save }
|
||||
|
||||
# when using the old form, and the ChampsService Class
|
||||
# TODO: to remove
|
||||
context 'when the value is already serialized' do
|
||||
let(:value) { '12/01/2017 10:23' }
|
||||
|
||||
it { expect(champ.value).to eq(value) }
|
||||
end
|
||||
|
||||
context 'when the value is not already serialized' do
|
||||
let(:value) { '{ 1=>2017, 2=>01, 3=>12, 4=>10, 5=>23 }' }
|
||||
|
||||
it { expect(champ.value).to eq('12/01/2017 10:23') }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#multiple_select_to_string' do
|
||||
let(:type_de_champ) { TypeDeChamp.new(type_champ: 'multiple_drop_down_list') }
|
||||
let(:champ) { Champ.new(type_de_champ: type_de_champ, value: value) }
|
||||
|
||||
before { champ.save }
|
||||
|
||||
# when using the old form, and the ChampsService Class
|
||||
# TODO: to remove
|
||||
context 'when the value is already deserialized' do
|
||||
let(:value) { '["1", "2"]' }
|
||||
|
||||
it { expect(champ.value).to eq(value) }
|
||||
|
||||
context 'when the value is nil' do
|
||||
let(:value) { nil }
|
||||
|
||||
it { expect(champ.value).to eq(value) }
|
||||
end
|
||||
end
|
||||
|
||||
# for explanation for the "" entry, see
|
||||
# https://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/select
|
||||
# GOTCHA
|
||||
context 'when the value is not already deserialized' do
|
||||
context 'when a choice is selected' do
|
||||
let(:value) { '["", "1", "2"]' }
|
||||
|
||||
it { expect(champ.value).to eq('["1", "2"]') }
|
||||
end
|
||||
|
||||
context 'when all choices are removed' do
|
||||
let(:value) { '[""]' }
|
||||
|
||||
it { expect(champ.value).to eq(nil) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue