shoulda-matchers 3.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +3 -3
  4. data/CONTRIBUTING.md +60 -28
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +15 -12
  7. data/NEWS.md +111 -0
  8. data/README.md +94 -6
  9. data/Rakefile +10 -8
  10. data/custom_plan.rb +88 -0
  11. data/gemfiles/4.0.0.gemfile +1 -0
  12. data/gemfiles/4.0.0.gemfile.lock +21 -18
  13. data/gemfiles/4.0.1.gemfile +1 -0
  14. data/gemfiles/4.0.1.gemfile.lock +21 -18
  15. data/gemfiles/4.1.gemfile +1 -0
  16. data/gemfiles/4.1.gemfile.lock +21 -18
  17. data/gemfiles/4.2.gemfile +1 -0
  18. data/gemfiles/4.2.gemfile.lock +24 -21
  19. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +6 -11
  20. data/lib/shoulda/matchers/active_model.rb +10 -1
  21. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +258 -180
  22. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +45 -0
  23. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_does_not_exist_error.rb +23 -0
  24. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +236 -0
  25. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +62 -0
  26. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +40 -0
  27. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +48 -0
  28. data/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb +14 -0
  29. data/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb +14 -0
  30. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +34 -14
  31. data/lib/shoulda/matchers/active_model/helpers.rb +9 -17
  32. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +13 -6
  33. data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +13 -2
  34. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +19 -35
  35. data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +13 -2
  36. data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +12 -2
  37. data/lib/shoulda/matchers/active_model/qualifiers.rb +12 -0
  38. data/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb +101 -0
  39. data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +21 -0
  40. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +30 -32
  41. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +5 -8
  42. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +22 -22
  43. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +27 -16
  44. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +58 -15
  45. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +22 -12
  46. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +165 -87
  47. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +7 -9
  48. data/lib/shoulda/matchers/active_model/validation_matcher.rb +111 -49
  49. data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +60 -0
  50. data/lib/shoulda/matchers/active_model/validator.rb +71 -52
  51. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +19 -5
  52. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +450 -124
  53. data/lib/shoulda/matchers/util.rb +43 -0
  54. data/lib/shoulda/matchers/util/word_wrap.rb +59 -31
  55. data/lib/shoulda/matchers/version.rb +1 -1
  56. data/script/update_gem_in_all_appraisals +1 -1
  57. data/script/update_gems_in_all_appraisals +1 -1
  58. data/spec/acceptance/multiple_libraries_integration_spec.rb +5 -2
  59. data/spec/acceptance/rails_integration_spec.rb +6 -2
  60. data/spec/spec_helper.rb +1 -3
  61. data/spec/support/acceptance/helpers/step_helpers.rb +4 -1
  62. data/spec/support/tests/current_bundle.rb +21 -7
  63. data/spec/support/unit/active_record/create_table.rb +54 -0
  64. data/spec/support/unit/attribute.rb +47 -0
  65. data/spec/support/unit/capture.rb +6 -0
  66. data/spec/support/unit/change_value.rb +111 -0
  67. data/spec/support/unit/create_model_arguments/basic.rb +135 -0
  68. data/spec/support/unit/create_model_arguments/has_many.rb +15 -0
  69. data/spec/support/unit/create_model_arguments/uniqueness_matcher.rb +74 -0
  70. data/spec/support/unit/helpers/active_record_versions.rb +1 -1
  71. data/spec/support/unit/helpers/class_builder.rb +61 -47
  72. data/spec/support/unit/helpers/database_helpers.rb +5 -3
  73. data/spec/support/unit/helpers/model_builder.rb +77 -97
  74. data/spec/support/unit/helpers/validation_matcher_scenario_helpers.rb +44 -0
  75. data/spec/support/unit/load_environment.rb +12 -0
  76. data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +2 -2
  77. data/spec/support/unit/matchers/fail_with_message_matcher.rb +12 -1
  78. data/spec/support/unit/model_creation_strategies/active_model.rb +111 -0
  79. data/spec/support/unit/model_creation_strategies/active_record.rb +77 -0
  80. data/spec/support/unit/model_creators.rb +19 -0
  81. data/spec/support/unit/model_creators/active_model.rb +39 -0
  82. data/spec/support/unit/model_creators/active_record.rb +43 -0
  83. data/spec/support/unit/model_creators/active_record/has_and_belongs_to_many.rb +95 -0
  84. data/spec/support/unit/model_creators/active_record/has_many.rb +67 -0
  85. data/spec/support/unit/model_creators/active_record/uniqueness_matcher.rb +42 -0
  86. data/spec/support/unit/model_creators/basic.rb +97 -0
  87. data/spec/support/unit/rails_application.rb +1 -1
  88. data/spec/support/unit/record_validating_confirmation_builder.rb +3 -7
  89. data/spec/support/unit/shared_examples/ignoring_interference_by_writer.rb +79 -0
  90. data/spec/support/unit/validation_matcher_scenario.rb +62 -0
  91. data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +4 -0
  92. data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +575 -140
  93. data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +115 -15
  94. data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +42 -4
  95. data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +92 -6
  96. data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +122 -10
  97. data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +306 -58
  98. data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +122 -3
  99. data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +805 -131
  100. data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +196 -29
  101. data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +82 -40
  102. data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +600 -101
  103. data/spec/unit/shoulda/matchers/util/word_wrap_spec.rb +88 -33
  104. data/spec/unit_spec_helper.rb +10 -22
  105. data/zeus.json +11 -0
  106. metadata +64 -23
  107. data/lib/shoulda/matchers/active_model/strict_validator.rb +0 -51
  108. data/spec/support/unit/shared_examples/numerical_type_submatcher.rb +0 -15
  109. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +0 -288
  110. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +0 -100
  111. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +0 -100
  112. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +0 -100
