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

Grow from Small Simple Steps

Grow from Small Simple Steps

Avatar for aquajach

aquajach

June 26, 2016
Tweet

More Decks by aquajach

Other Decks in Technology

Transcript

  1. THE PROBLEM gem 'activerecord-import' books = [] 10.times do |i|

    books << Book.new(:name => "book #{i}") end Book.import books
  2. THE PROBLEM class Book < ActiveRecord::Base enum status: [:drafted, :finished,

    :published] #book.status = 0 or book.status = 'drafted' end create_table 'books' do |t| t.integer 'status', default: 0 end books = [] 10.times do |i| books << Book.new(:name => "book #{i}") end Book.import books #=> ArgumentError: '0' is not a valid status
  3. WHY IT FAILS # Returns the list of a table's

    column names, data types, and default values. def column_definitions(table_name) # :nodoc: exec_query(<<-end_sql, 'SCHEMA').rows SELECT a.attname, format_type(a.atttypid, a.atttypmod), pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum end_sql end
  4. WHY IT FAILS # Returns the list of a table's

    column names, data types, and default values. def column_definitions(table_name) # :nodoc: exec_query(<<-end_sql, 'SCHEMA').rows SELECT a.attname, format_type(a.atttypid, a.atttypmod), pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum end_sql end text
  5. WHY IT FAILS class ActiveRecord::Base class << self def import

    ... array_of_attributes = models.map do |model| column_names.map do |name| model.read_attribute_before_type_cast(name.to_s) end end ... instance = new do |model| hash.each_pair{ |k, v| model.send("#{k}=", v) } #=> ArgumentError: '0' is not a valid status end ... end end end
  6. TEST? class Book < ActiveRecord::Base enum status: [:draft, :published] if

    ENV['AR_VERSION'].to_i >= 4.1 #AR_VERSION = 3.1, 3.2, 4.0, 4.1, 4.2 end
  7. TEST? class Book < ActiveRecord::Base enum status: [:draft, :published] if

    ENV['AR_VERSION'].to_i >= 4.1 #AR_VERSION = 3.1, 3.2, 4.0, 4.1, 4.2 end
  8. Rails 1.2 Maintainer: It was back to 2007. Use read_attribute

    if it gets test case pass Maintainer: why read_attribute_before_type_cast is used?
  9. Maintainer: Another method handles casting. Using read_attribute might be ok

    Maintainer: It was back to 2007. Use read_attribute if it gets test case pass
  10. Me: Just benchmark it, read_attribute is 50% slower for casting

    Maintainer: Another method handles casting. Using read_attribute might be ok
  11. Committer: Simple fix instance = new do |model| # hash.each_pair{

    |k, v| model.send("#{k}=", v) } hash.each_pair{ |k,v| model[k] = v } end Me: Just benchmark it, read_attribute is 50% slower for casting
  12. Committer: Simple fix instance = new do |model| # hash.each_pair{

    |k, v| model.send("#{k}=", v) } hash.each_pair{ |k,v| model[k] = v } end ☹ Me: Seems working, but…
  13. MY TAKEAWAYS • ActiveRecord::ConnectionAdapters • ActiveRecord different assignment methods and

    type casting • Default value in PostgreSQL • Libraries/gems supporting multiple ruby version and database adaptors • Rails enum