valeriy prokopchuk: validators in migrations
Post on 13-Jul-2015
82 Views
Preview:
TRANSCRIPT
# Migration Validators
Data should always be consistent
by Valeriy Prokopchuk. Sphere Consulting Inc.
# Data validation in RoR app
????
ActiveRecord: Validation helpers
Data Tier
Application Tier
Presentation Tier JS: Form Validations
Controller validations, ActiveRecord validations
???
# DB Constraints. Out of the box
● Unique, Not Null, Primary Key, Default:
create_table, { primary_key: :primary_key_column } do |t|
t.integer int_column, nil: false, default: 5
end
add_index :table_name, :int_column, unique: true
# DB Constraints. Foreign Keys
● Rails < 4
https://github.com/matthuhiggins/foreigner
change_table :comments do |t|
t.foreign_key :posts, dependent: :delete
end
● Rails 4
t.references :posts, index: :true
# DB Constraints. NO?
Trigger in MySQL …
CREATE TRIGGER trigger_name BEFORE INSERT ON table_name FOR EACH ROW
BEGIN
DECLARE var INT;
IF NOT(NEW.int_col IS NOT NULL AND NEW.int_col >= 1 AND NEW.int_col <= 3)
THEN SET var = (SELECT MAX(1) FROM `inclusion violated`);
END IF;
END
# DB Constraints. NO?
Function first in PostgreSQL …
CREATE OR REPLACE FUNCTION trg_mgr_validates_table_name_ins_func() RETURNS trigger AS $BODY$
BEGIN
IF NOT(NEW.int_column IS NOT NULL AND NEW.int_column >= 1 AND NEW.int_column <= 3)
THEN RAISE EXCEPTION 'inclusion violated for table_name field int_column';
END IF;
RETURN NEW;
END;
$BODY$
# DB constraints in migrations?
And trigger after that …
CREATE TRIGGER trg_mgr_validates_table_name_ins
BEFORE INSERT
ON table_name
FOR EACH ROW
EXECUTE PROCEDURE trg_mgr_validates_table_name_ins_func();
# DB constraints in migrations?
Let’s imagine…
create_table :table_name do |t|
t.integer :int_column, validates: { uniqueness: :true,
inclusion: { in: 1..3 } }
t.column :column_name, :integer, validates: { exclusion: { in: [1,2,3]} }
end
# Migration Validators (MV) Project
● RDBMs:
● Helpers
validates: { uniqueness: true, exclusion: true, inclusion: true,
length: true, format: true, presence: true }
# MV. Simple. Familiar
Create format validation...
create_table :table_name do |t|
t.change :str_column, validates: {
format: { with: /interesting/,
message: "value should be interesting"}
}
end
# MV. Simple. Familiar
Update format validation...
change_table :table_name do |t|
t.string :str_column, validates: {
format: { with: /VERY interesting/,
message: "value should be VERY interesting" }
}
end
# MV. Simple. Familiar
Delete format validation...
change_table :table_name do |t|
t.string :str_column, validates: { format: :false }
end
# MV. Configurable
Everything we already know…
create_table :table_name do |t|
t.string :column_name, validates: {
length: { in: 5..8,
too_long: 'Should be <= 8', too_short: 'Should be >= 5',
on: :save, allow_nil: true, allow_blank: true }
}
end
# MV. Configurable
And something related to db...
create_table :table_name do |t|
t.string :column_name, validates: {
length: { in: 5..8, on: [:create, :update], as: :trigger,
update_trigger_name: :upd_trg,
create_trigger_name: :upd_trg }
}
end
# MV. RDBMS agnostic
Same declaration:
create_table do |t|
t.integer :int_column, validates: { inclusion: { in: 1..3 } }
end
Different definitions:
{ MySQL: :trigger, SQLite: :trigger, PostgreSQL: :check }
# MV. Not supported yet
Change...
class Order < ActiveRecord::Migration
def change
create_table :orders do |t|
t.integer :int_column, validates: { uniqueness: true }
end
end
end
# MV. Homepage
● Corehttps://github.com/vprokopchuk256/mv-test
https://github.com/vprokopchuk256/mv-core
● Drivershttps://github.com/vprokopchuk256/mv-mysql
https://github.com/vprokopchuk256/mv-postgresql
https://github.com/vprokopchuk256/mv-sqlite
top related