Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Deep down fixtures

Deep down fixtures

Slides for talk given at RubyKaigi 2014

Avatar for Prathamesh Sonpatki

Prathamesh Sonpatki

September 19, 2014
Tweet

More Decks by Prathamesh Sonpatki

Other Decks in Technology

Transcript

  1. /rubykaigi2014/speakers/prathamesh.yml prathamesh: company: BigBinary role: Software Engineer hometown: Pune, India

    ruby_group: pune.rb github: prathamesh-sonpatki twitter: _cha1tanya interestes: <%= %w(ruby rails cricket emacs) %>
  2. /india/rubyconfs.yml rubyconfindia: website: rubyconfindia.org location: Goa when: April 3rd and

    4th 2015 ! garden_city_ruby_conf: website: gardencityruby.org location: Banglore when: 10 January 2015 cfp: will open soon.. ! deccan_ruby_conf: website: deccanrubyconf.org location: pune when: Around June/July 2015**
  3. Why? • We should know the tool before rejecting it

    • Fixtures are baked into Rails
  4. Why? • We should know the tool before rejecting it

    • Fixtures are baked into Rails • Understanding what all things are possible with fixtures
  5. Why? • We should know the tool before rejecting it

    • Fixtures are baked into Rails • Understanding what all things are possible with fixtures • Staying close to Rails stack
  6. Creating fixtures • As simple as writing .yml files •

    Needs thinking • Needs creativity(to make them memorable)
  7. Protip: Key matters repo1: user_name: rails name: rails full_name: rails/rails

    language: ruby created_at: 2012-11-10 21:50:48.351554000 Z updated_at: 2012-11-10 21:50:48.351554000 Z issues_count: 0
  8. Protip: Key matters repo1: user_name: rails name: rails full_name: rails/rails

    language: ruby created_at: 2012-11-10 21:50:48.351554000 Z updated_at: 2012-11-10 21:50:48.351554000 Z issues_count: 0 repo = repos(:repo1)
  9. Protip: Key matters repo1: user_name: rails name: rails full_name: rails/rails

    language: ruby created_at: 2012-11-10 21:50:48.351554000 Z updated_at: 2012-11-10 21:50:48.351554000 Z issues_count: 0 repo = repos(:repo1)
  10. Protip: Key matters rails_rails: user_name: rails name: rails full_name: rails/rails

    language: ruby created_at: 2012-11-10 21:50:48.351554000 Z updated_at: 2012-11-10 21:50:48.351554000 Z issues_count: 0 repo = repos(:rails_rails)
  11. Protip:Don’t specify ids** rails_rails: id: 1 user_name: rails name: rails

    full_name: rails/rails language: ruby created_at: 2012-11-10 21:50:48.351554000 Z updated_at: 2012-11-10 21:50:48.351554000 Z issues_count: 0
  12. Loading fixtures ! • Read from yaml file • Convert

    into hash • Delete all existing data
  13. Loading fixtures • Delete all existing data Fixture Delete (0.3ms)

    DELETE FROM "issue_assignments" Fixture Delete (0.3ms) DELETE FROM "issues" Fixture Delete (0.3ms) DELETE FROM "repo_subscriptions" Fixture Delete (0.3ms) DELETE FROM "repos" Fixture Delete (0.7ms) DELETE FROM "users"
  14. Loading fixtures • Delete all existing data • Load data

    Fixture Insert (0.2ms) INSERT INTO "repo_subscriptions" ("user_name", "repo_name", "created_at", "updated_at", "last_sent_at", "email_limit", "id", "repo_id", "user_id") VALUES ('rails', 'rails', '2013-10-29 21:09:48.351554', '2013-10-29 21:09:48.351554', NULL, 5, 836719243, 603590727, 110871456)
  15. Loading fixtures # /rails/activerecord/lib/active_record/connection_adapters/abstract/ database_statements.rb ! # Inserts the given

    fixture into the table. Overridden in adapters that # require something beyond a simple insert (eg. Oracle). def insert_fixture(fixture, table_name) columns = schema_cache.columns_hash(table_name) ! key_list = [] value_list = fixture.map do |name, value| key_list << quote_column_name(name) quote(value, columns[name]) end ! execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert' end
  16. Identifying fixtures # Returns a consistent, platform-independent identifier for +label+.

    # Integer identifiers are values less than 2^30. UUIDs are RFC 4122 versio 5 SHA-1 hashes. def self.identify(label, column_type = :integer) if column_type == :uuid Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s) else Zlib.crc32(label.to_s) % MAX_ID end end
  17. Associations schneems_to_triage: repo: issue_triage_sandbox user: schneems user_name: bemurphy repo_name: issue_triage_sandbox

    jroes_to_rails: repo: rails_rails user: jroes user_name: rails repo_name: rails !
  18. Associations schneems_to_triage: repo: issue_triage_sandbox user: schneems user_name: bemurphy repo_name: issue_triage_sandbox

    jroes_to_rails: repo: rails_rails user: jroes user_name: rails repo_name: rails !
  19. Setting a value to nil • A column with default

    value, but you need NULL • Many ways to do it
  20. Setting a value to nil irb(main):001:0> require 'yaml' => true

    irb(main):002:0> YAML.load("--- \n:k: null\n") => {:k=>nil}
  21. Setting a value to nil jroes_to_rails: repo: rails_rails user: jroes

    user_name: rails repo_name: rails created_at: 2013-10-29 21:09:48.351554000 Z updated_at: 2013-10-29 21:09:48.351554000 Z last_sent_at: NULL 60
  22. Setting a value to nil irb(main):001:0> require 'yaml' => true

    irb(main):002:0> YAML.load("--- \n:k: \n") => {:k=>nil} irb(main):003:0>
  23. Setting a value to nil jroes_to_rails: repo: rails_rails user: jroes

    user_name: rails repo_name: rails created_at: 2013-10-29 21:09:48.351554000 Z updated_at: 2013-10-29 21:09:48.351554000 Z last_sent_at:
  24. ERBin it up <% 1.upto(1000) do |i| %> issue_<%= i

    %>: name: rails_<%= i %> <% end %>
  25. ERBin it up • Need to generate dynamic data •

    Sprinkle ERB in yaml files • Use with caution
  26. Timestamps • Autofills standard timestamp columns if they are not

    present in fixture • Works only if model.record_timestamps is true(default is true)
  27. Timestamps # /rails/activerecord/lib/active_record/fixtures.rb ! now = config.default_timezone == :utc ?

    Time.now.utc : Time.now now = now.to_s(:db) ! if model_class.record_timestamps timestamp_column_names.each do |c_name| row[c_name] = now unless row.key?(c_name) end end
  28. Timestamps # /rails/activerecord/lib/active_record/fixtures.rb ! now = config.default_timezone == :utc ?

    Time.now.utc : Time.now now = now.to_s(:db) ! if model_class.record_timestamps timestamp_column_names.each do |c_name| row[c_name] = now unless row.key?(c_name) end end
  29. Timestamps • Autofills standard timestamp columns if they are not

    present in fixture • Works only if model.record_timestamps is true(default is true) • created_at, updated_at, created_on, updated_on
  30. Label Interpolation # /rails/activerecord/lib/active_record/fixtures.rb ! # interpolate the fixture label

    row.each do |key, value| row[key] = value.gsub("$LABEL", label) if value.is_a? (String) end ! !
  31. Database tricks** ! • now is special value in PostGreSQL

    • Shorthand that will be converted to date/time when read. • http://www.postgresql.org/docs/9.3/static/datatype- datetime.html#AEN5861
  32. YAML Defaults issue_triage_sandbox: user_name: bemurphy name: issue_triage_sandbox full_name: bemurphy/issue_triage_sandbox language:

    ruby created_at: 2012-11-10 21:50:48.351554000 Z updated_at: 2012-11-10 21:50:48.351554000 Z issues_count: 1 ! rails_rails: user_name: rails name: rails full_name: rails/rails language: ruby created_at: 2012-11-10 21:50:48.351554000 Z updated_at: 2012-11-10 21:50:48.351554000 Z issues_count: 0
  33. YAML Defaults issue_triage_sandbox: user_name: bemurphy name: issue_triage_sandbox full_name: bemurphy/issue_triage_sandbox language:

    ruby created_at: 2012-11-10 21:50:48.351554000 Z updated_at: 2012-11-10 21:50:48.351554000 Z issues_count: 1 ! rails_rails: user_name: rails name: rails full_name: rails/rails language: ruby created_at: 2012-11-10 21:50:48.351554000 Z updated_at: 2012-11-10 21:50:48.351554000 Z issues_count: 0
  34. YAML Defaults DEFAULTS: &DEFAULTS language: ruby created_at: 2012-11-10 21:50:48.351554000 Z

    updated_at: 2012-11-10 21:50:48.351554000 Z ! issue_triage_sandbox: user_name: bemurphy name: issue_triage_sandbox full_name: bemurphy/issue_triage_sandbox <<: *DEFAULTS issues_count: 1 ! rails_rails: user_name: rails name: rails full_name: rails/rails <<: *DEFAULTS issues_count: 0
  35. Ordered fixtures • By default fixtures are unordered • But

    sometimes, order is required • For eg. fork of a repo. Parent repo is needed before the repo can be forked.
  36. Ordered fixtures rails_rails: id: 1 user_name: rails name: rails full_name:

    rails/rails language: ruby created_at: 2012-11-10 21:50:48.351554000 Z updated_at: 2012-11-10 21:50:48.351554000 Z issues_count: 0 parent_repo_id:
  37. Ordered fixtures prathamesh_rails: id: 2 user_name: prathamesh-sonpatki name: rails full_name:

    prathamesh-sonpatki/rails language: ruby created_at: 2012-11-10 21:50:48.351554000 Z updated_at: 2012-11-10 21:50:48.351554000 Z issues_count: 0 parent_repo_id: 1
  38. Ordered fixtures • OMAP YAML --- !omap - rails_rails: id:

    1 user_name: rails name: rails full_name: rails/rails ! - prathamesh_rails: id: 2 user_name: prathamesh-sonpatki name: rails full_name: prathamesh-sonpatki/rails
  39. Table name != Model name • set_fixture_class method • class

    method • accepts hash of filenames with key and class name as value • key should be name of fixture(or relative path) • value should be name of class