@@ -9,10 +9,12 @@ module UnitTests
9
9
  Tests::Database.instance.adapter_name
10
10
  end
11
11
 
12
- def database_supports_uuid_columns?
12
+ def postgresql?
13
13
  database_adapter == :postgresql
14
14
  end
15
- alias_method :database_supports_array_columns?,
16
- :database_supports_uuid_columns?
15
+
16
+ alias_method :database_supports_array_columns?, :postgresql?
17
+ alias_method :database_supports_uuid_columns?, :postgresql?
18
+ alias_method :database_supports_money_columns?, :postgresql?
17
19
  end
18
20
  end
@@ -2,133 +2,113 @@ require_relative 'class_builder'
2
2
 
3
3
  module UnitTests
4
4
  module ModelBuilder
5
- include ClassBuilder
6
-
7
- def self.configure_example_group(example_group)
8
- example_group.include(self)
9
-
10
- example_group.after do
11
- clear_column_caches
12
- drop_created_tables
13
- end
5
+ def create_table(*args, &block)
6
+ ModelBuilder.create_table(*args, &block)
14
7
  end
15
8
 
16
- def create_table(table_name, options = {}, &block)
17
- connection = ActiveRecord::Base.connection
18
-
19
- begin
20
- connection.execute("DROP TABLE IF EXISTS #{table_name}")
21
- connection.create_table(table_name, options, &block)
22
- created_tables << table_name
23
- connection
24
- rescue Exception => e
25
- connection.execute("DROP TABLE IF EXISTS #{table_name}")
26
- raise e
27
- end
9
+ def define_model(*args, &block)
10
+ ModelBuilder.define_model(*args, &block)
28
11
  end
29
12
 
30
- def define_model_class(class_name, &block)
31
- define_class(class_name, ActiveRecord::Base, &block)
13
+ def define_model_class(*args, &block)
14
+ ModelBuilder.define_model_class(*args, &block)
32
15
  end
33
16
 
34
- def define_active_model_class(class_name, options = {}, &block)
35
- accessors = options.fetch(:accessors, [])
36
-
37
- define_class(class_name) do
38
- include ActiveModel::Validations
17
+ def define_active_model_class(*args, &block)
18
+ ModelBuilder.define_active_model_class(*args, &block)
19
+ end
39
20
 
40
- def initialize(attributes = {})
41
- attributes.each do |name, value|
42
- __send__("#{name}=", value)
43
- end
44
- end
21
+ class << self
22
+ def configure_example_group(example_group)
23
+ example_group.include(self)
45
24
 
46
- accessors.each do |column|
47
- attr_accessor column.to_sym
25
+ example_group.after do
26
+ ModelBuilder.reset
48
27
  end
