From 3f1f5e4b2c08bd1f7f6578eac1e9a0061b374cef Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Sat, 22 Jul 2023 08:50:45 -0700 Subject: [PATCH 1/2] Refactor allow_blank escape hatch to work better with params. Fixes #954 --- spec/avram/operations/save_operation_spec.cr | 27 +++++++++++++++----- spec/support/models/comment.cr | 2 +- src/avram/add_column_attributes.cr | 6 +++-- src/avram/attribute.cr | 1 + src/avram/model.cr | 4 +-- src/avram/validations.cr | 2 +- 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/spec/avram/operations/save_operation_spec.cr b/spec/avram/operations/save_operation_spec.cr index 0d5d235f2..99b77de79 100644 --- a/spec/avram/operations/save_operation_spec.cr +++ b/spec/avram/operations/save_operation_spec.cr @@ -83,13 +83,9 @@ private class SavePost < Post::SaveOperation end # This is to test an escape hatch where you don't want to -# define a Nil type, but your field is optional +# define a Nil type, but your String field can be an empty string private class AllowBlankComment < Comment::SaveOperation - skip_default_validations - - before_save do - body.allow_blank = true - end + permit_columns body, post_id end module DefaultUserValidations @@ -922,6 +918,15 @@ describe "Avram::SaveOperation" do comment.body.should eq("") end end + it "allows blank strings from params" do + post = PostFactory.create + params = build_params({comment: {post_id: post.id, body: ""}}.to_json, content_type: "application/json") + AllowBlankComment.create(params) do |op, new_comment| + op.valid?.should be_true + comment = new_comment.as(Comment) + comment.body.should eq("") + end + end it "still allows normal data to be saved" do post = PostFactory.create AllowBlankComment.create(post_id: post.id, body: "not blank") do |op, new_comment| @@ -930,13 +935,21 @@ describe "Avram::SaveOperation" do comment.body.should eq("not blank") end end - it "fails at postgres when saving nil" do + it "fails at postgres when saving nil from named args" do post = PostFactory.create expect_raises(PQ::PQError) do AllowBlankComment.create(post_id: post.id) do |_op, _new_comment| end end end + it "fails at postgres when saving nil from params" do + post = PostFactory.create + params = build_params({comment: {post_id: post.id}}.to_json, content_type: "application/json") + expect_raises(PQ::PQError) do + AllowBlankComment.create(params) do |_op, _new_comment| + end + end + end end end diff --git a/spec/support/models/comment.cr b/spec/support/models/comment.cr index 49784a1b0..66934fb07 100644 --- a/spec/support/models/comment.cr +++ b/spec/support/models/comment.cr @@ -4,7 +4,7 @@ class Comment < BaseModel table do primary_key custom_id : Int64 timestamps - column body : String + column body : String, allow_blank: true belongs_to post : Post end end diff --git a/src/avram/add_column_attributes.cr b/src/avram/add_column_attributes.cr index 465c6845f..c53764dc4 100644 --- a/src/avram/add_column_attributes.cr +++ b/src/avram/add_column_attributes.cr @@ -56,7 +56,9 @@ module Avram::AddColumnAttributes name: :{{ attribute[:name].id }}, param: permitted_params["{{ attribute[:name] }}"]?, value: value, - param_key: self.class.param_key) + param_key: self.class.param_key).tap do |attr| + attr.allow_blank = {{ attribute[:allow_blank] }} + end end private def default_value_for_{{ attribute[:name] }} @@ -96,7 +98,7 @@ module Avram::AddColumnAttributes def set_{{ attribute[:name] }}_from_param(_value) # In nilable types, `nil` is ok, and non-nilable types we will get the # "is required" error. - if _value.blank? + if _value.blank? && !{{ attribute[:name] }}.allow_blank? {{ attribute[:name] }}.value = nil return end diff --git a/src/avram/attribute.cr b/src/avram/attribute.cr index c40496040..f17fafad3 100644 --- a/src/avram/attribute.cr +++ b/src/avram/attribute.cr @@ -19,6 +19,7 @@ class Avram::Attribute(T) def permitted @_permitted ||= begin Avram::PermittedAttribute(T).new(name: @name, param: @param, value: @value, param_key: @param_key).tap do |attribute| + attribute.allow_blank = allow_blank? errors.each do |error| attribute.add_error error end diff --git a/src/avram/model.cr b/src/avram/model.cr index 251a28180..c9c211447 100644 --- a/src/avram/model.cr +++ b/src/avram/model.cr @@ -243,7 +243,7 @@ abstract class Avram::Model {% end %} end - macro column(type_declaration, autogenerated = false, serialize is_serialized = false) + macro column(type_declaration, autogenerated = false, serialize is_serialized = false, allow_blank = false) {% if type_declaration.type.is_a?(Union) %} {% data_type = type_declaration.type.types.first %} {% nilable = true %} @@ -257,7 +257,7 @@ abstract class Avram::Model {% value = nil %} {% end %} - {% COLUMNS << {name: type_declaration.var, type: data_type, nilable: nilable.id, autogenerated: autogenerated, value: value, serialized: is_serialized} %} + {% COLUMNS << {name: type_declaration.var, type: data_type, nilable: nilable.id, autogenerated: autogenerated, value: value, serialized: is_serialized, allow_blank: allow_blank} %} end macro setup_column_info_methods(columns, *args, **named_args) diff --git a/src/avram/validations.cr b/src/avram/validations.cr index 3cd6b4693..a7cacfd7d 100644 --- a/src/avram/validations.cr +++ b/src/avram/validations.cr @@ -93,7 +93,7 @@ module Avram::Validations ) : Bool no_errors = true attributes.each do |attribute| - if attribute.value.blank_for_validates_required? + if attribute.value.blank_for_validates_required? && !attribute.allow_blank? attribute.add_error(message) no_errors = false end From 94880a79f9c9cec14acc55e3bdc96767cc7caf26 Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Sat, 22 Jul 2023 09:23:20 -0700 Subject: [PATCH 2/2] using ameba master so we can get green until they do another release --- shard.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shard.yml b/shard.yml index a329706c5..ef9a10b49 100644 --- a/shard.yml +++ b/shard.yml @@ -44,7 +44,8 @@ dependencies: development_dependencies: ameba: github: crystal-ameba/ameba - version: ~> 1.4 + branch: master + # version: ~> 1.4 lucky: github: luckyframework/lucky version: ">= 1.0.0"