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

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