28
+ end
49
29
 
50
- if block_given?
51
- class_eval(&block)
52
- end
30
+ def reset
31
+ clear_column_caches
32
+ drop_created_tables
33
+ created_tables.clear
34
+ defined_models.clear
53
35
  end
54
- end
55
36
 
56
- def define_model(name, columns = {}, &block)
57
- class_name = name.to_s.pluralize.classify
58
- table_name = class_name.tableize.gsub('/', '_')
59
-
60
- table_block = lambda do |table|
61
- columns.each do |column_name, specification|
62
- if specification.is_a?(Hash)
63
- column_type = specification[:type]
64
- column_options = specification.fetch(:options, {})
65
- else
66
- column_type = specification
67
- column_options = {}
68
- end
69
-
70
- begin
71
- table.__send__(column_type, column_name, column_options)
72
- rescue NoMethodError
73
- raise NoMethodError, "#{Tests::Database.instance.adapter_class} does not support :#{column_type} columns"
74
- end
37
+ def create_table(table_name, options = {}, &block)
38
+ connection = ::ActiveRecord::Base.connection
39
+
40
+ begin
41
+ connection.execute("DROP TABLE IF EXISTS #{table_name}")
42
+ connection.create_table(table_name, options, &block)
43
+ created_tables << table_name
44
+ connection
45
+ rescue Exception => e
46
+ connection.execute("DROP TABLE IF EXISTS #{table_name}")
47
+ raise e
75
48
  end
76
49
  end
77
50
 
78
- if columns.key?(:id) && columns[:id] == false
79
- columns.delete(:id)
80
- create_table(table_name, id: false, &table_block)
81
- else
82
- create_table(table_name, &table_block)
51
+ def define_model_class(class_name, &block)
52
+ ClassBuilder.define_class(class_name, ::ActiveRecord::Base, &block)
83
53
  end
84
54
 
85
- model = define_model_class(class_name).tap do |m|
86
- if block
87
- if block.arity == 0
88
- m.class_eval(&block)
89
- else
90
- block.call(m)
91
- end
55
+ def define_active_model_class(class_name, options = {}, &block)
56
+ attribute_names = options.delete(:accessors) { [] }
57
+
58
+ columns = attribute_names.reduce({}) do |hash, attribute_name|
59
+ hash.merge(attribute_name => nil)
92
60
  end
93
61
 
94
- m.table_name = table_name
62
+ UnitTests::ModelCreationStrategies::ActiveModel.call(
63
+ 'Example',
64
+ columns,
65
+ options,
66
+ &block
67
+ )
95
68
  end
96
69
 
97
- defined_models << model
70
+ def define_model(name, columns = {}, options = {}, &block)
71
+ model = UnitTests::ModelCreationStrategies::ActiveRecord.call(
72
+ name,
73
+ columns,
74
+ options,
75
+ &block
76
+ )
77
+ defined_models << model
78
+ model
79
+ end
98
80
 
99
- model
100
- end
81
+ private
101
82
 
102
- private
83
+ def clear_column_caches
84
+ # Rails 4.x
85
+ if ::ActiveRecord::Base.connection.respond_to?(:schema_cache)
86
+ ::ActiveRecord::Base.connection.schema_cache.clear!
87
+ # Rails 3.1 - 4.0
88
+ elsif ::ActiveRecord::Base.connection_pool.respond_to?(:clear_cache!)
89
+ ::ActiveRecord::Base.connection_pool.clear_cache!
90
+ end
103
91
 
104
- def clear_column_caches
105
- # Rails 4.x
106
- if ActiveRecord::Base.connection.respond_to?(:schema_cache)
107
- ActiveRecord::Base.connection.schema_cache.clear!
108
- # Rails 3.1 - 4.0
109
- elsif ActiveRecord::Base.connection_pool.respond_to?(:clear_cache!)
110
- ActiveRecord::Base.connection_pool.clear_cache!
92
+ defined_models.each do |model|
93
+ model.reset_column_information
94
+ end
111
95
  end
112
96
 
113
- defined_models.each do |model|
114
- model.reset_column_information
115
- end
116
- end
97
+ def drop_created_tables
98
+ connection = ::ActiveRecord::Base.connection
117
99
 
