eac_rails_utils 0.10.1 → 0.11.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper.rb +5 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder.rb +10 -2
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/association_select_field.rb +1 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/common_text_fields.rb +1 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/currency_field.rb +1 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/date_field.rb +1 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/fields_for.rb +1 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/file_field.rb +1 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/radio_select_field.rb +1 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/searchable_association_field.rb +1 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/select_field.rb +3 -2
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/time_field.rb +1 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/year_month_field.rb +1 -1
- data/app/helpers/eac_rails_utils/data_table_helper.rb +13 -0
- data/{lib/eac → app/helpers/eac_rails_utils}/data_table_helper/column.rb +1 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/data_table_helper/data_table.rb +2 -2
- data/{lib/eac → app/helpers/eac_rails_utils}/data_table_helper/setup.rb +2 -2
- data/app/helpers/eac_rails_utils/links_helper.rb +5 -5
- data/{lib/eac → app/helpers/eac_rails_utils}/menus_helper.rb +5 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/menus_helper/bootstrap_gui_builder.rb +1 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/menus_helper/data_builder.rb +1 -1
- data/{lib/eac → app/helpers/eac_rails_utils}/menus_helper/gui_builder.rb +1 -1
- data/{lib/eac → app/validators/eac_rails_utils}/cpf_validator.rb +1 -1
- data/{lib/eac → app/validators/eac_rails_utils}/no_presence_validator.rb +1 -1
- data/config/locales/en.yml +8 -0
- data/config/locales/pt-BR.yml +8 -0
- data/lib/eac_rails_utils.rb +2 -39
- data/lib/eac_rails_utils/engine.rb +2 -0
- data/lib/{eac → eac_rails_utils}/htmlbeautifier.rb +1 -1
- data/lib/eac_rails_utils/models.rb +9 -0
- data/lib/eac_rails_utils/models/attribute_required.rb +43 -0
- data/lib/eac_rails_utils/models/fetch_errors.rb +92 -0
- data/lib/eac_rails_utils/models/inequality_queries.rb +39 -0
- data/lib/eac_rails_utils/models/tableless.rb +97 -0
- data/lib/eac_rails_utils/models/test_utils.rb +65 -0
- data/lib/eac_rails_utils/patches.rb +9 -0
- data/lib/eac_rails_utils/patches/action_controller_base.rb +2 -0
- data/lib/eac_rails_utils/patches/active_model_associations.rb +40 -0
- data/lib/eac_rails_utils/version.rb +1 -1
- data/test/dummy/app/assets/config/manifest.js +3 -0
- data/test/dummy/app/models/user.rb +4 -0
- data/test/dummy/config/application.rb +1 -1
- data/test/{lib/eac → helpers/eac_rails_utils}/common_form_helper_test.rb +2 -2
- data/test/{lib/eac → helpers/eac_rails_utils}/data_table_test_helper_test.rb +2 -2
- data/test/{app/helpers → helpers}/eac_rails_utils/formatter_helper_test.rb +0 -0
- data/test/lib/eac_rails_utils/{patches/model_attribute_required_test.rb → models/attribute_required_test.rb} +1 -0
- data/test/lib/eac_rails_utils/models/fetch_errors_test.rb +80 -0
- data/test/lib/eac_rails_utils/models/tableless_test.rb +25 -0
- data/test/{lib/eac → validators}/cpf_validator_test.rb +2 -2
- metadata +69 -66
- data/lib/eac/data_table_helper.rb +0 -13
- data/lib/eac/inequality_queries.rb +0 -37
- data/lib/eac/model.rb +0 -90
- data/lib/eac/test_utils.rb +0 -61
- data/lib/eac_rails_utils/patches/model_attribute_required.rb +0 -34
- data/lib/eac_rails_utils/patches/ofx_parser.rb +0 -43
- data/lib/eac_rails_utils/tableless_model.rb +0 -92
- data/test/lib/eac/model_test.rb +0 -78
- data/test/lib/eac/source_target_fixtures_test_files/a.source.html +0 -1
- data/test/lib/eac/source_target_fixtures_test_files/a.target.yaml +0 -1
- data/test/lib/eac/source_target_fixtures_test_files/b.source.html +0 -1
- data/test/lib/eac/source_target_fixtures_test_files/c.target.yaml +0 -1
- data/test/lib/eac_rails_utils/tableless_model_test.rb +0 -23
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EacRailsUtils
|
4
|
+
module Models
|
5
|
+
module FetchErrors
|
6
|
+
# Adiciona as mensagens de erro de record. As mensagens de uma coluna X em record
|
7
|
+
# serão adicionadas na coluna X em self. Se options[:default_column] for especificado
|
8
|
+
# as mensagens da coluna X de record em que X não existe em self serão adicionadas
|
9
|
+
# na coluna options[:default_column].
|
10
|
+
# Um array de colunas pode ser passado em options[:skip] de colunas em record que não
|
11
|
+
# terão suas falhas adicionadas.
|
12
|
+
def fetch_record_errors(record, options = {})
|
13
|
+
record.errors.keys.each do |column|
|
14
|
+
fetch_column_errors(record, column, column, options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Similar a fetch_record_errors, mas torna possível especificar, através de mapping,
|
19
|
+
# colunas-alvo em self com nomes diferentes das colunas-fonte em record.
|
20
|
+
# mapping tem o formato { record_column => self_column }.
|
21
|
+
def fetch_record_errors_by_mapping(record, mapping, options = {})
|
22
|
+
mapping.each do |record_column, self_column|
|
23
|
+
fetch_column_errors(record, record_column, self_column, options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def fetch_column_errors(record, record_column, self_column, options = {})
|
28
|
+
return if options[:skip]&.include?(record_column)
|
29
|
+
|
30
|
+
record.errors[record_column].each do |message|
|
31
|
+
fetch_error_column_message(self_column, message, options[:default_column],
|
32
|
+
"#{record.class.human_attribute_name(record_column)}: ")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Verifica se uma coluna existe.
|
37
|
+
def column?(column)
|
38
|
+
respond_to?(column) && respond_to?("#{column}=")
|
39
|
+
end
|
40
|
+
|
41
|
+
def save_or_raise
|
42
|
+
raise "Falha ao tentar salvar #{self.class.name}: #{errors_to_string}" unless save
|
43
|
+
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def fetch_error_column_message(column, message, default_column, default_column_message_prefix)
|
50
|
+
build_self_columns_messages(column, message, default_column,
|
51
|
+
default_column_message_prefix).each do |k, v|
|
52
|
+
if column?(k)
|
53
|
+
add_error_message(k, v)
|
54
|
+
break
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Adiciona uma mensagem de erro a uma coluna somente se a coluna
|
60
|
+
# ainda não a possui
|
61
|
+
def add_error_message(column, message)
|
62
|
+
return if errors[column].include?(message)
|
63
|
+
|
64
|
+
errors.add(column, message)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Produz uma lista de campos-mensagens, em ordem de preferência,
|
68
|
+
# que podem receber uma mensagem de falha.
|
69
|
+
def build_self_columns_messages(column, message, default_column,
|
70
|
+
default_column_message_prefix)
|
71
|
+
r = { column => message }
|
72
|
+
m = /^(.+)_id$/.match(column)
|
73
|
+
if m
|
74
|
+
r[m[1]] = message
|
75
|
+
else
|
76
|
+
r["#{column}_id"] = message
|
77
|
+
end
|
78
|
+
r[default_column] = "#{default_column_message_prefix}#{message}" if default_column
|
79
|
+
r
|
80
|
+
end
|
81
|
+
|
82
|
+
def errors_to_string
|
83
|
+
b = ''
|
84
|
+
errors.messages.each do |field, messages|
|
85
|
+
b += ' / ' if b != ''
|
86
|
+
b += field.to_s + ': ' + messages.to_s
|
87
|
+
end
|
88
|
+
b
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EacRailsUtils
|
4
|
+
module Models
|
5
|
+
# == Example:
|
6
|
+
#
|
7
|
+
# Note: model Product has a attribute "foo" Date, Time or Number:
|
8
|
+
#
|
9
|
+
# class Product
|
10
|
+
# include ::EacRailsUtils::Models::InequalityQueries
|
11
|
+
#
|
12
|
+
# add_inequality_queries(:foo)
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# This add the following scopes:
|
16
|
+
#
|
17
|
+
# Product.by_foo_gt(value) # Equivalent to Product.where("foo > ?", value)
|
18
|
+
# Product.by_foo_gteq(value) # Equivalent to Product.where("foo >= ?", value)
|
19
|
+
# Product.by_foo_lt(value) # Equivalent to Product.where("foo < ?", value)
|
20
|
+
# Product.by_foo_lteq(value) # Equivalent to Product.where("foo <= ?", value)
|
21
|
+
module InequalityQueries
|
22
|
+
class << self
|
23
|
+
def included(base)
|
24
|
+
base.extend(ClassMethods)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
def add_inequality_queries(attribute)
|
30
|
+
%w[gt gteq lt lteq].each do |ineq|
|
31
|
+
scope "by_#{attribute}_#{ineq}", lambda { |v|
|
32
|
+
where(arel_table[attribute].send(ineq, v))
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'eac_rails_utils/patches/active_model_associations'
|
4
|
+
require 'virtus'
|
5
|
+
|
6
|
+
module EacRailsUtils
|
7
|
+
module Models
|
8
|
+
class Tableless
|
9
|
+
include ActiveModel::Model
|
10
|
+
include Virtus.model
|
11
|
+
include ActiveModel::Associations
|
12
|
+
|
13
|
+
def initialize(values = {})
|
14
|
+
super(build_attributes(values))
|
15
|
+
end
|
16
|
+
|
17
|
+
def attributes=(values)
|
18
|
+
super(build_attributes(values))
|
19
|
+
end
|
20
|
+
|
21
|
+
# need hash like accessor, used internal Rails
|
22
|
+
def [](attr)
|
23
|
+
send(attr)
|
24
|
+
end
|
25
|
+
|
26
|
+
# need hash like accessor, used internal Rails
|
27
|
+
def []=(attr, value)
|
28
|
+
send("#{attr}=", value)
|
29
|
+
end
|
30
|
+
|
31
|
+
def save!
|
32
|
+
save || raise("#{self.class}.save failed: #{errors.messages}")
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def build_attributes(values)
|
38
|
+
AttributesBuilder.new(self.class, values).to_attributes
|
39
|
+
end
|
40
|
+
|
41
|
+
class AttributesBuilder
|
42
|
+
DATE_TIME_FIELDS = %i[year month day hour min sec].freeze
|
43
|
+
|
44
|
+
def initialize(model_class, values)
|
45
|
+
@model_class = model_class
|
46
|
+
@values = {}
|
47
|
+
values.each { |k, v| add(k, v) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_attributes
|
51
|
+
@values
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def add(key, value)
|
57
|
+
array_attr = parse_array_attr_key(key)
|
58
|
+
if array_attr
|
59
|
+
array_value_set(array_attr, value)
|
60
|
+
else
|
61
|
+
@values[key] = value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_array_attr_key(key)
|
66
|
+
m = /\A(.+)\(([0-9]+)(.)\)\z/.match(key)
|
67
|
+
return unless m
|
68
|
+
|
69
|
+
::OpenStruct.new(key: m[1], index: m[2].to_i - 1, converter: array_value_converter(m[3]))
|
70
|
+
end
|
71
|
+
|
72
|
+
def array_value_set(array_attr, value)
|
73
|
+
@values[array_attr.key] ||= {}
|
74
|
+
@values[array_attr.key].merge!(
|
75
|
+
DATE_TIME_FIELDS[array_attr.index] => value.send(array_attr.converter)
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
def array_value_converter(str_type)
|
80
|
+
case str_type
|
81
|
+
when 'i'
|
82
|
+
'to_i'
|
83
|
+
else
|
84
|
+
raise "Unknown array type: \"#{str_type}\""
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def date_time_attribute?(key)
|
89
|
+
attr = @model_class.attributes[key]
|
90
|
+
return false unless attr
|
91
|
+
|
92
|
+
raise attr.to_s
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EacRailsUtils
|
4
|
+
module Models
|
5
|
+
module TestUtils
|
6
|
+
# Add more helper methods to be used by all tests here...
|
7
|
+
def valid_invalid_column_values_test(record, column, valid_values, invalid_values)
|
8
|
+
valid_values.each do |v|
|
9
|
+
record.send("#{column}=", v)
|
10
|
+
assert record.valid?,
|
11
|
+
"#{record.errors.messages}, #{column} = #{v.inspect} should be valid"
|
12
|
+
end
|
13
|
+
invalid_values.each do |v|
|
14
|
+
record.send("#{column}=", v)
|
15
|
+
assert_not record.valid?, "#{column} = #{v.inspect} should be invalid"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Verifica falhas em campos específicos de um record
|
20
|
+
def assert_record_errors(record, fields_without_error, fields_with_error)
|
21
|
+
fields_without_error.each do |c|
|
22
|
+
assert record.errors[c].empty?,
|
23
|
+
"Column: #{c} should not have errors (#{record.errors[c]})"
|
24
|
+
end
|
25
|
+
fields_with_error. each do |c|
|
26
|
+
assert_not record.errors[c].empty?, "Column: #{c} should have errors"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Verifica, campo por campo, se invalida o registro.
|
31
|
+
def assert_column_changes(ppp, expected_valid_result, changes)
|
32
|
+
changes.each do |k, v|
|
33
|
+
ppp.send("#{k}=", v)
|
34
|
+
assert_equal expected_valid_result, ppp.valid?,
|
35
|
+
"\"#{k}\" change should be " + (expected_valid_result ? 'valid' : 'invalid')
|
36
|
+
assert_not ppp.errors[k].empty? unless expected_valid_result
|
37
|
+
ppp.restore_attributes
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Ex.: attrs = {a: 1, b: 2} resulta em
|
42
|
+
# [{a: nil, b: nil}, {a: 1, b: nil}, {a: nil, b: 2}, {a: 1, b: 2}].
|
43
|
+
def all_combinations(attrs)
|
44
|
+
combs = [{}]
|
45
|
+
attrs.each do |attr_name, value|
|
46
|
+
combs = all_combinations_new_combination(attr_name, value, combs)
|
47
|
+
end
|
48
|
+
combs
|
49
|
+
end
|
50
|
+
|
51
|
+
def all_combinations_new_combination(attr_name, value, combs)
|
52
|
+
new_comb = []
|
53
|
+
assert_not value.nil?, "#{attr_name}=#{value}"
|
54
|
+
[nil, value].each do |vv|
|
55
|
+
combs.each do |c|
|
56
|
+
cc = c.dup
|
57
|
+
cc[attr_name] = vv
|
58
|
+
new_comb << cc
|
59
|
+
end
|
60
|
+
end
|
61
|
+
new_comb
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_model/associations/hooks'
|
4
|
+
require 'activemodel/associations'
|
5
|
+
|
6
|
+
module EacRailsUtils
|
7
|
+
module Patches
|
8
|
+
module ActiveModelAssociations
|
9
|
+
module ScopeExtensionPatch
|
10
|
+
def add_constraints(scope, owner, association_klass, *extra_args)
|
11
|
+
if extra_args.any?
|
12
|
+
refl = extra_args.first
|
13
|
+
if refl.options[:active_model]
|
14
|
+
target_ids = refl.options[:target_ids]
|
15
|
+
return scope.where(id: owner[target_ids])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module ActiveModel
|
27
|
+
module Associations
|
28
|
+
module Hooks
|
29
|
+
def self.init
|
30
|
+
return unless ::Rails.version < '5'
|
31
|
+
|
32
|
+
ActiveSupport.on_load(:active_record) do
|
33
|
+
ActiveRecord::Associations::AssociationScope.prepend(
|
34
|
+
::EacRailsUtils::Patches::ActiveModelAssociations::ScopeExtensionPatch
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
File without changes
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
module EacRailsUtils
|
6
|
+
module Models
|
7
|
+
class FetchErrorsTest < ActiveSupport::TestCase
|
8
|
+
class M1
|
9
|
+
include ActiveModel::Model
|
10
|
+
include EacRailsUtils::Models::FetchErrors
|
11
|
+
attr_accessor :name, :age, :account, :country_id, :other
|
12
|
+
end
|
13
|
+
|
14
|
+
class M2
|
15
|
+
include ActiveModel::Model
|
16
|
+
attr_accessor :name, :myage, :account_id, :country
|
17
|
+
|
18
|
+
validate :my_validate
|
19
|
+
|
20
|
+
def my_validate
|
21
|
+
errors.add(:name, 'NAME_ERROR')
|
22
|
+
errors.add(:myage, 'MYAGE_ERROR')
|
23
|
+
errors.add(:account_id, 'ACCOUNT_ID_ERROR')
|
24
|
+
errors.add(:country, 'COUNTRY_ERROR')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def setup
|
29
|
+
reset_m1
|
30
|
+
reset_m2
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_fetch_column_errors
|
34
|
+
@m1.fetch_column_errors(@m2, :myage, :age)
|
35
|
+
assert_equal @m2.errors[:myage], @m1.errors[:age]
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_fetch_record_errors
|
39
|
+
@m1.fetch_record_errors(@m2)
|
40
|
+
{ name: :name, account_id: :account, country: :country_id }.each do |c2, c1|
|
41
|
+
assert_equal @m2.errors[c2], @m1.errors[c1], "c2: #{c2}, c1: #{c1}"
|
42
|
+
end
|
43
|
+
assert @m1.errors[:age].empty?
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_fetch_record_errors_with_default_column
|
47
|
+
@m1.fetch_record_errors(@m2, default_column: :other)
|
48
|
+
assert_equal @m2.errors[:name], @m1.errors[:name]
|
49
|
+
assert @m1.errors[:age].empty?
|
50
|
+
assert_equal ['Myage: MYAGE_ERROR'], @m1.errors[:other]
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_fetch_record_errors_with_skip_option
|
54
|
+
@m1.fetch_record_errors(@m2, skip: [:name])
|
55
|
+
assert @m1.errors[:name].empty?
|
56
|
+
assert @m1.errors[:age].empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_fetch_record_errors_by_mapping
|
60
|
+
@m1.fetch_record_errors_by_mapping(@m2, name: :name, myage: :age)
|
61
|
+
assert_equal @m2.errors[:name], @m1.errors[:name]
|
62
|
+
assert_equal @m2.errors[:myage], @m1.errors[:age]
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def reset_m1
|
68
|
+
@m1 = M1.new
|
69
|
+
assert @m1.errors.empty?
|
70
|
+
end
|
71
|
+
|
72
|
+
def reset_m2
|
73
|
+
@m2 = M2.new
|
74
|
+
assert_not @m2.valid?
|
75
|
+
assert_not @m2.errors[:name].empty?
|
76
|
+
assert_not @m2.errors[:myage].empty?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|