diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d4d74d..a1f6b30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,13 @@ ### Changed - Exposed `.find_by` as a public method for more complex querying of models, and to allow people to write their own custom filters on top of this method +- Hyphenated keys when passed into `.create` or `#update` will now be converted to underscores to ensure consistency with +ruby conventions and to prevent issues with helper generation +- `.with_email` filter now supports `email_address`, `email` and `email-address` key names for better flexibility when +filtering on email addresses ### Fixed +- Hyphenated keys are not permitted for the `primary_key` setting as this will cause issues with ruby ### Security diff --git a/lib/testing_record.rb b/lib/testing_record.rb index e25bf9f..caa591f 100644 --- a/lib/testing_record.rb +++ b/lib/testing_record.rb @@ -18,6 +18,7 @@ def configure # Configure a default primary key for all TestingRecord models def default_primary_key=(value) raise InvalidConfigurationError, 'Invalid primary key value, must be a Symbol' unless value.is_a?(Symbol) + raise InvalidConfigurationError, 'Primary key value cannot contain `-` please use `_` instead' if value.to_s.include?('-') @default_primary_key = value TestingRecord::Model.primary_key value diff --git a/lib/testing_record/dsl/builder/filters.rb b/lib/testing_record/dsl/builder/filters.rb index ebda919..6ff4a48 100644 --- a/lib/testing_record/dsl/builder/filters.rb +++ b/lib/testing_record/dsl/builder/filters.rb @@ -31,7 +31,12 @@ def find_by(attributes) # # @return [TestingRecord::Model, nil] def with_email(email_address) - find_by({ email_address: })&.first&.tap { |entity| entity.class.current = entity } + email_address_results = + find_by({ email_address: }).first || + find_by({ email: email_address }).first || + find_by({ 'email-address': email_address }).first + + email_address_results&.tap { |entity| entity.class.current = entity } end # Checks to see whether an entity exists with the provided id diff --git a/lib/testing_record/model.rb b/lib/testing_record/model.rb index 6c96a3e..25fd59b 100644 --- a/lib/testing_record/model.rb +++ b/lib/testing_record/model.rb @@ -25,7 +25,7 @@ class << self # # @return [TestingRecord::Model] def create(attributes) - attributes.transform_keys!(&:to_sym) + attributes.transform_keys! { |key| key.to_s.tr('-', '_').to_sym } if respond_to?(:all) create_with_caching(attributes) else @@ -135,7 +135,7 @@ def to_s # # @return [TestingRecord::Model] def update(attrs) - attrs.transform_keys(&:to_sym).each do |key, value| + attrs.transform_keys! { |key| key.to_s.tr('-', '_').to_sym }.each do |key, value| attributes[key] = value instance_variable_set("@#{key}", value) TestingRecord.logger.info("Updated '#{key}' on the #{self.class} entity to be '#{value}'") diff --git a/spec/testing_record/dsl/builder/filters_spec.rb b/spec/testing_record/dsl/builder/filters_spec.rb index b239148..9a3624c 100644 --- a/spec/testing_record/dsl/builder/filters_spec.rb +++ b/spec/testing_record/dsl/builder/filters_spec.rb @@ -5,6 +5,10 @@ Class.new(TestingRecord::Model) do caching :enabled primary_key :email_address + + def self.name + 'FakeModel' + end end end @@ -36,7 +40,7 @@ end end - context 'when entity exists' do + context 'when entity exists with an `email_address` key' do before do model_klazz.create({ email_address: 'foo@bar.com' }) model_klazz.create({ email_address: 'baz@bar.com' }) @@ -46,6 +50,29 @@ expect(model_klazz.with_email('foo@bar.com')).to be_a TestingRecord::Model end end + + context 'when entity exists with an `email-address` key' do + before do + model_klazz.create({ 'email-address': 'foo@bar.com' }) + model_klazz.create({ 'email-address': 'baz@bar.com' }) + end + + it 'finds the first matching model (which is stored as a snake_cased key)' do + expect(model_klazz.with_email('foo@bar.com')).to be_a TestingRecord::Model + end + end + + context 'when entity exists with an `email` key' do + before do + model_klazz.primary_key :email + model_klazz.create({ email: 'foo@bar.com' }) + model_klazz.create({ email: 'baz@bar.com' }) + end + + it 'finds the first matching model' do + expect(model_klazz.with_email('foo@bar.com')).to be_a TestingRecord::Model + end + end end describe '.find_by' do diff --git a/spec/testing_record/model_spec.rb b/spec/testing_record/model_spec.rb index 90737be..7a61449 100644 --- a/spec/testing_record/model_spec.rb +++ b/spec/testing_record/model_spec.rb @@ -85,6 +85,21 @@ expect(primary_model_entity).to respond_to(:attributes, :id, :foo, :bar) end end + + context 'with any hyphenated keys' do + before do + FakeModel.caching :enabled + FakeModel.create({ id: 1, snake_case: :whatever, 'hyphenated-case': :no_op, 'hyphenated-case-two': :no_op }) + end + + it 'stores the hyphenated keys as snake_cased keys in the attributes hash' do + expect(FakeModel.current.attributes).to eq({ hyphenated_case: :no_op, hyphenated_case_two: :no_op, id: 1, snake_case: :whatever }) + end + + it 'stores the hyphenated keys as snake_cased reader methods' do + expect(FakeModel.current).to respond_to(:hyphenated_case, :hyphenated_case_two) + end + end end describe '.current=' do