20121201032354_create_versions.rb 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. # This migration creates the `versions` table, the only schema PT requires.
  2. # All other migrations PT provides are optional.
  3. class CreateVersions < ActiveRecord::Migration
  4. # Class names of MySQL adapters.
  5. # - `MysqlAdapter` - Used by gems: `mysql`, `activerecord-jdbcmysql-adapter`.
  6. # - `Mysql2Adapter` - Used by `mysql2` gem.
  7. MYSQL_ADAPTERS = [
  8. "ActiveRecord::ConnectionAdapters::MysqlAdapter",
  9. "ActiveRecord::ConnectionAdapters::Mysql2Adapter"
  10. ].freeze
  11. # The largest text column available in all supported RDBMS is
  12. # 1024^3 - 1 bytes, roughly one gibibyte. We specify a size
  13. # so that MySQL will use `longtext` instead of `text`. Otherwise,
  14. # when serializing very large objects, `text` might not be big enough.
  15. TEXT_BYTES = 1_073_741_823
  16. def change
  17. create_table :versions, versions_table_options do |t|
  18. t.string :item_type, item_type_options
  19. t.integer :item_id, null: false
  20. t.string :event, null: false
  21. t.string :whodunnit
  22. t.text :object, limit: TEXT_BYTES
  23. # Known issue in MySQL: fractional second precision
  24. # -------------------------------------------------
  25. #
  26. # MySQL timestamp columns do not support fractional seconds unless
  27. # defined with "fractional seconds precision". MySQL users should manually
  28. # add fractional seconds precision to this migration, specifically, to
  29. # the `created_at` column.
  30. # (https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html)
  31. #
  32. # MySQL users should also upgrade to rails 4.2, which is the first
  33. # version of ActiveRecord with support for fractional seconds in MySQL.
  34. # (https://github.com/rails/rails/pull/14359)
  35. #
  36. t.datetime :created_at
  37. end
  38. add_index :versions, [:item_type, :item_id]
  39. end
  40. private
  41. # MySQL 5.6 utf8mb4 limit is 191 chars for keys used in indexes.
  42. # See https://github.com/airblade/paper_trail/issues/651
  43. def item_type_options
  44. opt = { null: false }
  45. opt[:limit] = 191 if mysql?
  46. opt
  47. end
  48. def mysql?
  49. MYSQL_ADAPTERS.include?(connection.class.name)
  50. end
  51. # Even modern versions of MySQL still use `latin1` as the default character
  52. # encoding. Many users are not aware of this, and run into trouble when they
  53. # try to use PaperTrail in apps that otherwise tend to use UTF-8. Postgres, by
  54. # comparison, uses UTF-8 except in the unusual case where the OS is configured
  55. # with a custom locale.
  56. #
  57. # - https://dev.mysql.com/doc/refman/5.7/en/charset-applications.html
  58. # - http://www.postgresql.org/docs/9.4/static/multibyte.html
  59. #
  60. # Furthermore, MySQL's original implementation of UTF-8 was flawed, and had
  61. # to be fixed later by introducing a new charset, `utf8mb4`.
  62. #
  63. # - https://mathiasbynens.be/notes/mysql-utf8mb4
  64. # - https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html
  65. #
  66. def versions_table_options
  67. if mysql?
  68. { options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" }
  69. else
  70. {}
  71. end
  72. end
  73. end