Merge pull request #645 from sgmap/form_with_rails_helper

Form with rails helper
This commit is contained in:
LeSim 2017-08-28 14:06:48 +02:00 committed by Mathieu Magnin
commit d23816a6b6
25 changed files with 201 additions and 125 deletions

View file

@ -8,8 +8,19 @@
} }
label { label {
margin-bottom: $default-spacer; margin-bottom: $default-padding;
display: inline-block; 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']), input[type=text]:not([data-address='true']),

View file

@ -32,19 +32,21 @@ class RootController < ApplicationController
end end
def patron def patron
@all_champs = TypeDeChamp.type_champs description = 'a not so long description'
.map { |name, _| TypeDeChamp.new(type_champ: name, libelle: name, mandatory: true) }
.map { |type_de_champ| Champ.new(type_de_champ: type_de_champ) } 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| .map.with_index do |champ, i|
champ.id = i champ.id = i
champ champ
end end
@all_champs all_champs
.select { |champ| champ.type_champ == 'header_section' } .select { |champ| champ.type_champ == 'header_section' }
.each { |champ| champ.type_de_champ.libelle = 'un super titre de 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) } .select { |champ| %w(drop_down_list multiple_drop_down_list).include?(champ.type_champ) }
.each do |champ| .each do |champ|
champ.type_de_champ.drop_down_list = DropDownList.new(type_de_champ: champ.type_de_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)| type_champ_values.each do |(type_champ, value)|
@all_champs all_champs
.select { |champ| champ.type_champ == type_champ.to_s } .select { |champ| champ.type_champ == type_champ.to_s }
.each { |champ| champ.value = value } .each { |champ| champ.value = value }
end end
@dossier = Dossier.new(champs: all_champs)
end end
end end

View file

@ -6,6 +6,9 @@ class Champ < ActiveRecord::Base
delegate :libelle, :type_champ, :order_place, :mandatory, :description, :drop_down_list, to: :type_de_champ 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 :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? } after_save :internal_notification, if: Proc.new { !dossier.nil? }
def mandatory? def mandatory?
@ -65,9 +68,35 @@ class Champ < ActiveRecord::Base
self.value = date self.value = date
end 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 def internal_notification
unless dossier.state == 'draft' unless dossier.state == 'draft'
NotificationService.new('champs', self.dossier.id, self.libelle).notify NotificationService.new('champs', self.dossier.id, self.libelle).notify
end end
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 end

View file

@ -43,6 +43,8 @@ class Dossier < ActiveRecord::Base
belongs_to :procedure belongs_to :procedure
belongs_to :user belongs_to :user
accepts_nested_attributes_for :champs
default_scope { where(hidden_at: nil) } default_scope { where(hidden_at: nil) }
scope :state_brouillon, -> { where(state: BROUILLON) } scope :state_brouillon, -> { where(state: BROUILLON) }
scope :state_not_brouillon, -> { where.not(state: BROUILLON) } scope :state_not_brouillon, -> { where.not(state: BROUILLON) }

View file

@ -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', 'data-address': 'true',
name: "champs['#{champ.id}']",
id: "champs_#{champ.id}",
placeholder: champ.libelle, placeholder: champ.libelle,
value: champ.value, required: champ.mandatory
required: champ.mandatory }

View file

@ -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

View file

@ -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', = form.check_box :value,
name: "champs['#{champ.id}']", { required: champ.mandatory },
id: "champs_#{champ.id}", 'on',
checked: ('checked' if champ.value == 'on'), 'off'
required: champ.mandatory }
%br %br

View file

@ -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 %div
%label %label
= radio_button_tag "champs['#{champ.id}']", "M.", champ.value == 'Mme' ? false : true = form.radio_button :value, 'M.'
Monsieur Monsieur
%label %label
= radio_button_tag "champs['#{champ.id}']", "Mme", champ.value == 'Mme' = form.radio_button :value, 'Mme.'
Madame Madame

View file

@ -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}']", = form.date_field :value,
placeholder: "JJ/MM/AAAA",
id: "champs_#{champ.id}",
value: champ.value, value: champ.value,
type: "date", placeholder: 'JJ/MM/AAAA',
required: champ.mandatory } required: champ.mandatory

View file

@ -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 .datetime
%input{ name: "champs['#{champ.id}']", = form.datetime_select(:value, selected: parsed_value, start_year: 1950, end_year: 2100, minute_step: 5)
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

View file

@ -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}']", = form.select :value,
options_for_select(Champ.departements, selected: champ.value)) Champ.departements,
required: champ.mandatory

View file

