activerecord_authorails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (270) hide show
  1. data/CHANGELOG +3043 -0
  2. data/README +360 -0
  3. data/RUNNING_UNIT_TESTS +64 -0
  4. data/Rakefile +226 -0
  5. data/examples/associations.png +0 -0
  6. data/examples/associations.rb +87 -0
  7. data/examples/shared_setup.rb +15 -0
  8. data/examples/validation.rb +85 -0
  9. data/install.rb +30 -0
  10. data/lib/active_record.rb +85 -0
  11. data/lib/active_record/acts/list.rb +244 -0
  12. data/lib/active_record/acts/nested_set.rb +211 -0
  13. data/lib/active_record/acts/tree.rb +89 -0
  14. data/lib/active_record/aggregations.rb +191 -0
  15. data/lib/active_record/associations.rb +1637 -0
  16. data/lib/active_record/associations/association_collection.rb +190 -0
  17. data/lib/active_record/associations/association_proxy.rb +158 -0
  18. data/lib/active_record/associations/belongs_to_association.rb +56 -0
  19. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  20. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +169 -0
  21. data/lib/active_record/associations/has_many_association.rb +210 -0
  22. data/lib/active_record/associations/has_many_through_association.rb +247 -0
  23. data/lib/active_record/associations/has_one_association.rb +80 -0
  24. data/lib/active_record/attribute_methods.rb +75 -0
  25. data/lib/active_record/base.rb +2164 -0
  26. data/lib/active_record/calculations.rb +270 -0
  27. data/lib/active_record/callbacks.rb +367 -0
  28. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +279 -0
  29. data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -0
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +58 -0
  31. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +343 -0
  32. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +310 -0
  33. data/lib/active_record/connection_adapters/abstract_adapter.rb +161 -0
  34. data/lib/active_record/connection_adapters/db2_adapter.rb +228 -0
  35. data/lib/active_record/connection_adapters/firebird_adapter.rb +728 -0
  36. data/lib/active_record/connection_adapters/frontbase_adapter.rb +861 -0
  37. data/lib/active_record/connection_adapters/mysql_adapter.rb +414 -0
  38. data/lib/active_record/connection_adapters/openbase_adapter.rb +350 -0
  39. data/lib/active_record/connection_adapters/oracle_adapter.rb +689 -0
  40. data/lib/active_record/connection_adapters/postgresql_adapter.rb +584 -0
  41. data/lib/active_record/connection_adapters/sqlite_adapter.rb +407 -0
  42. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +591 -0
  43. data/lib/active_record/connection_adapters/sybase_adapter.rb +662 -0
  44. data/lib/active_record/deprecated_associations.rb +104 -0
  45. data/lib/active_record/deprecated_finders.rb +44 -0
  46. data/lib/active_record/fixtures.rb +628 -0
  47. data/lib/active_record/locking/optimistic.rb +106 -0
  48. data/lib/active_record/locking/pessimistic.rb +77 -0
  49. data/lib/active_record/migration.rb +394 -0
  50. data/lib/active_record/observer.rb +178 -0
  51. data/lib/active_record/query_cache.rb +64 -0
  52. data/lib/active_record/reflection.rb +222 -0
  53. data/lib/active_record/schema.rb +58 -0
  54. data/lib/active_record/schema_dumper.rb +149 -0
  55. data/lib/active_record/timestamp.rb +51 -0
  56. data/lib/active_record/transactions.rb +136 -0
  57. data/lib/active_record/validations.rb +843 -0
  58. data/lib/active_record/vendor/db2.rb +362 -0
  59. data/lib/active_record/vendor/mysql.rb +1214 -0
  60. data/lib/active_record/vendor/simple.rb +693 -0
  61. data/lib/active_record/version.rb +9 -0
  62. data/lib/active_record/wrappers/yaml_wrapper.rb +15 -0
  63. data/lib/active_record/wrappings.rb +58 -0
  64. data/lib/active_record/xml_serialization.rb +308 -0
  65. data/test/aaa_create_tables_test.rb +59 -0
  66. data/test/abstract_unit.rb +77 -0
  67. data/test/active_schema_test_mysql.rb +31 -0
  68. data/test/adapter_test.rb +87 -0
  69. data/test/adapter_test_sqlserver.rb +81 -0
  70. data/test/aggregations_test.rb +95 -0
  71. data/test/all.sh +8 -0
  72. data/test/ar_schema_test.rb +33 -0
  73. data/test/association_inheritance_reload.rb +14 -0
  74. data/test/associations/callbacks_test.rb +126 -0
  75. data/test/associations/cascaded_eager_loading_test.rb +138 -0
  76. data/test/associations/eager_test.rb +393 -0
  77. data/test/associations/extension_test.rb +42 -0
  78. data/test/associations/join_model_test.rb +497 -0
  79. data/test/associations_test.rb +1809 -0
  80. data/test/attribute_methods_test.rb +49 -0
  81. data/test/base_test.rb +1586 -0
  82. data/test/binary_test.rb +37 -0
  83. data/test/calculations_test.rb +219 -0
  84. data/test/callbacks_test.rb +377 -0
  85. data/test/class_inheritable_attributes_test.rb +32 -0
  86. data/test/column_alias_test.rb +17 -0
  87. data/test/connection_test_firebird.rb +8 -0
  88. data/test/connections/native_db2/connection.rb +25 -0
  89. data/test/connections/native_firebird/connection.rb +26 -0
  90. data/test/connections/native_frontbase/connection.rb +27 -0
  91. data/test/connections/native_mysql/connection.rb +24 -0
  92. data/test/connections/native_openbase/connection.rb +21 -0
  93. data/test/connections/native_oracle/connection.rb +27 -0
  94. data/test/connections/native_postgresql/connection.rb +23 -0
  95. data/test/connections/native_sqlite/connection.rb +34 -0
  96. data/test/connections/native_sqlite3/connection.rb +34 -0
  97. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  98. data/test/connections/native_sqlserver/connection.rb +23 -0
  99. data/test/connections/native_sqlserver_odbc/connection.rb +25 -0
  100. data/test/connections/native_sybase/connection.rb +23 -0
  101. data/test/copy_table_sqlite.rb +64 -0
  102. data/test/datatype_test_postgresql.rb +52 -0
  103. data/test/default_test_firebird.rb +16 -0
  104. data/test/defaults_test.rb +60 -0
  105. data/test/deprecated_associations_test.rb +396 -0
  106. data/test/deprecated_finder_test.rb +151 -0
  107. data/test/empty_date_time_test.rb +25 -0
  108. data/test/finder_test.rb +504 -0
  109. data/test/fixtures/accounts.yml +28 -0
  110. data/test/fixtures/author.rb +99 -0
  111. data/test/fixtures/author_favorites.yml +4 -0
  112. data/test/fixtures/authors.yml +7 -0
  113. data/test/fixtures/auto_id.rb +4 -0
  114. data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
  115. data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
  116. data/test/fixtures/bad_fixtures/blank_line +3 -0
  117. data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
  118. data/test/fixtures/bad_fixtures/missing_value +1 -0
  119. data/test/fixtures/binary.rb +2 -0
  120. data/test/fixtures/categories.yml +14 -0
  121. data/test/fixtures/categories/special_categories.yml +9 -0
  122. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  123. data/test/fixtures/categories_ordered.yml +7 -0
  124. data/test/fixtures/categories_posts.yml +23 -0
  125. data/test/fixtures/categorization.rb +5 -0
  126. data/test/fixtures/categorizations.yml +17 -0
  127. data/test/fixtures/category.rb +20 -0
  128. data/test/fixtures/column_name.rb +3 -0
  129. data/test/fixtures/comment.rb +23 -0
  130. data/test/fixtures/comments.yml +59 -0
  131. data/test/fixtures/companies.yml +55 -0
  132. data/test/fixtures/company.rb +107 -0
  133. data/test/fixtures/company_in_module.rb +59 -0
  134. data/test/fixtures/computer.rb +3 -0
  135. data/test/fixtures/computers.yml +4 -0
  136. data/test/fixtures/course.rb +3 -0
  137. data/test/fixtures/courses.yml +7 -0
  138. data/test/fixtures/customer.rb +55 -0
  139. data/test/fixtures/customers.yml +17 -0
  140. data/test/fixtures/db_definitions/db2.drop.sql +32 -0
  141. data/test/fixtures/db_definitions/db2.sql +231 -0
  142. data/test/fixtures/db_definitions/db22.drop.sql +2 -0
  143. data/test/fixtures/db_definitions/db22.sql +5 -0
  144. data/test/fixtures/db_definitions/firebird.drop.sql +63 -0
  145. data/test/fixtures/db_definitions/firebird.sql +304 -0
  146. data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
  147. data/test/fixtures/db_definitions/firebird2.sql +6 -0
  148. data/test/fixtures/db_definitions/frontbase.drop.sql +32 -0
  149. data/test/fixtures/db_definitions/frontbase.sql +268 -0
  150. data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
  151. data/test/fixtures/db_definitions/frontbase2.sql +4 -0
  152. data/test/fixtures/db_definitions/mysql.drop.sql +32 -0
  153. data/test/fixtures/db_definitions/mysql.sql +234 -0
  154. data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
  155. data/test/fixtures/db_definitions/mysql2.sql +5 -0
  156. data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
  157. data/test/fixtures/db_definitions/openbase.sql +302 -0
  158. data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
  159. data/test/fixtures/db_definitions/openbase2.sql +7 -0
  160. data/test/fixtures/db_definitions/oracle.drop.sql +65 -0
  161. data/test/fixtures/db_definitions/oracle.sql +325 -0
  162. data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
  163. data/test/fixtures/db_definitions/oracle2.sql +6 -0
  164. data/test/fixtures/db_definitions/postgresql.drop.sql +37 -0
  165. data/test/fixtures/db_definitions/postgresql.sql +263 -0
  166. data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
  167. data/test/fixtures/db_definitions/postgresql2.sql +5 -0
  168. data/test/fixtures/db_definitions/schema.rb +60 -0
  169. data/test/fixtures/db_definitions/sqlite.drop.sql +32 -0
  170. data/test/fixtures/db_definitions/sqlite.sql +215 -0
  171. data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
  172. data/test/fixtures/db_definitions/sqlite2.sql +5 -0
  173. data/test/fixtures/db_definitions/sqlserver.drop.sql +34 -0
  174. data/test/fixtures/db_definitions/sqlserver.sql +243 -0
  175. data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
  176. data/test/fixtures/db_definitions/sqlserver2.sql +5 -0
  177. data/test/fixtures/db_definitions/sybase.drop.sql +34 -0
  178. data/test/fixtures/db_definitions/sybase.sql +218 -0
  179. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  180. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  181. data/test/fixtures/default.rb +2 -0
  182. data/test/fixtures/developer.rb +52 -0
  183. data/test/fixtures/developers.yml +21 -0
  184. data/test/fixtures/developers_projects.yml +17 -0
  185. data/test/fixtures/developers_projects/david_action_controller +3 -0
  186. data/test/fixtures/developers_projects/david_active_record +3 -0
  187. data/test/fixtures/developers_projects/jamis_active_record +2 -0
  188. data/test/fixtures/edge.rb +5 -0
  189. data/test/fixtures/edges.yml +6 -0
  190. data/test/fixtures/entrant.rb +3 -0
  191. data/test/fixtures/entrants.yml +14 -0
  192. data/test/fixtures/fk_test_has_fk.yml +3 -0
  193. data/test/fixtures/fk_test_has_pk.yml +2 -0
  194. data/test/fixtures/flowers.jpg +0 -0
  195. data/test/fixtures/funny_jokes.yml +10 -0
  196. data/test/fixtures/joke.rb +6 -0
  197. data/test/fixtures/keyboard.rb +3 -0
  198. data/test/fixtures/legacy_thing.rb +3 -0
  199. data/test/fixtures/legacy_things.yml +3 -0
  200. data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
  201. data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
  202. data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
  203. data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
  204. data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
  205. data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
  206. data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
  207. data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
  208. data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
  209. data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
  210. data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
  211. data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
  212. data/test/fixtures/mixed_case_monkey.rb +3 -0
  213. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  214. data/test/fixtures/mixin.rb +63 -0
  215. data/test/fixtures/mixins.yml +127 -0
  216. data/test/fixtures/movie.rb +5 -0
  217. data/test/fixtures/movies.yml +7 -0
  218. data/test/fixtures/naked/csv/accounts.csv +1 -0
  219. data/test/fixtures/naked/yml/accounts.yml +1 -0
  220. data/test/fixtures/naked/yml/companies.yml +1 -0
  221. data/test/fixtures/naked/yml/courses.yml +1 -0
  222. data/test/fixtures/order.rb +4 -0
  223. data/test/fixtures/people.yml +3 -0
  224. data/test/fixtures/person.rb +4 -0
  225. data/test/fixtures/post.rb +58 -0
  226. data/test/fixtures/posts.yml +48 -0
  227. data/test/fixtures/project.rb +27 -0
  228. data/test/fixtures/projects.yml +7 -0
  229. data/test/fixtures/reader.rb +4 -0
  230. data/test/fixtures/readers.yml +4 -0
  231. data/test/fixtures/reply.rb +37 -0
  232. data/test/fixtures/subject.rb +4 -0
  233. data/test/fixtures/subscriber.rb +6 -0
  234. data/test/fixtures/subscribers/first +2 -0
  235. data/test/fixtures/subscribers/second +2 -0
  236. data/test/fixtures/tag.rb +7 -0
  237. data/test/fixtures/tagging.rb +6 -0
  238. data/test/fixtures/taggings.yml +18 -0
  239. data/test/fixtures/tags.yml +7 -0
  240. data/test/fixtures/task.rb +3 -0
  241. data/test/fixtures/tasks.yml +7 -0
  242. data/test/fixtures/topic.rb +25 -0
  243. data/test/fixtures/topics.yml +22 -0
  244. data/test/fixtures/vertex.rb +9 -0
  245. data/test/fixtures/vertices.yml +4 -0
  246. data/test/fixtures_test.rb +401 -0
  247. data/test/inheritance_test.rb +205 -0
  248. data/test/lifecycle_test.rb +137 -0
  249. data/test/locking_test.rb +190 -0
  250. data/test/method_scoping_test.rb +416 -0
  251. data/test/migration_test.rb +768 -0
  252. data/test/migration_test_firebird.rb +124 -0
  253. data/test/mixin_nested_set_test.rb +196 -0
  254. data/test/mixin_test.rb +550 -0
  255. data/test/modules_test.rb +34 -0
  256. data/test/multiple_db_test.rb +60 -0
  257. data/test/pk_test.rb +104 -0
  258. data/test/readonly_test.rb +107 -0
  259. data/test/reflection_test.rb +159 -0
  260. data/test/schema_authorization_test_postgresql.rb +75 -0
  261. data/test/schema_dumper_test.rb +96 -0
  262. data/test/schema_test_postgresql.rb +64 -0
  263. data/test/synonym_test_oracle.rb +17 -0
  264. data/test/table_name_test_sqlserver.rb +23 -0
  265. data/test/threaded_connections_test.rb +48 -0
  266. data/test/transactions_test.rb +230 -0
  267. data/test/unconnected_test.rb +32 -0
  268. data/test/validations_test.rb +1097 -0
  269. data/test/xml_serialization_test.rb +125 -0
  270. metadata +365 -0
