POLO
WORKINGWITHREALWORLDDATAIN
DEVELOPMENT
@nettofarah
1 / 39
nettofarah
github.com/nettofarah
@nettofarah
http://bit.ly/polo-rb
2 / 39
RealWorldProductionDatain
Development
3 / 39
BecauseManagingDataishard
Especially across Different environments
4 / 39
Datain Rails.env.dev
is...
Ugly, Incomplete, Weird and Biased
5 / 39
SomeConsequencesofInconsistent
Data
6 / 39
!"!",##misalignment,form
validation,specialcharacters$$
7 / 39
TheWorstConsequence
8 / 39
Rails.env.dev
will look %
9 / 39
Buthowdopeoplesolvethese
problems?
10 / 39
Wecantestitin PRODUCTION
11 / 39
Rails.env.staging ?
12 / 39
Custom db/migrations
fordata
13 / 39
rake db:seed
14 / 39
CSVsandSpreadsheets
15 / 39
16 / 39
SampleDatabaseSnapshots
17 / 39
Your good ol'
ActiveRecord::Associations
to
.sql
18 / 39
POLOletsyouturnthis...
19 / 39
class Chef < ActiveRecord::Base
has_many :recipes
has_many :ingredients, through: :recipes
end
class Recipe < ActiveRecord::Base
has_many :recipes_ingredients
has_many :ingredients, through: :recipes_ingredients
end
class Ingredient < ActiveRecord::Base
end
class RecipesIngredient < ActiveRecord::Base
belongs_to :recipe
belongs_to :ingredient
end
20 / 39
Intothis...
21 / 39
inserts = Polo.explore(Chef, 1)
# Chef -> ActiveRecord::Base object
# 1 -> Database ID. (Chef with ID 1)
INSERT INTO `chefs` (`id`, `name`)
VALUES (1, 'Netto')
22 / 39
Itworkswithassociationstoo
23 / 39
inserts = Polo.explore(Chef, 1, :recipes)
# :recipes ->
# ActiveRecord::Associations::HasManyAssociation
#
# a Chef has many Recipes
INSERT INTO `chefs` (`id`, `name`)
VALUES (1, 'Netto')
INSERT INTO `recipes`
(`id`, `title`, `num_steps`, `chef_id`)
VALUES
(1, 'Turkey Sandwich', NULL, 1)
INSERT INTO `recipes`
(`id`, `title`, `num_steps`, `chef_id`)
VALUES
(2, 'Cheese Burger', NULL, 1)
24 / 39
Italsoworkswithnested
associations
25 / 39
inserts = Polo.explore(Chef, 1, { :recipes => :ingredients })
# { :recipes => :ingredients } ->
# load every recipe and ingredientes
...
INSERT INTO `recipes` (`id`, `title`, `num_steps`, `chef_id`)
VALUES (1, 'Turkey Sandwich', NULL, 1)
INSERT INTO `recipes` (`id`, `title`, `num_steps`, `chef_id`)
VALUES (2, 'Cheese Burger', NULL, 1)
INSERT INTO `recipes_ingredients`
(`id`, `recipe_id`, `ingredient_id`)
VALUES (1, 1, 1)
INSERT INTO `recipes_ingredients`
(`id`, `recipe_id`, `ingredient_id`)
VALUES (2, 1, 2)
...
INSERT INTO `ingredients` (`id`, `name`, `quantity`)
VALUES (1, 'Turkey', 'a lot')
INSERT INTO `ingredients` (`id`, `name`, `quantity`)
VALUES (2, 'Cheese', '1 slice')
...
26 / 39
&&
Showmethemagic!
27 / 39
Collectalltheobjects
lib/polo/collector.rb#L16
28 / 39
asn = ActiveSupport::Notifications
# Extracted so this can fit in a slide
asn.subscribed(collector, 'sql.active_record') do
# Set up ActiveRecord::Preloader
base_finder = @base_class.
includes(@dependency_tree)
.where(id: @id)
# Store SELECTS in some global storage
collect_sql(@base_class, base_finder.to_sql)
end
29 / 39
''
TransformthemtoSQL
lib/polo/sql_translator.rb#51
30 / 39
attributes = record.attributes
keys = attributes.keys.map do |key|
"`#{key}`"
end
values = attributes.map do |key, value|
column = record.column_for_attribute(key)
attribute = cast_attribute(record, column, value)
connection.quote(attribute)
end
joined_keys = keys.join(', ')
joined_values = values.join(', ')
table_name = record.class.table_name
"INSERT INTO `#{table_name}`" +
" (#{joined_keys}) VALUES (#{joined_values})"
31 / 39
PROFIT!((
32 / 39
Ineedyourhelp!))
33 / 39
onGithub
http://github.com/IFTTT/polo
34 / 39
PullRequests**
35 / 39
PostgreSQL,SQLiteandOracle
support
(advanced features only, basic usage still
works)
36 / 39
ActiveRecord<3.2support
37 / 39
Checkoutsomeotherreallycool
OpenSourceprojects
http://ifttt.github.io
38 / 39
Questions?
39 / 39

Polo: Desenvolvendo os problemas de inconsistência de dados em projetos Rails