@ -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) - dossier = Dossier.find_by(id: champ.value)
- show_text_summary = dossier.present? - show_text_summary = dossier.present?
@ -6,14 +6,11 @@
- text_summary = dossier.try(:text_summary) - text_summary = dossier.try(:text_summary)
.dossier-link .dossier-link
%input{ name: "champs['#{ champ.id }']", = form.number_field :value,
placeholder: "Numéro de dossier", placeholder: "Numéro de dossier",
id: "champs_#{ champ.id }", autocomplete: 'off',
value: champ.value, 'data-type': 'dossier-link',
type: 'number', required: champ.mandatory
'autocomplete' => 'off',
'data-type' => 'dossier-link',
required: champ.mandatory }
.help-block .help-block
%p.text-info{ style: show_text_summary ? nil : 'display: none;' } %p.text-info{ style: show_text_summary ? nil : 'display: none;' }

View file

@ -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? = form.select :value,
= select_tag("champs['#{champ.id}']", champ.drop_down_list.options,
options_for_select(champ.drop_down_list.options, disabled: champ.drop_down_list.disabled_options,
selected: champ.drop_down_list.selected_options_without_decorator(champ), required: champ.mandatory
disabled: champ.drop_down_list.disabled_options),
multiple: false)

View file

@ -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', = form.email_field :value,
name: "champs['#{champ.id}']",
id: "champs_#{champ.id}",
placeholder: champ.libelle, placeholder: champ.libelle,
value: champ.value, required: champ.mandatory
required: champ.mandatory }

View file

@ -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', = form.check_box :value,
name: "champs['#{champ.id}']", { required: champ.mandatory },
id: "champs_#{champ.id}", 'on',
checked: ('checked' if champ.value == 'on'), 'off'
required: champ.mandatory }
%br %br

View file

@ -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? - if champ.drop_down_list && champ.drop_down_list.options.any?
= select_tag("champs['#{champ.id}']", = form.select :value,
options_for_select(champ.drop_down_list.options, champ.drop_down_list.options,
selected: champ.drop_down_list.selected_options_without_decorator(champ), { selected: champ.drop_down_list.selected_options_without_decorator(champ),
disabled: champ.drop_down_list.disabled_options), disabled: champ.drop_down_list.disabled_options },
multiple: true, multiple: true,
class: 'select2') class: 'select2'

View file

@ -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', = form.number_field :value,
name: "champs['#{champ.id}']",
id: "champs_#{champ.id}",
placeholder: champ.libelle, placeholder: champ.libelle,
value: champ.value, required: champ.mandatory
required: champ.mandatory }

View file

@ -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}']", = form.select :value,
options_for_select(Champ.pays, selected: champ.value)) Champ.pays,
required: champ.mandatory

View file

@ -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', = form.phone_field :value,
name: "champs['#{champ.id}']",
id: "champs_#{champ.id}",
placeholder: champ.libelle, placeholder: champ.libelle,
value: champ.value, required: champ.mandatory
required: champ.mandatory }

View file

@ -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}']", = form.select :value,
options_for_select(Champ.regions, selected: champ.value)) Champ.regions,
required: champ.mandatory

View file

@ -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', = form.text_field :value,
name: "champs['#{champ.id}']",
id: "champs_#{champ.id}",
placeholder: champ.libelle, placeholder: champ.libelle,
value: champ.value, required: champ.mandatory
required: champ.mandatory }

View file

@ -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, placeholder: champ.description,
id: "champs_#{champ.id}", required: champ.mandatory,
row: '6', value: sanitize(champ.value)
required: champ.mandatory }
= sanitize(champ.value)

View file

@ -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 %div
%label %label
= radio_button_tag "champs['#{champ.id}']", "true", champ.value == 'true' = form.radio_button :value, true
Oui Oui
%label %label
= radio_button_tag "champs['#{champ.id}']", "false", champ.value == 'false' = form.radio_button :value, false
Non Non

View file

@ -11,12 +11,16 @@
%h1 Formulaires %h1 Formulaires
%form.form %form.form
- @all_champs.each do |champ| = form_for @dossier, url: '', html: { class: 'form' } do |f|
= render partial: "new_gestionnaire/dossiers/champs/#{champ.type_champ}", locals: { champ: champ } = 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" } %input{ type: "password", value: "12345678" }
.send-wrapper .send-wrapper
%input.button.send{ type: "submit", value: "Enregistrer un brouillon (formnovalidate)", formnovalidate: true } = f.submit 'Enregistrer un brouillon (formnovalidate)', formnovalidate: true, class: 'button send'
%input.button.send{ type: "submit", value: "Envoyer" } = f.submit 'Envoyer', class: 'button send'
%h1 Boutons %h1 Boutons

View file

@ -4,4 +4,63 @@ describe Champ do
require 'models/champ_shared_example.rb' require 'models/champ_shared_example.rb'
it_should_behave_like "champ_spec" 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 end