From 7a9fc99390bbf863b36715ac3c88e807df74c05f Mon Sep 17 00:00:00 2001 From: Andy Pike Date: Wed, 29 Mar 2017 17:05:53 +0100 Subject: [PATCH] Add Form#attributes_with_values and support dashes in param keys --- Gemfile.lock | 2 +- lib/rectify.rb | 1 + lib/rectify/form.rb | 6 +- lib/rectify/format_attributes_hash.rb | 26 ++++++++ lib/rectify/version.rb | 2 +- spec/lib/rectify/form_spec.rb | 87 +++++++++++++++++---------- 6 files changed, 89 insertions(+), 35 deletions(-) create mode 100644 lib/rectify/format_attributes_hash.rb diff --git a/Gemfile.lock b/Gemfile.lock index e8c14dd..840063b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,7 +8,7 @@ GIT PATH remote: . specs: - rectify (0.8.0) + rectify (0.9.0) activemodel (>= 4.1.0) activerecord (>= 4.1.0) activesupport (>= 4.1.0) diff --git a/lib/rectify.rb b/lib/rectify.rb index 3d2035e..530936d 100644 --- a/lib/rectify.rb +++ b/lib/rectify.rb @@ -9,6 +9,7 @@ require "rectify/version" require "rectify/form" require "rectify/form_attribute" +require "rectify/format_attributes_hash" require "rectify/build_form_from_model" require "rectify/command" require "rectify/presenter" diff --git a/lib/rectify/form.rb b/lib/rectify/form.rb index 2019326..d2e96c3 100644 --- a/lib/rectify/form.rb +++ b/lib/rectify/form.rb @@ -19,7 +19,7 @@ def self.from_params(params, additional_params = {}) convert_indexed_hashes_to_arrays(attributes_hash) - new(attributes_hash) + new(FormatAttributesHash.new.format(attributes_hash)) end def self.convert_indexed_hashes_to_arrays(attributes_hash) @@ -93,6 +93,10 @@ def attributes super.except(:id) end + def attributes_with_values + attributes.reject { |attribute| public_send(attribute).nil? } + end + def map_model(model) # Implement this in your form object for custom mapping from model to form # object as part of the `.from_model` call after matching attributes are diff --git a/lib/rectify/format_attributes_hash.rb b/lib/rectify/format_attributes_hash.rb new file mode 100644 index 0000000..810fb7a --- /dev/null +++ b/lib/rectify/format_attributes_hash.rb @@ -0,0 +1,26 @@ +# Based on http://stackoverflow.com/questions/8706930/converting-nested-hash-keys-from-camelcase-to-snake-case-in-ruby + +module Rectify + class FormatAttributesHash + def format(params) + convert_hash_keys(params) + end + + private + + def convert_hash_keys(value) + case value + when Array + value.map { |v| convert_hash_keys(v) } + when Hash + Hash[value.map { |k, v| [underscore_key(k), convert_hash_keys(v)] }] + else + value + end + end + + def underscore_key(k) + k.to_s.underscore.to_sym + end + end +end diff --git a/lib/rectify/version.rb b/lib/rectify/version.rb index 1910688..6818b5f 100644 --- a/lib/rectify/version.rb +++ b/lib/rectify/version.rb @@ -1,3 +1,3 @@ module Rectify - VERSION = "0.8.0".freeze + VERSION = "0.9.0".freeze end diff --git a/spec/lib/rectify/form_spec.rb b/spec/lib/rectify/form_spec.rb index 3f77451..eb64438 100644 --- a/spec/lib/rectify/form_spec.rb +++ b/spec/lib/rectify/form_spec.rb @@ -88,6 +88,19 @@ expect(form.contacts[2].number).to eq("789") end + it "converts param keys with dashes to underscores" do + params = ActionController::Parameters.new( + "id" => "1", + "user" => { + "first-name" => "Andy" + } + ) + + form = UserForm.from_params(params) + + expect(form.first_name).to eq("Andy") + end + it "populates an indexed array of attributes" do params = ActionController::Parameters.new( "user" => { @@ -135,36 +148,6 @@ expect { form.some_extra_data }.to raise_error(NoMethodError) end - - context "when a model is explicitally mimicked" do - it "returns the matching model name" do - expect(ChildForm.model_name.name).to eq("User") - end - end - - context "when a model is not explicitally mimicked" do - describe "#model_name" do - it "returns the class name minus the `Form` suffix" do - expect(OrderForm.model_name.name).to eq("Order") - end - - it "returns the class name minus the `Form` suffix and namespace" do - expect(Inventory::ProductForm.model_name.name).to eq("Product") - end - end - - it "uses the class name minus the `Form` suffix as the params key" do - order_params = { - "order" => { - "number" => "12345" - } - } - - form = OrderForm.from_params(order_params) - - expect(form.number).to eq("12345") - end - end end describe ".from_model" do @@ -249,8 +232,32 @@ end describe ".model_name" do - it "allows a form to mimic a model" do - expect(UserForm.model_name.name).to eq("User") + context "when a model is explicitally mimicked" do + it "returns the matching model name" do + expect(ChildForm.model_name.name).to eq("User") + end + end + + context "when a model is not explicitally mimicked" do + it "returns the class name minus the `Form` suffix" do + expect(OrderForm.model_name.name).to eq("Order") + end + + it "returns the class name minus the `Form` suffix and namespace" do + expect(Inventory::ProductForm.model_name.name).to eq("Product") + end + end + + it "uses the class name minus the `Form` suffix as the params key" do + order_params = { + "order" => { + "number" => "12345" + } + } + + form = OrderForm.from_params(order_params) + + expect(form.number).to eq("12345") end end @@ -296,6 +303,22 @@ end end + describe "#attributes_with_values" do + it "returns a hash of attributes where their values are non-nil" do + form = AddressForm.new( + :id => 1, + :street => "1 High Street", + :town => nil, + :post_code => "GU1 2AB" + ) + + expect(form.attributes_with_values).to eq( + :street => "1 High Street", + :post_code => "GU1 2AB" + ) + end + end + context "when being used with a form builder" do describe "#to_key" do it "returns an array containing the id" do