data/README ADDED
@@ -0,0 +1,360 @@
1
+ = Active Record -- Object-relation mapping put on rails
2
+
3
+ Active Record connects business objects and database tables to create a persistable
4
+ domain model where logic and data are presented in one wrapping. It's an implementation
5
+ of the object-relational mapping (ORM) pattern[http://www.martinfowler.com/eaaCatalog/activeRecord.html]
6
+ by the same name as described by Martin Fowler:
7
+
8
+ "An object that wraps a row in a database table or view, encapsulates
9
+ the database access, and adds domain logic on that data."
10
+
11
+ Active Record's main contribution to the pattern is to relieve the original of two stunting problems:
12
+ lack of associations and inheritance. By adding a simple domain language-like set of macros to describe
13
+ the former and integrating the Single Table Inheritance pattern for the latter, Active Record narrows the
14
+ gap of functionality between the data mapper and active record approach.
15
+
16
+ A short rundown of the major features:
17
+
18
+ * Automated mapping between classes and tables, attributes and columns.
19
+
20
+ class Product < ActiveRecord::Base; end
21
+
22
+ ...is automatically mapped to the table named "products", such as:
23
+
24
+ CREATE TABLE products (
25
+ id int(11) NOT NULL auto_increment,
26
+ name varchar(255),
27
+ PRIMARY KEY (id)
28
+ );
29
+
30
+ ...which again gives Product#name and Product#name=(new_name)
31
+
32
+ {Learn more}[link:classes/ActiveRecord/Base.html]
33
+
34
+
35
+ * Associations between objects controlled by simple meta-programming macros.
36
+
37
+ class Firm < ActiveRecord::Base
38
+ has_many :clients
39
+ has_one :account
40
+ belongs_to :conglomorate
41
+ end
42
+
43
+ {Learn more}[link:classes/ActiveRecord/Associations/ClassMethods.html]
44
+
45
+
46
+ * Aggregations of value objects controlled by simple meta-programming macros.
47
+
48
+ class Account < ActiveRecord::Base
49
+ composed_of :balance, :class_name => "Money",
50
+ :mapping => %w(balance amount)
51
+ composed_of :address,
52
+ :mapping => [%w(address_street street), %w(address_city city)]
53
+ end
54
+
55
+ {Learn more}[link:classes/ActiveRecord/Aggregations/ClassMethods.html]
56
+
57
+
58
+ * Validation rules that can differ for new or existing objects.
59
+
60
+ class Account < ActiveRecord::Base
61
+ validates_presence_of :subdomain, :name, :email_address, :password
62
+ validates_uniqueness_of :subdomain
63
+ validates_acceptance_of :terms_of_service, :on => :create
64
+ validates_confirmation_of :password, :email_address, :on => :create
65
+ end
66
+
67
+ {Learn more}[link:classes/ActiveRecord/Validations.html]
68
+
69
+
70
+ * Acts that can make records work as lists or trees:
71
+
72
+ class Item < ActiveRecord::Base
73
+ belongs_to :list
74
+ acts_as_list :scope => :list
75
+ end
76
+
77
+ item.move_higher
78
+ item.move_to_bottom
79
+
80
+ Learn about {acts_as_list}[link:classes/ActiveRecord/Acts/List/ClassMethods.html], {the instance methods acts_as_list provides}[link:classes/ActiveRecord/Acts/List/InstanceMethods.html], and
81
+ {acts_as_tree}[link:classes/ActiveRecord/Acts/Tree/ClassMethods.html]
82
+
83
+ * Callbacks as methods or queues on the entire lifecycle (instantiation, saving, destroying, validating, etc).
84
+
85
+ class Person < ActiveRecord::Base
86
+ def before_destroy # is called just before Person#destroy
87
+ CreditCard.find(credit_card_id).destroy
88
+ end
89
+ end
90
+
91
+ class Account < ActiveRecord::Base
92
+ after_find :eager_load, 'self.class.announce(#{id})'
93
+ end
94
+
95
+ {Learn more}[link:classes/ActiveRecord/Callbacks.html]
96
+
97
+
98
+ * Observers for the entire lifecycle
99
+
100
+ class CommentObserver < ActiveRecord::Observer
101
+ def after_create(comment) # is called just after Comment#save
102
+ Notifications.deliver_new_comment("david@loudthinking.com", comment)
103
+ end
104
+ end
105
+
106
+ {Learn more}[link:classes/ActiveRecord/Observer.html]
107
+
108
+
109
+ * Inheritance hierarchies
110
+
111
+ class Company < ActiveRecord::Base; end
112
+ class Firm < Company; end
113
+ class Client < Company; end
114
+ class PriorityClient < Client; end
115
+
116
+ {Learn more}[link:classes/ActiveRecord/Base.html]
117
+
118
+
119
+ * Transaction support on both a database and object level. The latter is implemented
120
+ by using Transaction::Simple[http://railsmanual.com/module/Transaction::Simple]
121
+
122
+ # Just database transaction
123
+ Account.transaction do
124
+ david.withdrawal(100)
125
+ mary.deposit(100)
126
+ end
127
+
128
+ # Database and object transaction
129
+ Account.transaction(david, mary) do
130
+ david.withdrawal(100)
131
+ mary.deposit(100)
132
+ end
133
+
134
+ {Learn more}[link:classes/ActiveRecord/Transactions/ClassMethods.html]
135
+
136
+
137
+ * Reflections on columns, associations, and aggregations
138
+
139
+ reflection = Firm.reflect_on_association(:clients)
140
+ reflection.klass # => Client (class)
141
+ Firm.columns # Returns an array of column descriptors for the firms table
142
+
143
+ {Learn more}[link:classes/ActiveRecord/Reflection/ClassMethods.html]
144
+
145
+
146
+ * Direct manipulation (instead of service invocation)
147
+
148
+ So instead of (Hibernate[http://www.hibernate.org/] example):
149
+
150
+ long pkId = 1234;
151
+ DomesticCat pk = (DomesticCat) sess.load( Cat.class, new Long(pkId) );
152
+ // something interesting involving a cat...
153
+ sess.save(cat);
154
+ sess.flush(); // force the SQL INSERT
155
+
156
+ Active Record lets you:
157
+
158
+ pkId = 1234
159
+ cat = Cat.find(pkId)
160
+ # something even more interesting involving the same cat...
161
+ cat.save
162
+
163
+ {Learn more}[link:classes/ActiveRecord/Base.html]
164
+
165
+
166
+ * Database abstraction through simple adapters (~100 lines) with a shared connector
167
+
168
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite", :database => "dbfile")
169
+
170
+ ActiveRecord::Base.establish_connection(
171
+ :adapter => "mysql",
172
+ :host => "localhost",
173
+ :username => "me",
174
+ :password => "secret",
175
+ :database => "activerecord"
176
+ )
177
+
178
+ {Learn more}[link:classes/ActiveRecord/Base.html#M000081] and read about the built-in support for
179
+ MySQL[link:classes/ActiveRecord/ConnectionAdapters/MysqlAdapter.html], PostgreSQL[link:classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter.html], SQLite[link:classes/ActiveRecord/ConnectionAdapters/SQLiteAdapter.html], Oracle[link:classes/ActiveRecord/ConnectionAdapters/OCIAdapter.html], SQLServer[link:classes/ActiveRecord/ConnectionAdapters/SQLServerAdapter.html], and DB2[link:classes/ActiveRecord/ConnectionAdapters/DB2Adapter.html].
180
+
181
+
182
+ * Logging support for Log4r[http://log4r.sourceforge.net] and Logger[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc]
183
+
184
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
185
+ ActiveRecord::Base.logger = Log4r::Logger.new("Application Log")
186
+
187
+
188
+ == Simple example (1/2): Defining tables and classes (using MySQL)
189
+
190
+ Data definitions are specified only in the database. Active Record queries the database for
191
+ the column names (that then serves to determine which attributes are valid) on regular
192
+ object instantiation through the new constructor and relies on the column names in the rows
193
+ with the finders.
194
+
195
+ # CREATE TABLE companies (
196
+ # id int(11) unsigned NOT NULL auto_increment,
197
+ # client_of int(11),
198
+ # name varchar(255),
199
+ # type varchar(100),
200
+ # PRIMARY KEY (id)
201
+ # )
202
+
203
+ Active Record automatically links the "Company" object to the "companies" table
204
+
205
+ class Company < ActiveRecord::Base
206
+ has_many :people, :class_name => "Person"
207
+ end
208
+
209
+ class Firm < Company
210
+ has_many :clients
211
+
212
+ def people_with_all_clients
213
+ clients.inject([]) { |people, client| people + client.people }
214
+ end
215
+ end
216
+
217
+ The foreign_key is only necessary because we didn't use "firm_id" in the data definition
218
+
219
+ class Client < Company
220
+ belongs_to :firm, :foreign_key => "client_of"
221
+ end
222
+
223
+ # CREATE TABLE people (
224
+ # id int(11) unsigned NOT NULL auto_increment,
225
+ # name text,
226
+ # company_id text,
227
+ # PRIMARY KEY (id)
228
+ # )
229
+
230
+ Active Record will also automatically link the "Person" object to the "people" table
231
+
232
+ class Person < ActiveRecord::Base
233
+ belongs_to :company
234
+ end
235
+
236
+ == Simple example (2/2): Using the domain
237
+
238
+ Picking a database connection for all the Active Records
239
+
240
+ ActiveRecord::Base.establish_connection(
241
+ :adapter => "mysql",
242
+ :host => "localhost",
243
+ :username => "me",
244
+ :password => "secret",
245
+ :database => "activerecord"
246
+ )
247
+
248
+ Create some fixtures
249
+
250
+ firm = Firm.new("name" => "Next Angle")
251
+ # SQL: INSERT INTO companies (name, type) VALUES("Next Angle", "Firm")
252
+ firm.save
253
+
254
+ client = Client.new("name" => "37signals", "client_of" => firm.id)
255
+ # SQL: INSERT INTO companies (name, client_of, type) VALUES("37signals", 1, "Firm")
256
+ client.save
257
+
258
+ Lots of different finders
259
+
260
+ # SQL: SELECT * FROM companies WHERE id = 1
261
+ next_angle = Company.find(1)
262
+
263
+ # SQL: SELECT * FROM companies WHERE id = 1 AND type = 'Firm'
264
+ next_angle = Firm.find(1)
265
+
266
+ # SQL: SELECT * FROM companies WHERE id = 1 AND name = 'Next Angle'
267
+ next_angle = Company.find(:first, :conditions => "name = 'Next Angle'")
268
+
269
+ next_angle = Firm.find_by_sql("SELECT * FROM companies WHERE id = 1").first
270
+
271
+ The supertype, Company, will return subtype instances
272
+
273
+ Firm === next_angle
274
+
275
+ All the dynamic methods added by the has_many macro
276
+
277
+ next_angle.clients.empty? # true
278
+ next_angle.clients.size # total number of clients
279
+ all_clients = next_angle.clients
280
+
281
+ Constrained finds makes access security easier when ID comes from a web-app
282
+
283
+ # SQL: SELECT * FROM companies WHERE client_of = 1 AND type = 'Client' AND id = 2
284
+ thirty_seven_signals = next_angle.clients.find(2)
285
+
286
+ Bi-directional associations thanks to the "belongs_to" macro
287
+
288
+ thirty_seven_signals.firm.nil? # true
289
+
290
+
291
+ == Examples
292
+
293
+ Active Record ships with a couple of examples that should give you a good feel for
294
+ operating usage. Be sure to edit the <tt>examples/shared_setup.rb</tt> file for your
295
+ own database before running the examples. Possibly also the table definition SQL in
296
+ the examples themselves.
297
+
298
+ It's also highly recommended to have a look at the unit tests. Read more in link:files/RUNNING_UNIT_TESTS.html
299
+
300
+
301
+ == Philosophy
302
+
303
+ Active Record attempts to provide a coherent wrapper as a solution for the inconvenience that is
304
+ object-relational mapping. The prime directive for this mapping has been to minimize
305
+ the amount of code needed to build a real-world domain model. This is made possible
306
+ by relying on a number of conventions that make it easy for Active Record to infer
307
+ complex relations and structures from a minimal amount of explicit direction.
308
+
309
+ Convention over Configuration:
310
+ * No XML-files!
311
+ * Lots of reflection and run-time extension
312
+ * Magic is not inherently a bad word
313
+
314
+ Admit the Database:
315
+ * Lets you drop down to SQL for odd cases and performance
316
+ * Doesn't attempt to duplicate or replace data definitions
317
+
318
+
319
+ == Download
320
+
321
+ The latest version of Active Record can be found at
322
+
323
+ * http://rubyforge.org/project/showfiles.php?group_id=182
324
+
325
+ Documentation can be found at
326
+
327
+ * http://ar.rubyonrails.com
328
+
329
+
330
+ == Installation
331
+
332
+ The prefered method of installing Active Record is through its GEM file. You'll need to have
333
+ RubyGems[http://rubygems.rubyforge.org/wiki/wiki.pl] installed for that, though. If you have,
334
+ then use:
335
+
336
+ % [sudo] gem install activerecord-1.10.0.gem
337
+
338
+ You can also install Active Record the old-fashion way with the following command:
339
+
340
+ % [sudo] ruby install.rb
341
+
342
+ from its distribution directory.
343
+
344
+
345
+ == License
346
+
347
+ Active Record is released under the MIT license.
348
+
349
+
350
+ == Support
351
+
352
+ The Active Record homepage is http://www.rubyonrails.com. You can find the Active Record
353
+ RubyForge page at http://rubyforge.org/projects/activerecord. And as Jim from Rake says:
354
+
355
+ Feel free to submit commits or feature requests. If you send a patch,
356
+ remember to update the corresponding unit tests. If fact, I prefer
357
+ new feature to be submitted in the form of new unit tests.
358
+
359
+ For other information, feel free to ask on the ruby-talk mailing list
360
+ (which is mirrored to comp.lang.ruby) or contact mailto:david@loudthinking.com.
@@ -0,0 +1,64 @@
1
+ == Creating the test database
2
+
3
+ The default names for the test databases are "activerecord_unittest" and
4
+ "activerecord_unittest2". If you want to use another database name then be sure
5
+ to update the connection adapter setups you want to test with in
6
+ test/connections/<your database>/connection.rb.
7
+ When you have the database online, you can import the fixture tables with
8
+ the test/fixtures/db_definitions/*.sql files.
9
+
10
+ Make sure that you create database objects with the same user that you specified in
11
+ connection.rb otherwise (on Postgres, at least) tests for default values will fail.
12
+
13
+ == Running with Rake
14
+
15
+ The easiest way to run the unit tests is through Rake. The default task runs
16
+ the entire test suite for all the adapters. You can also run the suite on just
17
+ one adapter by using the tasks test_mysql, test_sqlite, test_postgresql or any
18
+ of the other test_ tasks. For more information, checkout the full array of rake
19
+ tasks with "rake -T"
20
+
21
+ Rake can be found at http://rake.rubyforge.org
22
+
23
+ == Running by hand
24
+
25
+ Unit tests are located in test directory. If you only want to run a single test suite,
26
+ or don't want to bother with Rake, you can do so with something like:
27
+
28
+ cd test; ruby -I "connections/native_mysql" base_test.rb
29
+
30
+ That'll run the base suite using the MySQL-Ruby adapter. Change the adapter
31
+ and test suite name as needed.
32
+
33
+ You can also run all the suites on a specific adapter with:
34
+
35
+ cd test; all.sh "connections/native_mysql"
36
+
37
+ == Faster tests
38
+
39
+ If you are using a database that supports transactions, you can set the
40
+ "AR_TX_FIXTURES" environment variable to "yes" to use transactional fixtures.
41
+ This gives a very large speed boost. With rake:
42
+
43
+ rake AR_TX_FIXTURES=yes
44
+
45
+ Or, by hand:
46
+
47
+ AR_TX_FIXTURES=yes ruby -I connections/native_sqlite3 base_test.rb
48
+
49
+ == Testing with Oracle
50
+
51
+ In order to allow for testing against Oracle using an "arunit" schema within an existing
52
+ Oracle database, the database name and tns connection string must be set in environment
53
+ variables prior to running the unit tests.
54
+
55
+ $ export ARUNIT_DB_NAME=MYDB
56
+ $ export ARUNIT_DB=MYDB
57
+
58
+ The ARUNIT_DB_NAME variable should be set to the name by which the database knows
59
+ itself, ie., what will be returned by the query:
60
+
61
+ select sys_context('userenv','db_name') db from dual
62
+
63
+ And the ARUNIT_DB variable should be set to the tns connection string.
64
+
@@ -0,0 +1,226 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/contrib/rubyforgepublisher'
8
+ require File.join(File.dirname(__FILE__), 'lib', 'active_record', 'version')
9
+
10
+ PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
11
+ PKG_NAME = 'activerecord'
12
+ PKG_VERSION = ActiveRecord::VERSION::STRING + PKG_BUILD
13
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
14
+
15
+ RELEASE_NAME = "REL #{PKG_VERSION}"
16
+
17
+ RUBY_FORGE_PROJECT = "activerecord"
18
+ RUBY_FORGE_USER = "webster132"
19
+
20
+ PKG_FILES = FileList[
21
+ "lib/**/*", "test/**/*", "examples/**/*", "doc/**/*", "[A-Z]*", "install.rb", "Rakefile"
22
+ ].exclude(/\bCVS\b|~$/)
23
+
24
+
25
+ desc "Default Task"
26
+ task :default => [ :test_mysql, :test_sqlite, :test_postgresql ]
27
+
28
+ # Run the unit tests
29
+
30
+ for adapter in %w( mysql postgresql sqlite sqlite3 firebird sqlserver sqlserver_odbc db2 oracle sybase openbase frontbase )
31
+ Rake::TestTask.new("test_#{adapter}") { |t|
32
+ t.libs << "test" << "test/connections/native_#{adapter}"
33
+ if adapter =~ /^sqlserver/
34
+ t.pattern = "test/**/*_test{,_sqlserver}.rb"
35
+ else
36
+ t.pattern = "test/**/*_test{,_#{adapter}}.rb"
37
+ end
38
+ t.verbose = true
39
+ }
40
+ end
41
+
42
+ SCHEMA_PATH = File.join(File.dirname(__FILE__), *%w(test fixtures db_definitions))
43
+
44
+ desc 'Build the MySQL test databases'
45
+ task :build_mysql_databases do
46
+ %x( mysqladmin create activerecord_unittest )
47
+ %x( mysqladmin create activerecord_unittest2 )
48
+ %x( mysql -e "grant all on activerecord_unittest.* to rails@localhost" )
49
+ %x( mysql -e "grant all on activerecord_unittest2.* to rails@localhost" )
50
+ %x( mysql activerecord_unittest < #{File.join(SCHEMA_PATH, 'mysql.sql')} )
51
+ %x( mysql activerecord_unittest < #{File.join(SCHEMA_PATH, 'mysql2.sql')} )
52
+ end
53
+
54
+ desc 'Drop the MySQL test databases'
55
+ task :drop_mysql_databases do
56
+ %x( mysqladmin -f drop activerecord_unittest )
57
+ %x( mysqladmin -f drop activerecord_unittest2 )
58
+ end
59
+
60
+ desc 'Rebuild the MySQL test databases'
61
+ task :rebuild_mysql_databases => [:drop_mysql_databases, :build_mysql_databases]
62
+
63
+ desc 'Build the PostgreSQL test databases'
64
+ task :build_postgresql_databases do
65
+ %x( createdb -U postgres activerecord_unittest )
66
+ %x( createdb -U postgres activerecord_unittest2 )
67
+ %x( psql activerecord_unittest -f #{File.join(SCHEMA_PATH, 'postgresql.sql')} postgres )
68
+ %x( psql activerecord_unittest2 -f #{File.join(SCHEMA_PATH, 'postgresql2.sql')} postgres )
69
+ end
70
+
71
+ desc 'Drop the PostgreSQL test databases'
72
+ task :drop_postgresql_databases do
73
+ %x( dropdb -U postgres activerecord_unittest )
74
+ %x( dropdb -U postgres activerecord_unittest2 )
75
+ end
76
+
77
+ desc 'Rebuild the PostgreSQL test databases'
78
+ task :rebuild_postgresql_databases => [:drop_postgresql_databases, :build_postgresql_databases]
79
+
80
+ desc 'Build the FrontBase test databases'
81
+ task :build_frontbase_databases => :rebuild_frontbase_databases
82
+
83
+ desc 'Rebuild the FrontBase test databases'
84
+ task :rebuild_frontbase_databases do
85
+ build_frontbase_database = Proc.new do |db_name, sql_definition_file|
86
+ %(
87
+ STOP DATABASE #{db_name};
88
+ DELETE DATABASE #{db_name};
89
+ CREATE DATABASE #{db_name};
90
+
91
+ CONNECT TO #{db_name} AS SESSION_NAME USER _SYSTEM;
92
+ SET COMMIT FALSE;
93
+
94
+ CREATE USER RAILS;
95
+ CREATE SCHEMA RAILS AUTHORIZATION RAILS;
96
+ COMMIT;
97
+
98
+ SET SESSION AUTHORIZATION RAILS;
99
+ SCRIPT '#{sql_definition_file}';
100
+
101
+ COMMIT;
102
+
103
+ DISCONNECT ALL;
104
+ )
105
+ end
106
+ create_activerecord_unittest = build_frontbase_database['activerecord_unittest', File.join(SCHEMA_PATH, 'frontbase.sql')]
107
+ create_activerecord_unittest2 = build_frontbase_database['activerecord_unittest2', File.join(SCHEMA_PATH, 'frontbase2.sql')]
108
+ execute_frontbase_sql = Proc.new do |sql|
109
+ system(<<-SHELL)
110
+ /Library/FrontBase/bin/sql92 <<-SQL
111
+ #{sql}
112
+ SQL
113
+ SHELL
114
+ end
115
+ execute_frontbase_sql[create_activerecord_unittest]
116
+ execute_frontbase_sql[create_activerecord_unittest2]
117
+ end
118
+
119
+ # Generate the RDoc documentation
120
+
121
+ Rake::RDocTask.new { |rdoc|
122
+ rdoc.rdoc_dir = 'doc'
123
+ rdoc.title = "Active Record -- Object-relation mapping put on rails"
124
+ rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
125
+ rdoc.template = "#{ENV['template']}.rb" if ENV['template']
126
+ rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
127
+ rdoc.rdoc_files.include('lib/**/*.rb')
128
+ rdoc.rdoc_files.exclude('lib/active_record/vendor/*')
129
+ rdoc.rdoc_files.include('dev-utils/*.rb')
130
+ }
131
+
132
+ # Enhance rdoc task to copy referenced images also
133
+ task :rdoc do
134
+ FileUtils.mkdir_p "doc/files/examples/"
135
+ FileUtils.copy "examples/associations.png", "doc/files/examples/associations.png"
136
+ end
137
+
138
+
139
+ # Create compressed packages
140
+
141
+ dist_dirs = [ "lib", "test", "examples", "dev-utils" ]
142
+
143
+ spec = Gem::Specification.new do |s|
144
+ s.name = PKG_NAME
145
+ s.version = PKG_VERSION
146
+ s.summary = "Implements the ActiveRecord pattern for ORM."
147
+ s.description = %q{Implements the ActiveRecord pattern (Fowler, PoEAA) for ORM. It ties database tables and classes together for business objects, like Customer or Subscription, that can find, save, and destroy themselves without resorting to manual SQL.}
148
+
149
+ s.files = [ "Rakefile", "install.rb", "README", "RUNNING_UNIT_TESTS", "CHANGELOG" ]
150
+ dist_dirs.each do |dir|
151
+ s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
152
+ end
153
+
154
+ s.add_dependency('activesupport', '= 1.4.2' + PKG_BUILD)
155
+
156
+ s.files.delete "test/fixtures/fixture_database.sqlite"
157
+ s.files.delete "test/fixtures/fixture_database_2.sqlite"
158
+ s.files.delete "test/fixtures/fixture_database.sqlite3"
159
+ s.files.delete "test/fixtures/fixture_database_2.sqlite3"
160
+ s.require_path = 'lib'
161
+ s.autorequire = 'active_record'
162
+
163
+ s.has_rdoc = true
164
+ s.extra_rdoc_files = %w( README )
165
+ s.rdoc_options.concat ['--main', 'README']
166
+
167
+ s.author = "David Heinemeier Hansson"
168
+ s.email = "david@loudthinking.com"
169
+ s.homepage = "http://www.rubyonrails.org"
170
+ s.rubyforge_project = "activerecord"
171
+ end
172
+
173
+ Rake::GemPackageTask.new(spec) do |p|
174
+ p.gem_spec = spec
175
+ p.need_tar = true
176
+ p.need_zip = true
177
+ end
178
+
179
+ task :lines do
180
+ lines, codelines, total_lines, total_codelines = 0, 0, 0, 0
181
+
182
+ for file_name in FileList["lib/active_record/**/*.rb"]
183
+ next if file_name =~ /vendor/
184
+ f = File.open(file_name)
185
+
186
+ while line = f.gets
187
+ lines += 1
188
+ next if line =~ /^\s*$/
189
+ next if line =~ /^\s*#/
190
+ codelines += 1
191
+ end
192
+ puts "L: #{sprintf("%4d", lines)}, LOC #{sprintf("%4d", codelines)} | #{file_name}"
193
+
194
+ total_lines += lines
195
+ total_codelines += codelines
196
+
197
+ lines, codelines = 0, 0
198
+ end
199
+
200
+ puts "Total: Lines #{total_lines}, LOC #{total_codelines}"
201
+ end
202
+
203
+
204
+ # Publishing ------------------------------------------------------
205
+
206
+ desc "Publish the beta gem"
207
+ task :pgem => [:package] do
208
+ Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
209
+ `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'`
210
+ end
211
+
212
+ desc "Publish the API documentation"
213
+ task :pdoc => [:rdoc] do
214
+ Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/ar", "doc").upload
215
+ end
216
+
217
+ desc "Publish the release files to RubyForge."
218
+ task :release => [ :package ] do
219
+ require 'rubyforge'
220
+
221
+ packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
222
+
223
+ rubyforge = RubyForge.new
224
+ rubyforge.login
225
+ rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
226
+ end