Skip to content

v4.0.0

Compare
Choose a tag to compare
@AaronLasseigne AaronLasseigne released this 10 Jan 22:34

Changed

  • drop support for Ruby < 2.5, added support for Ruby 3.0
  • drop support for Rails < 5.0, added support for Rails 6.1
  • #398 - Predicate methods have been removed.
  • #412 - Filters will now treat blank string values as nil
    (except string and symbol).
  • #392 - Integer parsing now defaults the base to 10.
  • The inputs method now returns an ActiveInteraction::Input instead of a
    hash. The ActiveInteraction::Input class still responds to all hash methods.
  • The object and record filters now only accept an instance of the correct
    class type or a subclass of the correct class. They no longer allow you to
    check for included modules.
  • The interface filter will now look for an ancestor of the value passed
    based on the name of the interface or the value passed in the from option.
  • The InvalidClassError has been replaced by InvalidNameError.
  • When introspecting an array filter, the inner filter is referenced by :'0'
    instead of the singularized version of the array filter name.

Added

  • Implicit coercion of types are now supported in filters (e.g. to_str, to_int,
    etc).
  • The interface and record filters, when used as an inner filter for an
    array, will have their from/class option set to a singularized version of
    the array filter name.

Upgrading

Predicate Methods

We've removed the predicate methods that were automatically generated for each
input. They would return true if an input was not nil. They can be manually
replaced with that same check.

# v3.8
class Example < ActiveInteraction::Base
  string :first_name

  validates :first_name,
    presence: true,
    if: :first_name?

  def execute
    # ...
  end
end

# v4.0
class Example < ActiveInteraction::Base
  string :first_name

  validates :first_name,
    presence: true,
    unless: 'first_name.nil?'

  def execute
    # ...
  end
end

Blank Values Treated As nil For Filters

In an effort to improve form support, strings that are blank? will
be converted into nil for all filters except string and symbol.
Previously, blank strings would have cased :invalid_type errors but
they'll now cause a :missing error which should be more form
friendly. If the filter has a default, the blank string will cause
the default to be used.

class Example < ActiveInteraction::Base
  integer :i
  boolean :b, default: false

  def execute
    [i, b]
  end
end

# v3.8
Example.run(i: '', b: '').errors.details
=> {:i=>[{:error=>:invalid_type, :type=>"integer"}], :b=>[{:error=>:invalid_type, :type=>"boolean"}]}

# v4.0
Example.run(i: '', b: '').errors.details
=> {:i=>[{:error=>:missing}]}

# v3.8
Example.run(i: 0, b: '').errors.details
=> {:b=>[{:error=>:invalid_type, :type=>"boolean"}]}

# v4.0
Example.run(i: 0, b: '').errors.details
=> {}

Example.run(i: 0, b: '').result
=> [0, false] # the default is used for `:b`

Integer Parsing Base Now 10

Integers are parsed using Integer. By default this meant that when
strings were parsed, radix indicators (0, 0b, and 0x) were honored. Now
we're defaulting the base to 10. This means all strings will be parsed
as though they are base 10.

class Example < ActiveInteraction::Base
  integer :x

  def execute
    x
  end
end

# v3.8
Example.run!(x: '010')
# => 8

# v4.0
Example.run!(x: '010')
# => 10

If you want the old behavior that respected the radix you can pass 0
as the base.

- integer :x
+ integer :x, base: 0

With that change, we can see the radix is respected again.

# v4.0.0
Example.run!(x: '010')
# => 8

Object and Record Filter Changes

The object and record filters used to be able to check for included modules
in addition to a class type. This has been removed. If you want any object that
has a particular module included, you'll need to use the newly expanded
interface filter.