118
- def drop_created_tables
119
- connection = ActiveRecord::Base.connection
120
-
121
- created_tables.each do |table_name|
122
- connection.execute("DROP TABLE IF EXISTS #{table_name}")
100
+ created_tables.each do |table_name|
101
+ connection.execute("DROP TABLE IF EXISTS #{table_name}")
102
+ end
123
103
  end
124
- end
125
104
 
126
- def created_tables
127
- @_created_tables ||= []
128
- end
105
+ def created_tables
106
+ @_created_tables ||= []
107
+ end
129
108
 
130
- def defined_models
131
- @_defined_models ||= []
109
+ def defined_models
110
+ @_defined_models ||= []
111
+ end
132
112
  end
133
113
  end
134
114
  end
@@ -0,0 +1,44 @@
1
+ module UnitTests
2
+ module ValidationMatcherScenarioHelpers
3
+ def self.configure_example_group(example_group)
4
+ example_group.include(self)
5
+ end
6
+
7
+ def build_scenario_for_validation_matcher(args)
8
+ UnitTests::ValidationMatcherScenario.new(
9
+ build_validation_matcher_scenario_args(args)
10
+ )
11
+ end
12
+
13
+ protected
14
+
15
+ def validation_matcher_scenario_args
16
+ {}
17
+ end
18
+
19
+ def configure_validation_matcher(matcher)
20
+ matcher
21
+ end
22
+
23
+ private
24
+
25
+ def build_validation_matcher_scenario_args(args)
26
+ args.
27
+ deep_merge(validation_matcher_scenario_args).
28
+ deep_merge(
29
+ matcher_name: matcher_name,
30
+ matcher_proc: method(matcher_name)
31
+ )
32
+ end
33
+
34
+ def matcher_name
35
+ validation_matcher_scenario_args.fetch(:matcher_name) do
36
+ raise KeyNotFoundError.new(<<-MESSAGE)
37
+ Please implement #validation_matcher_scenario_args in your example
38
+ group, in such a way that it returns a hash that contains a
39
+ :matcher_name key.
40
+ MESSAGE
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,12 @@
1
+ require_relative '../tests/current_bundle'
2
+ require_relative 'rails_application'
3
+
4
+ Tests::CurrentBundle.instance.assert_appraisal!
5
+
6
+ $test_app = UnitTests::RailsApplication.new
7
+ $test_app.create
8
+ $test_app.load
9
+
10
+ require 'active_record/base'
11
+
12
+ ENV['RAILS_ENV'] = 'test'
@@ -24,10 +24,10 @@ module UnitTests
24
24
  lines << Shoulda::Matchers::Util.indent(expected, 2)
25
25
 
26
26
  if @actual
27
- lines << 'Actually failed with:'
27
+ lines << 'The full message was:'
28
28
  lines << Shoulda::Matchers::Util.indent(@actual, 2)
29
29
  else
30
- lines << 'However, the expectation did not fail.'
30
+ lines << 'However, the expectation did not fail at all.'
31
31
  end
32
32
 
33
33
  lines.join("\n")
@@ -26,8 +26,13 @@ module UnitTests
26
26
  if @actual
27
27
  lines << 'Actually failed with:'
28
28
  lines << Shoulda::Matchers::Util.indent(@actual, 2)
29
+ lines << "Diff:"
30
+ lines << Shoulda::Matchers::Util.indent(
31
+ differ.diff(@actual, expected)[1..-1],
32
+ 2
33
+ )
29
34
  else
30
- lines << 'However, the expectation did not fail.'
35
+ lines << 'However, the expectation did not fail at all.'
31
36
  end
32
37
 
33
38
  lines.join("\n")
@@ -46,6 +51,12 @@ module UnitTests
46
51
  def failure_message_for_should_not
47
52
  failure_message_when_negated
48
53
  end
54
+
55
+ private
56
+
57
+ def differ
58
+ @_differ ||= RSpec::Support::Differ.new
59
+ end
49
60
  end
50
61
  end
51
62
  end
