Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Active records before_type_cast
1. The Calm Before the Cast
Understanding ActiveRecord's Casting
2. What is Casting?
Casting is a manufacturing process by which a
liquid material is usually poured into a mold
In computer science it is the explicit changing
of the data type of a given entity
e.g, casting a string into an array:
Array("foo") # => ["foo"]
3. ActiveRecord's Casting
Extending the ActiveRecord::Base class
creates attribute accessors that map to a given
database table's columns
The column type in the database dictates the
data type of the returned value
Database data types != Ruby data types
4. ActiveRecord's Type Casting
System
bundle open activerecord
Database specific adapters read column
definitions (extend abstract):
lib/active_record/connection_adapters/postgres
ql_adapter.rb|74
These are cast to Ruby classes:
lib/active_record/connection_adapters/abstract/
schema_definitions.rb|70
5. CREATE TABLE foo (
bar integer,
baz character varying(255),
qux timestamp without time zone
);
SELECT * FROM foo WHERE id=1;
Casting occurs here
{ Abstract adapter
Postgres adapter
Foo.find(1) # =>
#<Foo bar: 1, baz "a", qux: "2012-03-
06 12:00:00">
6. What happens when this implicit
type casting fails?
# == Schema Information
# bar :integer
# qux :datetime
class Foo < ActiveRecord::Base; end
$ Foo.new(:bar => 'a', :qux => 'cheezburger')
#<Foo bar: 0, qux: nil>
8. What About Validations?
ActiveRecord has some validations, such as
Integer's "validates :numericality => true" (is
this even a real word?!)
But not all data types have validations e.g.
DateTime
A nil value for datetime after the type cast may
silently pass validation, losing a user's input
without notice
9. Before the Cast:
ActiveRecord provides dynamic methods that
hold a value before and after the type cast:
a = Foo.new(:bar => 'a', :qux => 'cheezburger')
a.qux # nil
a.qux_before_type_cast # "cheezburger"
10. Lets Write our Own Validator
class Foo < ActiveRecord::Base
validate :datetime_value_is_castable
def datetime_value_is_castable
begin
DateTime.parse(qux_before_type_cast)
rescue ArgumentError
errors.add(:qux, "is not a valid date format")
end
end
end
11. And The Exciting Conclusion
a = Foo.new(:qux => 'cheezburger')
a.valid? # => false
a.errors # => { :qux => ["is not a valid date
format" ]}
Now the user can be alerted that their value is
invalid, without it being silently discarded
12. Questions/Comments
Ben Simpson
ben@mojotech.com
http://mrfrosti.com
@mrfrosti