activerecord 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +4928 -3
- data/README +45 -46
- data/RUNNING_UNIT_TESTS +8 -11
- data/Rakefile +247 -0
- data/install.rb +8 -38
- data/lib/active_record/aggregations.rb +64 -49
- data/lib/active_record/associations/association_collection.rb +217 -47
- data/lib/active_record/associations/association_proxy.rb +159 -0
- data/lib/active_record/associations/belongs_to_association.rb +56 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +155 -37
- data/lib/active_record/associations/has_many_association.rb +145 -75
- data/lib/active_record/associations/has_many_through_association.rb +283 -0
- data/lib/active_record/associations/has_one_association.rb +96 -0
- data/lib/active_record/associations.rb +1537 -304
- data/lib/active_record/attribute_methods.rb +328 -0
- data/lib/active_record/base.rb +2001 -588
- data/lib/active_record/calculations.rb +269 -0
- data/lib/active_record/callbacks.rb +169 -165
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +308 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +472 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +306 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +125 -279
- data/lib/active_record/connection_adapters/mysql_adapter.rb +442 -77
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +805 -135
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +353 -69
- data/lib/active_record/fixtures.rb +946 -100
- data/lib/active_record/locking/optimistic.rb +144 -0
- data/lib/active_record/locking/pessimistic.rb +77 -0
- data/lib/active_record/migration.rb +417 -0
- data/lib/active_record/observer.rb +142 -32
- data/lib/active_record/query_cache.rb +23 -0
- data/lib/active_record/reflection.rb +163 -70
- data/lib/active_record/schema.rb +58 -0
- data/lib/active_record/schema_dumper.rb +171 -0
- data/lib/active_record/serialization.rb +98 -0
- data/lib/active_record/serializers/json_serializer.rb +71 -0
- data/lib/active_record/serializers/xml_serializer.rb +315 -0
- data/lib/active_record/timestamp.rb +41 -0
- data/lib/active_record/transactions.rb +87 -57
- data/lib/active_record/validations.rb +909 -122
- data/lib/active_record/vendor/db2.rb +362 -0
- data/lib/active_record/vendor/mysql.rb +126 -29
- data/lib/active_record/version.rb +9 -0
- data/lib/active_record.rb +35 -7
- data/lib/activerecord.rb +1 -0
- data/test/aaa_create_tables_test.rb +72 -0
- data/test/abstract_unit.rb +73 -5
- data/test/active_schema_test_mysql.rb +43 -0
- data/test/adapter_test.rb +105 -0
- data/test/adapter_test_sqlserver.rb +95 -0
- data/test/aggregations_test.rb +110 -16
- data/test/all.sh +2 -2
- data/test/ar_schema_test.rb +33 -0
- data/test/association_inheritance_reload.rb +14 -0
- data/test/associations/ar_joins_test.rb +0 -0
- data/test/associations/callbacks_test.rb +147 -0
- data/test/associations/cascaded_eager_loading_test.rb +110 -0
- data/test/associations/eager_singularization_test.rb +145 -0
- data/test/associations/eager_test.rb +442 -0
- data/test/associations/extension_test.rb +47 -0
- data/test/associations/inner_join_association_test.rb +88 -0
- data/test/associations/join_model_test.rb +553 -0
- data/test/associations_test.rb +1930 -267
- data/test/attribute_methods_test.rb +146 -0
- data/test/base_test.rb +1316 -84
- data/test/binary_test.rb +32 -0
- data/test/calculations_test.rb +251 -0
- data/test/callbacks_test.rb +400 -0
- data/test/class_inheritable_attributes_test.rb +3 -4
- data/test/column_alias_test.rb +17 -0
- data/test/connection_test_firebird.rb +8 -0
- data/test/connection_test_mysql.rb +30 -0
- data/test/connections/native_db2/connection.rb +25 -0
- data/test/connections/native_firebird/connection.rb +26 -0
- data/test/connections/native_frontbase/connection.rb +27 -0
- data/test/connections/native_mysql/connection.rb +21 -18
- data/test/connections/native_openbase/connection.rb +21 -0
- data/test/connections/native_oracle/connection.rb +27 -0
- data/test/connections/native_postgresql/connection.rb +17 -18
- data/test/connections/native_sqlite/connection.rb +17 -16
- data/test/connections/native_sqlite3/connection.rb +25 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
- data/test/connections/native_sybase/connection.rb +23 -0
- data/test/copy_table_test_sqlite.rb +69 -0
- data/test/datatype_test_postgresql.rb +203 -0
- data/test/date_time_test.rb +37 -0
- data/test/default_test_firebird.rb +16 -0
- data/test/defaults_test.rb +67 -0
- data/test/deprecated_finder_test.rb +30 -0
- data/test/finder_test.rb +607 -32
- data/test/fixtures/accounts.yml +28 -0
- data/test/fixtures/all/developers.yml +0 -0
- data/test/fixtures/all/people.csv +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author.rb +107 -0
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/authors.yml +7 -0
- data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
- data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
- data/test/fixtures/bad_fixtures/blank_line +3 -0
- data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
- data/test/fixtures/bad_fixtures/missing_value +1 -0
- data/test/fixtures/binaries.yml +132 -0
- data/test/fixtures/binary.rb +2 -0
- data/test/fixtures/book.rb +4 -0
- data/test/fixtures/books.yml +7 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories.yml +14 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/categories_posts.yml +23 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +17 -0
- data/test/fixtures/category.rb +26 -0
- data/test/fixtures/citation.rb +6 -0
- data/test/fixtures/comment.rb +23 -0
- data/test/fixtures/comments.yml +59 -0
- data/test/fixtures/companies.yml +55 -0
- data/test/fixtures/company.rb +81 -4
- data/test/fixtures/company_in_module.rb +32 -6
- data/test/fixtures/computer.rb +4 -0
- data/test/fixtures/computers.yml +4 -0
- data/test/fixtures/contact.rb +16 -0
- data/test/fixtures/courses.yml +7 -0
- data/test/fixtures/customer.rb +28 -3
- data/test/fixtures/customers.yml +17 -0
- data/test/fixtures/db_definitions/db2.drop.sql +33 -0
- data/test/fixtures/db_definitions/db2.sql +235 -0
- data/test/fixtures/db_definitions/db22.drop.sql +2 -0
- data/test/fixtures/db_definitions/db22.sql +5 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +65 -0
- data/test/fixtures/db_definitions/firebird.sql +310 -0
- data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
- data/test/fixtures/db_definitions/firebird2.sql +6 -0
- data/test/fixtures/db_definitions/frontbase.drop.sql +33 -0
- data/test/fixtures/db_definitions/frontbase.sql +273 -0
- data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase2.sql +4 -0
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +318 -0
- data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase2.sql +7 -0
- data/test/fixtures/db_definitions/oracle.drop.sql +67 -0
- data/test/fixtures/db_definitions/oracle.sql +330 -0
- data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle2.sql +6 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +44 -0
- data/test/fixtures/db_definitions/postgresql.sql +217 -38
- data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/postgresql2.sql +2 -2
- data/test/fixtures/db_definitions/schema.rb +354 -0
- data/test/fixtures/db_definitions/schema2.rb +11 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +33 -0
- data/test/fixtures/db_definitions/sqlite.sql +139 -5
- data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlite2.sql +1 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +35 -0
- data/test/fixtures/db_definitions/sybase.sql +222 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/developer.rb +70 -6
- data/test/fixtures/developers.yml +21 -0
- data/test/fixtures/developers_projects/david_action_controller +2 -1
- data/test/fixtures/developers_projects/david_active_record +2 -1
- data/test/fixtures/developers_projects.yml +17 -0
- data/test/fixtures/edge.rb +5 -0
- data/test/fixtures/edges.yml +6 -0
- data/test/fixtures/entrants.yml +14 -0
- data/test/fixtures/example.log +1 -0
- data/test/fixtures/fk_test_has_fk.yml +3 -0
- data/test/fixtures/fk_test_has_pk.yml +2 -0
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/funny_jokes.yml +10 -0
- data/test/fixtures/item.rb +7 -0
- data/test/fixtures/items.yml +4 -0
- data/test/fixtures/joke.rb +3 -0
- data/test/fixtures/keyboard.rb +3 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/matey.rb +4 -0
- data/test/fixtures/mateys.yml +4 -0
- data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
- data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
- data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
- data/test/fixtures/minimalistic.rb +2 -0
- data/test/fixtures/minimalistics.yml +2 -0
- data/test/fixtures/mixed_case_monkey.rb +3 -0
- data/test/fixtures/mixed_case_monkeys.yml +6 -0
- data/test/fixtures/mixins.yml +29 -0
- data/test/fixtures/movies.yml +7 -0
- data/test/fixtures/naked/csv/accounts.csv +1 -0
- data/test/fixtures/naked/yml/accounts.yml +1 -0
- data/test/fixtures/naked/yml/companies.yml +1 -0
- data/test/fixtures/naked/yml/courses.yml +1 -0
- data/test/fixtures/order.rb +4 -0
- data/test/fixtures/parrot.rb +13 -0
- data/test/fixtures/parrots.yml +27 -0
- data/test/fixtures/parrots_pirates.yml +7 -0
- data/test/fixtures/people.yml +3 -0
- data/test/fixtures/person.rb +4 -0
- data/test/fixtures/pirate.rb +5 -0
- data/test/fixtures/pirates.yml +9 -0
- data/test/fixtures/post.rb +59 -0
- data/test/fixtures/posts.yml +48 -0
- data/test/fixtures/project.rb +27 -2
- data/test/fixtures/projects.yml +7 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +18 -2
- data/test/fixtures/reserved_words/distinct.yml +5 -0
- data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
- data/test/fixtures/reserved_words/group.yml +14 -0
- data/test/fixtures/reserved_words/select.yml +8 -0
- data/test/fixtures/reserved_words/values.yml +7 -0
- data/test/fixtures/ship.rb +3 -0
- data/test/fixtures/ships.yml +5 -0
- data/test/fixtures/subject.rb +4 -0
- data/test/fixtures/subscriber.rb +4 -3
- data/test/fixtures/tag.rb +7 -0
- data/test/fixtures/tagging.rb +10 -0
- data/test/fixtures/taggings.yml +25 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/task.rb +3 -0
- data/test/fixtures/tasks.yml +7 -0
- data/test/fixtures/topic.rb +20 -3
- data/test/fixtures/topics.yml +22 -0
- data/test/fixtures/treasure.rb +4 -0
- data/test/fixtures/treasures.yml +10 -0
- data/test/fixtures/vertex.rb +9 -0
- data/test/fixtures/vertices.yml +4 -0
- data/test/fixtures_test.rb +574 -8
- data/test/inheritance_test.rb +113 -27
- data/test/json_serialization_test.rb +180 -0
- data/test/lifecycle_test.rb +56 -29
- data/test/locking_test.rb +273 -0
- data/test/method_scoping_test.rb +416 -0
- data/test/migration_test.rb +933 -0
- data/test/migration_test_firebird.rb +124 -0
- data/test/mixin_test.rb +95 -0
- data/test/modules_test.rb +23 -10
- data/test/multiple_db_test.rb +17 -3
- data/test/pk_test.rb +59 -15
- data/test/query_cache_test.rb +104 -0
- data/test/readonly_test.rb +107 -0
- data/test/reflection_test.rb +124 -27
- data/test/reserved_word_test_mysql.rb +177 -0
- data/test/schema_authorization_test_postgresql.rb +75 -0
- data/test/schema_dumper_test.rb +131 -0
- data/test/schema_test_postgresql.rb +64 -0
- data/test/serialization_test.rb +47 -0
- data/test/synonym_test_oracle.rb +17 -0
- data/test/table_name_test_sqlserver.rb +23 -0
- data/test/threaded_connections_test.rb +48 -0
- data/test/transactions_test.rb +227 -29
- data/test/unconnected_test.rb +14 -6
- data/test/validations_test.rb +1293 -32
- data/test/xml_serialization_test.rb +202 -0
- metadata +347 -143
- data/dev-utils/eval_debugger.rb +0 -9
- data/examples/associations.rb +0 -87
- data/examples/shared_setup.rb +0 -15
- data/examples/validation.rb +0 -88
- data/lib/active_record/deprecated_associations.rb +0 -70
- data/lib/active_record/support/class_attribute_accessors.rb +0 -43
- data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
- data/lib/active_record/support/clean_logger.rb +0 -10
- data/lib/active_record/support/inflector.rb +0 -70
- data/lib/active_record/vendor/simple.rb +0 -702
- data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
- data/lib/active_record/wrappings.rb +0 -59
- data/rakefile +0 -122
- data/test/deprecated_associations_test.rb +0 -336
- data/test/fixtures/accounts/signals37 +0 -3
- data/test/fixtures/accounts/unknown +0 -2
- data/test/fixtures/companies/first_client +0 -6
- data/test/fixtures/companies/first_firm +0 -4
- data/test/fixtures/companies/second_client +0 -6
- data/test/fixtures/courses/java +0 -2
- data/test/fixtures/courses/ruby +0 -2
- data/test/fixtures/customers/david +0 -6
- data/test/fixtures/db_definitions/mysql.sql +0 -96
- data/test/fixtures/db_definitions/mysql2.sql +0 -4
- data/test/fixtures/developers/david +0 -2
- data/test/fixtures/developers/jamis +0 -2
- data/test/fixtures/entrants/first +0 -3
- data/test/fixtures/entrants/second +0 -3
- data/test/fixtures/entrants/third +0 -3
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
- data/test/fixtures/movies/first +0 -2
- data/test/fixtures/movies/second +0 -2
- data/test/fixtures/projects/action_controller +0 -2
- data/test/fixtures/projects/active_record +0 -2
- data/test/fixtures/topics/first +0 -9
- data/test/fixtures/topics/second +0 -8
- data/test/inflector_test.rb +0 -104
- data/test/thread_safety_test.rb +0 -33
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'bigdecimal'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
# This class is used to dump the database schema for some connection to some
|
6
|
+
# output format (i.e., ActiveRecord::Schema).
|
7
|
+
class SchemaDumper #:nodoc:
|
8
|
+
private_class_method :new
|
9
|
+
|
10
|
+
# A list of tables which should not be dumped to the schema.
|
11
|
+
# Acceptable values are strings as well as regexp.
|
12
|
+
# This setting is only used if ActiveRecord::Base.schema_format == :ruby
|
13
|
+
cattr_accessor :ignore_tables
|
14
|
+
@@ignore_tables = []
|
15
|
+
|
16
|
+
def self.dump(connection=ActiveRecord::Base.connection, stream=STDOUT)
|
17
|
+
new(connection).dump(stream)
|
18
|
+
stream
|
19
|
+
end
|
20
|
+
|
21
|
+
def dump(stream)
|
22
|
+
header(stream)
|
23
|
+
tables(stream)
|
24
|
+
trailer(stream)
|
25
|
+
stream
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def initialize(connection)
|
31
|
+
@connection = connection
|
32
|
+
@types = @connection.native_database_types
|
33
|
+
@info = @connection.select_one("SELECT * FROM schema_info") rescue nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def header(stream)
|
37
|
+
define_params = @info ? ":version => #{@info['version']}" : ""
|
38
|
+
|
39
|
+
stream.puts <<HEADER
|
40
|
+
# This file is auto-generated from the current state of the database. Instead of editing this file,
|
41
|
+
# please use the migrations feature of ActiveRecord to incrementally modify your database, and
|
42
|
+
# then regenerate this schema definition.
|
43
|
+
#
|
44
|
+
# Note that this schema.rb definition is the authoritative source for your database schema. If you need
|
45
|
+
# to create the application database on another system, you should be using db:schema:load, not running
|
46
|
+
# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
47
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
48
|
+
#
|
49
|
+
# It's strongly recommended to check this file into your version control system.
|
50
|
+
|
51
|
+
ActiveRecord::Schema.define(#{define_params}) do
|
52
|
+
|
53
|
+
HEADER
|
54
|
+
end
|
55
|
+
|
56
|
+
def trailer(stream)
|
57
|
+
stream.puts "end"
|
58
|
+
end
|
59
|
+
|
60
|
+
def tables(stream)
|
61
|
+
@connection.tables.sort.each do |tbl|
|
62
|
+
next if ["schema_info", ignore_tables].flatten.any? do |ignored|
|
63
|
+
case ignored
|
64
|
+
when String; tbl == ignored
|
65
|
+
when Regexp; tbl =~ ignored
|
66
|
+
else
|
67
|
+
raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
table(tbl, stream)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def table(table, stream)
|
75
|
+
columns = @connection.columns(table)
|
76
|
+
begin
|
77
|
+
tbl = StringIO.new
|
78
|
+
|
79
|
+
if @connection.respond_to?(:pk_and_sequence_for)
|
80
|
+
pk, pk_seq = @connection.pk_and_sequence_for(table)
|
81
|
+
end
|
82
|
+
pk ||= 'id'
|
83
|
+
|
84
|
+
tbl.print " create_table #{table.inspect}"
|
85
|
+
if columns.detect { |c| c.name == pk }
|
86
|
+
if pk != 'id'
|
87
|
+
tbl.print %Q(, :primary_key => "#{pk}")
|
88
|
+
end
|
89
|
+
else
|
90
|
+
tbl.print ", :id => false"
|
91
|
+
end
|
92
|
+
tbl.print ", :force => true"
|
93
|
+
tbl.puts " do |t|"
|
94
|
+
|
95
|
+
column_specs = columns.map do |column|
|
96
|
+
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
|
97
|
+
next if column.name == pk
|
98
|
+
spec = {}
|
99
|
+
spec[:name] = column.name.inspect
|
100
|
+
spec[:type] = column.type.to_s
|
101
|
+
spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && column.type != :decimal
|
102
|
+
spec[:precision] = column.precision.inspect if !column.precision.nil?
|
103
|
+
spec[:scale] = column.scale.inspect if !column.scale.nil?
|
104
|
+
spec[:null] = 'false' if !column.null
|
105
|
+
spec[:default] = default_string(column.default) if !column.default.nil?
|
106
|
+
(spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
|
107
|
+
spec
|
108
|
+
end.compact
|
109
|
+
|
110
|
+
# find all migration keys used in this table
|
111
|
+
keys = [:name, :limit, :precision, :scale, :default, :null] & column_specs.map(&:keys).flatten
|
112
|
+
|
113
|
+
# figure out the lengths for each column based on above keys
|
114
|
+
lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
|
115
|
+
|
116
|
+
# the string we're going to sprintf our values against, with standardized column widths
|
117
|
+
format_string = lengths.map{ |len| "%-#{len}s" }
|
118
|
+
|
119
|
+
# find the max length for the 'type' column, which is special
|
120
|
+
type_length = column_specs.map{ |column| column[:type].length }.max
|
121
|
+
|
122
|
+
# add column type definition to our format string
|
123
|
+
format_string.unshift " t.%-#{type_length}s "
|
124
|
+
|
125
|
+
format_string *= ''
|
126
|
+
|
127
|
+
column_specs.each do |colspec|
|
128
|
+
values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
|
129
|
+
values.unshift colspec[:type]
|
130
|
+
tbl.print((format_string % values).gsub(/,\s*$/, ''))
|
131
|
+
tbl.puts
|
132
|
+
end
|
133
|
+
|
134
|
+
tbl.puts " end"
|
135
|
+
tbl.puts
|
136
|
+
|
137
|
+
indexes(table, tbl)
|
138
|
+
|
139
|
+
tbl.rewind
|
140
|
+
stream.print tbl.read
|
141
|
+
rescue => e
|
142
|
+
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
|
143
|
+
stream.puts "# #{e.message}"
|
144
|
+
stream.puts
|
145
|
+
end
|
146
|
+
|
147
|
+
stream
|
148
|
+
end
|
149
|
+
|
150
|
+
def default_string(value)
|
151
|
+
case value
|
152
|
+
when BigDecimal
|
153
|
+
value.to_s
|
154
|
+
when Date, DateTime, Time
|
155
|
+
"'" + value.to_s(:db) + "'"
|
156
|
+
else
|
157
|
+
value.inspect
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def indexes(table, stream)
|
162
|
+
indexes = @connection.indexes(table)
|
163
|
+
indexes.each do |index|
|
164
|
+
stream.print " add_index #{index.table.inspect}, #{index.columns.inspect}, :name => #{index.name.inspect}"
|
165
|
+
stream.print ", :unique => true" if index.unique
|
166
|
+
stream.puts
|
167
|
+
end
|
168
|
+
stream.puts unless indexes.empty?
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module ActiveRecord #:nodoc:
|
2
|
+
module Serialization
|
3
|
+
class Serializer #:nodoc:
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
def initialize(record, options = {})
|
7
|
+
@record, @options = record, options.dup
|
8
|
+
end
|
9
|
+
|
10
|
+
# To replicate the behavior in ActiveRecord#attributes,
|
11
|
+
# :except takes precedence over :only. If :only is not set
|
12
|
+
# for a N level model but is set for the N+1 level models,
|
13
|
+
# then because :except is set to a default value, the second
|
14
|
+
# level model can have both :except and :only set. So if
|
15
|
+
# :only is set, always delete :except.
|
16
|
+
def serializable_attribute_names
|
17
|
+
attribute_names = @record.attribute_names
|
18
|
+
|
19
|
+
if options[:only]
|
20
|
+
options.delete(:except)
|
21
|
+
attribute_names = attribute_names & Array(options[:only]).collect { |n| n.to_s }
|
22
|
+
else
|
23
|
+
options[:except] = Array(options[:except]) | Array(@record.class.inheritance_column)
|
24
|
+
attribute_names = attribute_names - options[:except].collect { |n| n.to_s }
|
25
|
+
end
|
26
|
+
|
27
|
+
attribute_names
|
28
|
+
end
|
29
|
+
|
30
|
+
def serializable_method_names
|
31
|
+
Array(options[:methods]).inject([]) do |method_attributes, name|
|
32
|
+
method_attributes << name if @record.respond_to?(name.to_s)
|
33
|
+
method_attributes
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def serializable_names
|
38
|
+
serializable_attribute_names + serializable_method_names
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add associations specified via the :includes option.
|
42
|
+
# Expects a block that takes as arguments:
|
43
|
+
# +association+ - name of the association
|
44
|
+
# +records+ - the association record(s) to be serialized
|
45
|
+
# +opts+ - options for the association records
|
46
|
+
def add_includes(&block)
|
47
|
+
if include_associations = options.delete(:include)
|
48
|
+
base_only_or_except = { :except => options[:except],
|
49
|
+
:only => options[:only] }
|
50
|
+
|
51
|
+
include_has_options = include_associations.is_a?(Hash)
|
52
|
+
associations = include_has_options ? include_associations.keys : Array(include_associations)
|
53
|
+
|
54
|
+
for association in associations
|
55
|
+
records = case @record.class.reflect_on_association(association).macro
|
56
|
+
when :has_many, :has_and_belongs_to_many
|
57
|
+
@record.send(association).to_a
|
58
|
+
when :has_one, :belongs_to
|
59
|
+
@record.send(association)
|
60
|
+
end
|
61
|
+
|
62
|
+
unless records.nil?
|
63
|
+
association_options = include_has_options ? include_associations[association] : base_only_or_except
|
64
|
+
opts = options.merge(association_options)
|
65
|
+
yield(association, records, opts)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
options[:include] = include_associations
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def serializable_record
|
74
|
+
returning(serializable_record = {}) do
|
75
|
+
serializable_names.each { |name| serializable_record[name] = @record.send(name) }
|
76
|
+
add_includes do |association, records, opts|
|
77
|
+
if records.is_a?(Enumerable)
|
78
|
+
serializable_record[association] = records.collect { |r| self.class.new(r, opts).serializable_record }
|
79
|
+
else
|
80
|
+
serializable_record[association] = self.class.new(records, opts).serializable_record
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def serialize
|
87
|
+
# overwrite to implement
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_s(&block)
|
91
|
+
serialize(&block)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
require 'active_record/serializers/xml_serializer'
|
98
|
+
require 'active_record/serializers/json_serializer'
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module ActiveRecord #:nodoc:
|
2
|
+
module Serialization
|
3
|
+
# Returns a JSON string representing the model. Some configuration is
|
4
|
+
# available through +options+.
|
5
|
+
#
|
6
|
+
# Without any +options+, the returned JSON string will include all
|
7
|
+
# the model's attributes. For example:
|
8
|
+
#
|
9
|
+
# konata = User.find(1)
|
10
|
+
# konata.to_json
|
11
|
+
#
|
12
|
+
# {"id": 1, "name": "Konata Izumi", "age": 16,
|
13
|
+
# "created_at": "2006/08/01", "awesome": true}
|
14
|
+
#
|
15
|
+
# The :only and :except options can be used to limit the attributes
|
16
|
+
# included, and work similar to the #attributes method. For example:
|
17
|
+
#
|
18
|
+
# konata.to_json(:only => [ :id, :name ])
|
19
|
+
#
|
20
|
+
# {"id": 1, "name": "Konata Izumi"}
|
21
|
+
#
|
22
|
+
# konata.to_json(:except => [ :id, :created_at, :age ])
|
23
|
+
#
|
24
|
+
# {"name": "Konata Izumi", "awesome": true}
|
25
|
+
#
|
26
|
+
# To include any methods on the model, use :methods.
|
27
|
+
#
|
28
|
+
# konata.to_json(:methods => :permalink)
|
29
|
+
#
|
30
|
+
# {"id": 1, "name": "Konata Izumi", "age": 16,
|
31
|
+
# "created_at": "2006/08/01", "awesome": true,
|
32
|
+
# "permalink": "1-konata-izumi"}
|
33
|
+
#
|
34
|
+
# To include associations, use :include.
|
35
|
+
#
|
36
|
+
# konata.to_json(:include => :posts)
|
37
|
+
#
|
38
|
+
# {"id": 1, "name": "Konata Izumi", "age": 16,
|
39
|
+
# "created_at": "2006/08/01", "awesome": true,
|
40
|
+
# "posts": [{"id": 1, "author_id": 1, "title": "Welcome to the weblog"},
|
41
|
+
# {"id": 2, author_id: 1, "title": "So I was thinking"}]}
|
42
|
+
#
|
43
|
+
# 2nd level and higher order associations work as well:
|
44
|
+
#
|
45
|
+
# konata.to_json(:include => { :posts => {
|
46
|
+
# :include => { :comments => {
|
47
|
+
# :only => :body } },
|
48
|
+
# :only => :title } })
|
49
|
+
#
|
50
|
+
# {"id": 1, "name": "Konata Izumi", "age": 16,
|
51
|
+
# "created_at": "2006/08/01", "awesome": true,
|
52
|
+
# "posts": [{"comments": [{"body": "1st post!"}, {"body": "Second!"}],
|
53
|
+
# "title": "Welcome to the weblog"},
|
54
|
+
# {"comments": [{"body": "Don't think too hard"}],
|
55
|
+
# "title": "So I was thinking"}]}
|
56
|
+
def to_json(options = {})
|
57
|
+
JsonSerializer.new(self, options).to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
def from_json(json)
|
61
|
+
self.attributes = ActiveSupport::JSON.decode(json)
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
class JsonSerializer < ActiveRecord::Serialization::Serializer #:nodoc:
|
66
|
+
def serialize
|
67
|
+
serializable_record.to_json
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,315 @@
|
|
1
|
+
module ActiveRecord #:nodoc:
|
2
|
+
module Serialization
|
3
|
+
# Builds an XML document to represent the model. Some configuration is
|
4
|
+
# available through +options+, however more complicated cases should
|
5
|
+
# override ActiveRecord's to_xml.
|
6
|
+
#
|
7
|
+
# By default the generated XML document will include the processing
|
8
|
+
# instruction and all object's attributes. For example:
|
9
|
+
#
|
10
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
11
|
+
# <topic>
|
12
|
+
# <title>The First Topic</title>
|
13
|
+
# <author-name>David</author-name>
|
14
|
+
# <id type="integer">1</id>
|
15
|
+
# <approved type="boolean">false</approved>
|
16
|
+
# <replies-count type="integer">0</replies-count>
|
17
|
+
# <bonus-time type="datetime">2000-01-01T08:28:00+12:00</bonus-time>
|
18
|
+
# <written-on type="datetime">2003-07-16T09:28:00+1200</written-on>
|
19
|
+
# <content>Have a nice day</content>
|
20
|
+
# <author-email-address>david@loudthinking.com</author-email-address>
|
21
|
+
# <parent-id></parent-id>
|
22
|
+
# <last-read type="date">2004-04-15</last-read>
|
23
|
+
# </topic>
|
24
|
+
#
|
25
|
+
# This behavior can be controlled with :only, :except,
|
26
|
+
# :skip_instruct, :skip_types and :dasherize. The :only and
|
27
|
+
# :except options are the same as for the #attributes method.
|
28
|
+
# The default is to dasherize all column names, to disable this,
|
29
|
+
# set :dasherize to false. To not have the column type included
|
30
|
+
# in the XML output, set :skip_types to true.
|
31
|
+
#
|
32
|
+
# For instance:
|
33
|
+
#
|
34
|
+
# topic.to_xml(:skip_instruct => true, :except => [ :id, :bonus_time, :written_on, :replies_count ])
|
35
|
+
#
|
36
|
+
# <topic>
|
37
|
+
# <title>The First Topic</title>
|
38
|
+
# <author-name>David</author-name>
|
39
|
+
# <approved type="boolean">false</approved>
|
40
|
+
# <content>Have a nice day</content>
|
41
|
+
# <author-email-address>david@loudthinking.com</author-email-address>
|
42
|
+
# <parent-id></parent-id>
|
43
|
+
# <last-read type="date">2004-04-15</last-read>
|
44
|
+
# </topic>
|
45
|
+
#
|
46
|
+
# To include first level associations use :include
|
47
|
+
#
|
48
|
+
# firm.to_xml :include => [ :account, :clients ]
|
49
|
+
#
|
50
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
51
|
+
# <firm>
|
52
|
+
# <id type="integer">1</id>
|
53
|
+
# <rating type="integer">1</rating>
|
54
|
+
# <name>37signals</name>
|
55
|
+
# <clients type="array">
|
56
|
+
# <client>
|
57
|
+
# <rating type="integer">1</rating>
|
58
|
+
# <name>Summit</name>
|
59
|
+
# </client>
|
60
|
+
# <client>
|
61
|
+
# <rating type="integer">1</rating>
|
62
|
+
# <name>Microsoft</name>
|
63
|
+
# </client>
|
64
|
+
# </clients>
|
65
|
+
# <account>
|
66
|
+
# <id type="integer">1</id>
|
67
|
+
# <credit-limit type="integer">50</credit-limit>
|
68
|
+
# </account>
|
69
|
+
# </firm>
|
70
|
+
#
|
71
|
+
# To include any methods on the object(s) being called use :methods
|
72
|
+
#
|
73
|
+
# firm.to_xml :methods => [ :calculated_earnings, :real_earnings ]
|
74
|
+
#
|
75
|
+
# <firm>
|
76
|
+
# # ... normal attributes as shown above ...
|
77
|
+
# <calculated-earnings>100000000000000000</calculated-earnings>
|
78
|
+
# <real-earnings>5</real-earnings>
|
79
|
+
# </firm>
|
80
|
+
#
|
81
|
+
# To call any Proc's on the object(s) use :procs. The Proc's
|
82
|
+
# are passed a modified version of the options hash that was
|
83
|
+
# given to #to_xml.
|
84
|
+
#
|
85
|
+
# proc = Proc.new { |options| options[:builder].tag!('abc', 'def') }
|
86
|
+
# firm.to_xml :procs => [ proc ]
|
87
|
+
#
|
88
|
+
# <firm>
|
89
|
+
# # ... normal attributes as shown above ...
|
90
|
+
# <abc>def</abc>
|
91
|
+
# </firm>
|
92
|
+
#
|
93
|
+
# Alternatively, you can also just yield the builder object as part of the to_xml call:
|
94
|
+
#
|
95
|
+
# firm.to_xml do |xml|
|
96
|
+
# xml.creator do
|
97
|
+
# xml.first_name "David"
|
98
|
+
# xml.last_name "Heinemeier Hansson"
|
99
|
+
# end
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# <firm>
|
103
|
+
# # ... normal attributes as shown above ...
|
104
|
+
# <creator>
|
105
|
+
# <first_name>David</first_name>
|
106
|
+
# <last_name>Heinemeier Hansson</last_name>
|
107
|
+
# </creator>
|
108
|
+
# </firm>
|
109
|
+
#
|
110
|
+
# You can override the to_xml method in your ActiveRecord::Base
|
111
|
+
# subclasses if you need to. The general form of doing this is
|
112
|
+
#
|
113
|
+
# class IHaveMyOwnXML < ActiveRecord::Base
|
114
|
+
# def to_xml(options = {})
|
115
|
+
# options[:indent] ||= 2
|
116
|
+
# xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
117
|
+
# xml.instruct! unless options[:skip_instruct]
|
118
|
+
# xml.level_one do
|
119
|
+
# xml.tag!(:second_level, 'content')
|
120
|
+
# end
|
121
|
+
# end
|
122
|
+
# end
|
123
|
+
def to_xml(options = {}, &block)
|
124
|
+
serializer = XmlSerializer.new(self, options)
|
125
|
+
block_given? ? serializer.to_s(&block) : serializer.to_s
|
126
|
+
end
|
127
|
+
|
128
|
+
def from_xml(xml)
|
129
|
+
self.attributes = Hash.from_xml(xml).values.first
|
130
|
+
self
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class XmlSerializer < ActiveRecord::Serialization::Serializer #:nodoc:
|
135
|
+
def builder
|
136
|
+
@builder ||= begin
|
137
|
+
options[:indent] ||= 2
|
138
|
+
builder = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
139
|
+
|
140
|
+
unless options[:skip_instruct]
|
141
|
+
builder.instruct!
|
142
|
+
options[:skip_instruct] = true
|
143
|
+
end
|
144
|
+
|
145
|
+
builder
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def root
|
150
|
+
root = (options[:root] || @record.class.to_s.underscore).to_s
|
151
|
+
dasherize? ? root.dasherize : root
|
152
|
+
end
|
153
|
+
|
154
|
+
def dasherize?
|
155
|
+
!options.has_key?(:dasherize) || options[:dasherize]
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
# To replicate the behavior in ActiveRecord#attributes,
|
160
|
+
# :except takes precedence over :only. If :only is not set
|
161
|
+
# for a N level model but is set for the N+1 level models,
|
162
|
+
# then because :except is set to a default value, the second
|
163
|
+
# level model can have both :except and :only set. So if
|
164
|
+
# :only is set, always delete :except.
|
165
|
+
def serializable_attributes
|
166
|
+
serializable_attribute_names.collect { |name| Attribute.new(name, @record) }
|
167
|
+
end
|
168
|
+
|
169
|
+
def serializable_method_attributes
|
170
|
+
Array(options[:methods]).inject([]) do |method_attributes, name|
|
171
|
+
method_attributes << MethodAttribute.new(name.to_s, @record) if @record.respond_to?(name.to_s)
|
172
|
+
method_attributes
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def add_attributes
|
177
|
+
(serializable_attributes + serializable_method_attributes).each do |attribute|
|
178
|
+
add_tag(attribute)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def add_procs
|
183
|
+
if procs = options.delete(:procs)
|
184
|
+
[ *procs ].each do |proc|
|
185
|
+
proc.call(options)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def add_tag(attribute)
|
191
|
+
builder.tag!(
|
192
|
+
dasherize? ? attribute.name.dasherize : attribute.name,
|
193
|
+
attribute.value.to_s,
|
194
|
+
attribute.decorations(!options[:skip_types])
|
195
|
+
)
|
196
|
+
end
|
197
|
+
|
198
|
+
def add_associations(association, records, opts)
|
199
|
+
if records.is_a?(Enumerable)
|
200
|
+
tag = association.to_s
|
201
|
+
tag = tag.dasherize if dasherize?
|
202
|
+
if records.empty?
|
203
|
+
builder.tag!(tag, :type => :array)
|
204
|
+
else
|
205
|
+
builder.tag!(tag, :type => :array) do
|
206
|
+
association_name = association.to_s.singularize
|
207
|
+
records.each do |record|
|
208
|
+
record.to_xml opts.merge(
|
209
|
+
:root => association_name,
|
210
|
+
:type => (record.class.to_s.underscore == association_name ? nil : record.class.name)
|
211
|
+
)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
else
|
216
|
+
if record = @record.send(association)
|
217
|
+
record.to_xml(opts.merge(:root => association))
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def serialize
|
223
|
+
args = [root]
|
224
|
+
if options[:namespace]
|
225
|
+
args << {:xmlns=>options[:namespace]}
|
226
|
+
end
|
227
|
+
|
228
|
+
if options[:type]
|
229
|
+
args << {:type=>options[:type]}
|
230
|
+
end
|
231
|
+
|
232
|
+
builder.tag!(*args) do
|
233
|
+
add_attributes
|
234
|
+
procs = options.delete(:procs)
|
235
|
+
add_includes { |association, records, opts| add_associations(association, records, opts) }
|
236
|
+
options[:procs] = procs
|
237
|
+
add_procs
|
238
|
+
yield builder if block_given?
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
class Attribute #:nodoc:
|
243
|
+
attr_reader :name, :value, :type
|
244
|
+
|
245
|
+
def initialize(name, record)
|
246
|
+
@name, @record = name, record
|
247
|
+
|
248
|
+
@type = compute_type
|
249
|
+
@value = compute_value
|
250
|
+
end
|
251
|
+
|
252
|
+
# There is a significant speed improvement if the value
|
253
|
+
# does not need to be escaped, as #tag! escapes all values
|
254
|
+
# to ensure that valid XML is generated. For known binary
|
255
|
+
# values, it is at least an order of magnitude faster to
|
256
|
+
# Base64 encode binary values and directly put them in the
|
257
|
+
# output XML than to pass the original value or the Base64
|
258
|
+
# encoded value to the #tag! method. It definitely makes
|
259
|
+
# no sense to Base64 encode the value and then give it to
|
260
|
+
# #tag!, since that just adds additional overhead.
|
261
|
+
def needs_encoding?
|
262
|
+
![ :binary, :date, :datetime, :boolean, :float, :integer ].include?(type)
|
263
|
+
end
|
264
|
+
|
265
|
+
def decorations(include_types = true)
|
266
|
+
decorations = {}
|
267
|
+
|
268
|
+
if type == :binary
|
269
|
+
decorations[:encoding] = 'base64'
|
270
|
+
end
|
271
|
+
|
272
|
+
if include_types && type != :string
|
273
|
+
decorations[:type] = type
|
274
|
+
end
|
275
|
+
|
276
|
+
if value.nil?
|
277
|
+
decorations[:nil] = true
|
278
|
+
end
|
279
|
+
|
280
|
+
decorations
|
281
|
+
end
|
282
|
+
|
283
|
+
protected
|
284
|
+
def compute_type
|
285
|
+
type = @record.class.serialized_attributes.has_key?(name) ? :yaml : @record.class.columns_hash[name].type
|
286
|
+
|
287
|
+
case type
|
288
|
+
when :text
|
289
|
+
:string
|
290
|
+
when :time
|
291
|
+
:datetime
|
292
|
+
else
|
293
|
+
type
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def compute_value
|
298
|
+
value = @record.send(name)
|
299
|
+
|
300
|
+
if formatter = Hash::XML_FORMATTING[type.to_s]
|
301
|
+
value ? formatter.call(value) : nil
|
302
|
+
else
|
303
|
+
value
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
class MethodAttribute < Attribute #:nodoc:
|
309
|
+
protected
|
310
|
+
def compute_type
|
311
|
+
Hash::XML_TYPE_NAMES[@record.send(name).class.name] || :string
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
# Active Record automatically timestamps create and update operations if the table has fields
|
3
|
+
# named created_at/created_on or updated_at/updated_on.
|
4
|
+
#
|
5
|
+
# Timestamping can be turned off by setting
|
6
|
+
# <tt>ActiveRecord::Base.record_timestamps = false</tt>
|
7
|
+
#
|
8
|
+
# Timestamps are in the local timezone by default but can use UTC by setting
|
9
|
+
# <tt>ActiveRecord::Base.default_timezone = :utc</tt>
|
10
|
+
module Timestamp
|
11
|
+
def self.included(base) #:nodoc:
|
12
|
+
base.alias_method_chain :create, :timestamps
|
13
|
+
base.alias_method_chain :update, :timestamps
|
14
|
+
|
15
|
+
base.class_inheritable_accessor :record_timestamps, :instance_writer => false
|
16
|
+
base.record_timestamps = true
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def create_with_timestamps #:nodoc:
|
21
|
+
if record_timestamps
|
22
|
+
t = self.class.default_timezone == :utc ? Time.now.utc : Time.now
|
23
|
+
write_attribute('created_at', t) if respond_to?(:created_at) && created_at.nil?
|
24
|
+
write_attribute('created_on', t) if respond_to?(:created_on) && created_on.nil?
|
25
|
+
|
26
|
+
write_attribute('updated_at', t) if respond_to?(:updated_at)
|
27
|
+
write_attribute('updated_on', t) if respond_to?(:updated_on)
|
28
|
+
end
|
29
|
+
create_without_timestamps
|
30
|
+
end
|
31
|
+
|
32
|
+
def update_with_timestamps #:nodoc:
|
33
|
+
if record_timestamps
|
34
|
+
t = self.class.default_timezone == :utc ? Time.now.utc : Time.now
|
35
|
+
write_attribute('updated_at', t) if respond_to?(:updated_at)
|
36
|
+
write_attribute('updated_on', t) if respond_to?(:updated_on)
|
37
|
+
end
|
38
|
+
update_without_timestamps
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|