@@ -0,0 +1,111 @@
1
+ module UnitTests
2
+ module ModelCreationStrategies
3
+ class ActiveModel
4
+ def self.call(name, columns = {}, options = {}, &block)
5
+ new(name, columns, options, &block).call
6
+ end
7
+
8
+ def initialize(name, columns = {}, options = {}, &block)
9
+ @name = name
10
+ @columns = columns
11
+ @options = options
12
+ @model_customizers = []
13
+
14
+ if block
15
+ customize_model(&block)
16
+ end
17
+ end
18
+
19
+ def customize_model(&block)
20
+ model_customizers << block
21
+ end
22
+
23
+ def call
24
+ ClassBuilder.define_class(name, Model).tap do |model|
25
+ model.columns = columns.keys
26
+
27
+ model_customizers.each do |block|
28
+ run_block(model, block)
29
+ end
30
+ end
31
+ end
32
+
33
+ protected
34
+
35
+ attr_reader :name, :columns, :model_customizers, :options
36
+
37
+ private
38
+
39
+ def run_block(model, block)
40
+ if block
41
+ if block.arity == 0
42
+ model.class_eval(&block)
43
+ else
44
+ block.call(model)
45
+ end
46
+ end
47
+ end
48
+
49
+ class Model
50
+ class << self
51
+ def columns
52
+ @_columns ||= []
53
+ end
54
+
55
+ def columns=(columns)
56
+ existing_columns = self.columns
57
+ new_columns = columns - existing_columns
58
+
59
+ @_columns += new_columns
60
+
61
+ include attributes_module
62
+
63
+ attributes_module.module_eval do
64
+ new_columns.each do |column|
65
+ define_method(column) do
66
+ attributes[column]
67
+ end
68
+
69
+ define_method("#{column}=") do |value|
70
+ attributes[column] = value
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def attributes_module
79
+ @_attributes_module ||= Module.new
80
+ end
81
+ end
82
+
83
+ include ::ActiveModel::Model
84
+
85
+ attr_reader :attributes
86
+
87
+ def initialize(attributes = {})
88
+ @attributes = attributes.symbolize_keys
89
+ end
90
+
91
+ def inspect
92
+ middle = '%s:0x%014x%s' % [
93
+ self.class,
94
+ object_id * 2,
95
+ ' ' + inspected_attributes.join(' ')
96
+ ]
97
+
98
+ "#<#{middle.strip}>"
99
+ end
100
+
101
+ private
102
+
103
+ def inspected_attributes
104
+ self.class.columns.map do |key, value|
105
+ "#{key}: #{attributes[key].inspect}"
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,77 @@
1
+ module UnitTests
2
+ module ModelCreationStrategies
3
+ class ActiveRecord
4
+ def self.call(name, columns = {}, options = {}, &block)
5
+ new(name, columns, options, &block).call
6
+ end
7
+
8
+ def initialize(name, columns = {}, options = {}, &block)
9
+ @name = name
10
+ @columns = columns
11
+ @options = options
12
+ @model_customizers = []
13
+
14
+ if block
15
+ customize_model(&block)
16
+ end
17
+ end
18
+
19
+ def customize_model(&block)
20
+ model_customizers << block
21
+ end
22
+
23
+ def call
24
+ create_table_for_model
25
+ define_class_for_model
26
+ end
27
+
28
+ protected
29
+
30
+ attr_reader :columns, :model_customizers, :name, :options
31
+
32
+ private
33
+
34
+ def create_table_for_model
35
+ UnitTests::ActiveRecord::CreateTable.call(table_name, columns)
36
+ end
37
+
38
+ def define_class_for_model
39
+ model = UnitTests::ModelBuilder.define_model_class(class_name)
40
+
41
+ model_customizers.each do |block|
42
+ run_block(model, block)
43
+ end
44
+
45
+ if whitelist_attributes?
46
+ model.attr_accessible(*columns.keys)
47
+ end
48
+
49
+ model.table_name = table_name
50
+
51
+ model
52
+ end
53
+
54
+ def run_block(model, block)
55
+ if block
56
+ if block.arity == 0
57
+ model.class_eval(&block)
58
+ else
59
+ block.call(model)
60
+ end
61
+ end
62
+ end
63
+
64
+ def class_name
65
+ name.to_s.pluralize.classify
66
+ end
67
+
68
+ def table_name
69
+ class_name.tableize.gsub('/', '_')
70
+ end
71
+
72
+ def whitelist_attributes?
73
+ options.fetch(:whitelist_attributes, true)
74
+ end
75
+ end
76
+ end
77
+ end