diff options
| author | Zog | 2018-05-03 16:42:28 +0200 |
|---|---|---|
| committer | Zog | 2018-05-03 16:42:28 +0200 |
| commit | 581dbb024db288dc70713af3c5b5052b453412a9 (patch) | |
| tree | e157880fe365b853659fa0fae95aef91d74ae756 | |
| parent | db65c0ffc7ccc76a144689ec3db43fbc2e61ee82 (diff) | |
| download | chouette-core-581dbb024db288dc70713af3c5b5052b453412a9.tar.bz2 | |
Refs #6092; Add specs on CustomlFields6092-update-custom-fields
- Show validation errors on fields
- Smarter attachments
| -rw-r--r-- | Gemfile | 1 | ||||
| -rw-r--r-- | Gemfile.lock | 2 | ||||
| -rw-r--r-- | app/assets/stylesheets/components/_lists.sass | 4 | ||||
| -rw-r--r-- | app/models/custom_field.rb | 69 | ||||
| -rw-r--r-- | app/uploaders/custom_field_attachment_uploader.rb | 26 | ||||
| -rw-r--r-- | app/views/shared/custom_fields/_attachment.html.slim | 8 | ||||
| -rw-r--r-- | spec/models/custom_field_spec.rb | 96 |
7 files changed, 176 insertions, 30 deletions
@@ -130,6 +130,7 @@ gem 'acts_as_tree', '~> 2.1.0', require: 'acts_as_tree' gem 'rabl' gem 'carrierwave', '~> 1.0' +gem 'rmagick' gem 'sidekiq', require: ['sidekiq', 'sidekiq/web'] gem 'whenever', github: 'af83/whenever', require: false # '~> 0.9' diff --git a/Gemfile.lock b/Gemfile.lock index 2071eee78..db412abd0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -444,6 +444,7 @@ GEM rgeo-activerecord (4.0.5) activerecord (~> 4.2) rgeo (~> 0.3) + rmagick (2.16.0) roo (2.7.1) nokogiri (~> 1) rubyzip (~> 1.1, < 2.0.0) @@ -681,6 +682,7 @@ DEPENDENCIES reflex! responders rgeo (~> 0.5.2) + rmagick roo rspec-rails (~> 3.5.0) rspec-snapshot diff --git a/app/assets/stylesheets/components/_lists.sass b/app/assets/stylesheets/components/_lists.sass index 3cce20021..f9b449541 100644 --- a/app/assets/stylesheets/components/_lists.sass +++ b/app/assets/stylesheets/components/_lists.sass @@ -30,6 +30,8 @@ $dlWidth: 40% // overflow: hidden vertical-align: top padding: 5px 15px 6px 15px + img + max-width: 100% // Definition term .dl-term @@ -58,4 +60,4 @@ $dlWidth: 40% ul list-style: none padding-left: 0 - margin-bottom: 0
\ No newline at end of file + margin-bottom: 0 diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb index deb0326f8..de090fac2 100644 --- a/app/models/custom_field.rb +++ b/app/models/custom_field.rb @@ -2,10 +2,11 @@ class CustomField < ApplicationModel extend Enumerize belongs_to :workgroup - enumerize :field_type, in: %i{list integer string attachment} + enumerize :field_type, in: %i{list integer float string attachment} validates :name, uniqueness: {scope: [:resource_type, :workgroup_id]} validates :code, uniqueness: {scope: [:resource_type, :workgroup_id], case_sensitive: false}, presence: true + validates :workgroup, :resource_type, :field_type, presence: true class Collection < HashWithIndifferentAccess def initialize object, workgroup=nil @@ -47,7 +48,7 @@ class CustomField < ApplicationModel end def options - @custom_field.options || {} + @custom_field.options&.stringify_keys || {} end def validate @@ -59,6 +60,10 @@ class CustomField < ApplicationModel @valid end + def required? + !!options["required"] + end + def value @raw_value end @@ -76,7 +81,8 @@ class CustomField < ApplicationModel end def errors_key - "custom_fields.#{code}" + # this must match the ID used in the inputs + "custom_field_#{code}" end def to_hash @@ -91,7 +97,7 @@ class CustomField < ApplicationModel end def preprocess_value_for_assignment val - val + val || default_value end def render_partial @@ -111,7 +117,7 @@ class CustomField < ApplicationModel @instance.custom_field end - delegate :custom_field, :value, :options, to: :@instance + delegate :custom_field, :value, :options, :required?, to: :@instance delegate :code, :name, :field_type, to: :custom_field def to_s @@ -122,7 +128,7 @@ class CustomField < ApplicationModel protected def form_input_id - "custom_field_#{code}" + "custom_field_#{code}".to_sym end def form_input_name @@ -144,26 +150,64 @@ class CustomField < ApplicationModel class Integer < Base def value - @raw_value&.to_i + @raw_value.present? ? @raw_value.to_i : nil end def validate @valid = true - return if @raw_value.is_a?(Fixnum) || @raw_value.is_a?(Float) - unless @raw_value.to_s =~ /\A\d*\Z/ + return if @raw_value.is_a?(Fixnum) + unless @raw_value.to_s =~ /\A-?\d*\Z/ @owner.errors.add errors_key, "'#{@raw_value}' is not a valid integer" @valid = false end end + + class Input < Base::Input + def form_input_options + super.update({ + as: :integer + }) + end + end + end + + class Float < Integer + def value + @raw_value.present? ? @raw_value.to_f : nil + end + + def validate + @valid = true + return if @raw_value.is_a?(Fixnum) || @raw_value.is_a?(Float) + unless @raw_value.to_s =~ /\A-?\d*(\.\d+)?\Z/ + @owner.errors.add errors_key, "'#{@raw_value}' is not a valid float" + @valid = false + end + end + + class Input < Base::Input + def form_input_options + super.update({ + as: :float + }) + end + end end class List < Integer def validate super return unless value.present? - unless value >= 0 && value < options["list_values"].size - @owner.errors.add errors_key, "'#{@raw_value}' is not a valid value" - @valid = false + if options["list_values"].is_a?(Hash) + unless options["list_values"].keys.map(&:to_s).include?(value.to_s) + @owner.errors.add errors_key, "'#{@raw_value}' is not a valid value" + @valid = false + end + else + unless value >= 0 && value < options["list_values"].size + @owner.errors.add errors_key, "'#{@raw_value}' is not a valid value" + @valid = false + end end end @@ -178,6 +222,7 @@ class CustomField < ApplicationModel collection = options["list_values"] collection = collection.each_with_index.to_a if collection.is_a?(Array) collection = collection.map(&:reverse) if collection.is_a?(Hash) + collection = [["", ""]] + collection unless required? super.update({ selected: value, collection: collection diff --git a/app/uploaders/custom_field_attachment_uploader.rb b/app/uploaders/custom_field_attachment_uploader.rb index 411b65bc3..94a14f7e4 100644 --- a/app/uploaders/custom_field_attachment_uploader.rb +++ b/app/uploaders/custom_field_attachment_uploader.rb @@ -1,5 +1,5 @@ class CustomFieldAttachmentUploader < CarrierWave::Uploader::Base - + include CarrierWave::RMagick storage :file def store_dir @@ -9,4 +9,28 @@ class CustomFieldAttachmentUploader < CarrierWave::Uploader::Base def extension_whitelist model.send "#{mounted_as}_extension_whitelist" end + + process :dynamic_versions + + def method_missing mid, *args + unless @dynamic_versions_loaded + dynamic_versions + @versions = nil + cache! + end + send mid, *args + end + + def dynamic_versions + custom_field = model.custom_fields[mounted_as.to_s.gsub('custom_field_', '').to_sym] + _versions = custom_field.options["versions"] || {} + + _versions.each do |name, size| + size = size.split('x') + self.class.version name do + process :resize_to_fit => size + end + end + @dynamic_versions_loaded = true + end end diff --git a/app/views/shared/custom_fields/_attachment.html.slim b/app/views/shared/custom_fields/_attachment.html.slim index 32d0fda4d..13714d239 100644 --- a/app/views/shared/custom_fields/_attachment.html.slim +++ b/app/views/shared/custom_fields/_attachment.html.slim @@ -1,4 +1,10 @@ - if field.value.present? - = link_to I18n.t("custom_fields.#{field.owner.class.name.demodulize.underscore}.#{field.code}.link"), field.value.url + - if field.options["display_inline"] + - version = field.options["display_inline"].is_a?(String) && field.options["display_inline"] + = link_to field.value.url do + = image_tag version ? field.value.send(version).url : field.value.url, class: "custom_field_attachment" + - else + - label = field.options["label"] || I18n.t("custom_fields.#{field.owner.class.name.demodulize.underscore}.#{field.code}.link") + = link_to label, field.value.url - else = "-" diff --git a/spec/models/custom_field_spec.rb b/spec/models/custom_field_spec.rb index 0c2644499..4c8ec2910 100644 --- a/spec/models/custom_field_spec.rb +++ b/spec/models/custom_field_spec.rb @@ -52,18 +52,11 @@ RSpec.describe CustomField, type: :model do let(:ref2){ create :workbench_referential } before do create :custom_field, field_type: :integer, code: :ref1_energy, name: :energy, workgroup: ref1.workgroup, options: {default: 12} - class CustomField - enumerize :field_type, in: %i{list integer string attachment float_test} - class Instance - class FloatTest < Integer - def preprocess_value_for_assignment val - val&.to_f - end - end - end - end - create :custom_field, field_type: :float_test, code: :ref1_energy, name: :energy, workgroup: ref1.workgroup, options: {default: 12}, resource_type: "Company" + + create :custom_field, field_type: :float, code: :ref1_energy, name: :energy, workgroup: ref1.workgroup, options: {default: 12}, resource_type: "Company" create :custom_field, field_type: :integer, code: :ref2_energy, name: :energy, workgroup: ref2.workgroup + expect_any_instance_of(CustomField::Instance::Float).to receive(:preprocess_value_for_assignment) {|_, v| v.to_f } + end it "should only initialize fields from the right workgroup" do ref1.switch @@ -81,17 +74,22 @@ RSpec.describe CustomField, type: :model do end context "with a 'list' field_type" do - let!(:field){ [create(:custom_field, code: :energy, field_type: 'list', options: {list_values: %w(foo bar baz)}, workgroup: workgroup)] } + let!(:field){ [create(:custom_field, code: :energy, field_type: 'list', options: {list_values: %w(foo bar baz), default: 1}, workgroup: workgroup)] } let!( :vj ){ create :vehicle_journey, custom_field_values: {energy: "1"} } it "should cast the value" do expect(vj.custom_fields[:energy].value).to eq 1 expect(vj.custom_fields[:energy].display_value).to eq "bar" end - it "should not break initailizartion if the model does not have the :custom_field_values attribute" do + it "should not break initialization if the model does not have the :custom_field_values attribute" do expect{Chouette::VehicleJourney.where(id: vj.id).select(:id).last}.to_not raise_error end + it "should use the default value" do + vj = Chouette::VehicleJourney.new + expect(vj.custom_fields[:energy].value).to eq 1 + end + it "should validate the value" do { "1" => true, @@ -105,7 +103,37 @@ RSpec.describe CustomField, type: :model do expect(vj.validate).to be_truthy else expect(vj.validate).to be_falsy - expect(vj.errors.messages[:"custom_fields.energy"]).to be_present + expect(vj.errors.messages[:"custom_field_energy"]).to be_present + end + end + end + + context 'with the values defined in a Hash' do + let!(:field){ [create(:custom_field, code: :energy, field_type: 'list', options: {list_values:{"1" => "foo", "2" => "bar", "3" => "BAZ"}}, workgroup: workgroup)] } + it "should cast the value" do + expect(vj.custom_fields[:energy].value).to eq 1 + expect(vj.custom_fields[:energy].display_value).to eq "foo" + end + + it "should not break initialization if the model does not have the :custom_field_values attribute" do + expect{Chouette::VehicleJourney.where(id: vj.id).select(:id).last}.to_not raise_error + end + + it "should validate the value" do + { + "1" => true, + 1 => true, + "azerty" => false, + "10" => false, + 10 => false + }.each do |val, valid| + vj = build :vehicle_journey, custom_field_values: {energy: val} + if valid + expect(vj.validate).to be_truthy + else + expect(vj.validate).to be_falsy + expect(vj.errors.messages[:"custom_field_energy"]).to be_present + end end end end @@ -122,6 +150,44 @@ RSpec.describe CustomField, type: :model do { 99 => true, "99" => true, + "-99" => true, + -99 => true, + 99.1 => false, + "99.1" => false, + "-99.1" => false, + -99.1 => false, + "azerty" => false, + "91a" => false, + "a91" => false + }.each do |val, valid| + vj = build :vehicle_journey, custom_field_values: {energy: val} + if valid + expect(vj.validate).to be_truthy + else + expect(vj.validate).to be_falsy, "#{val} should not ba a valid value" + expect(vj.errors.messages[:"custom_field_energy"]).to be_present + end + end + end + end + + context "with a 'float' field_type" do + let!(:field){ [create(:custom_field, code: :energy, field_type: 'float', workgroup: workgroup)] } + let!( :vj ){ create :vehicle_journey, custom_field_values: {energy: "99"} } + it "should cast the value" do + expect(vj.custom_fields[:energy].value).to eq 99.0 + end + + it "should validate the value" do + { + 99 => true, + "99" => true, + "-99" => true, + -99 => true, + 99.1 => true, + "99.1" => true, + "-99.1" => true, + -99.1 => true, "azerty" => false, "91a" => false, "a91" => false @@ -131,7 +197,7 @@ RSpec.describe CustomField, type: :model do expect(vj.validate).to be_truthy else expect(vj.validate).to be_falsy, "#{val} should not ba a valid value" - expect(vj.errors.messages[:"custom_fields.energy"]).to be_present + expect(vj.errors.messages[:"custom_field_energy"]).to be_present end end end |
