activerecord 1.6.0 → 1.7.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 +78 -0
- data/README +20 -29
- data/RUNNING_UNIT_TESTS +1 -2
- data/examples/validation.rb +0 -3
- data/install.rb +3 -16
- data/lib/active_record.rb +11 -4
- data/lib/active_record/aggregations.rb +2 -2
- data/lib/active_record/associations.rb +8 -8
- data/lib/active_record/associations/association_collection.rb +1 -1
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +1 -1
- data/lib/active_record/base.rb +117 -43
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/connection_adapters/abstract_adapter.rb +7 -14
- data/lib/active_record/connection_adapters/db2_adapter.rb +33 -22
- data/lib/active_record/connection_adapters/mysql_adapter.rb +74 -33
- data/lib/active_record/connection_adapters/oci_adapter.rb +265 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +23 -3
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +13 -4
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +158 -67
- data/lib/active_record/deprecated_associations.rb +4 -4
- data/lib/active_record/fixtures.rb +12 -5
- data/lib/active_record/locking.rb +22 -22
- data/lib/active_record/observer.rb +6 -3
- data/lib/active_record/timestamp.rb +15 -5
- data/lib/active_record/transactions.rb +4 -4
- data/lib/active_record/validations.rb +272 -189
- data/lib/active_record/wrappings.rb +2 -2
- data/rakefile +17 -2
- data/test/aaa_create_tables_test.rb +58 -0
- data/test/abstract_unit.rb +3 -2
- data/test/aggregations_test.rb +0 -1
- data/test/associations_test.rb +27 -28
- data/test/base_test.rb +74 -2
- data/test/binary_test.rb +6 -2
- data/test/class_inheritable_attributes_test.rb +1 -1
- data/test/column_alias_test.rb +9 -2
- data/test/connections/native_oci/connection.rb +25 -0
- data/test/connections/native_sqlite/connection.rb +4 -1
- data/test/connections/native_sqlite3/connection.rb +4 -2
- data/test/deprecated_associations_test.rb +4 -5
- data/test/finder_test.rb +20 -4
- data/test/fixtures/db_definitions/create_oracle_db.bat +5 -0
- data/test/fixtures/db_definitions/create_oracle_db.sh +5 -0
- data/test/fixtures/db_definitions/db2.drop.sql +18 -0
- data/test/fixtures/db_definitions/db2.sql +1 -0
- data/test/fixtures/db_definitions/db22.drop.sql +2 -0
- data/test/fixtures/db_definitions/db22.sql +1 -0
- data/test/fixtures/db_definitions/drop_oracle_tables.sql +35 -0
- data/test/fixtures/db_definitions/drop_oracle_tables2.sql +3 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +18 -0
- data/test/fixtures/db_definitions/mysql.sql +2 -1
- data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/mysql2.sql +1 -0
- data/test/fixtures/db_definitions/oci.drop.sql +18 -0
- data/test/fixtures/db_definitions/oci.sql +167 -0
- data/test/fixtures/db_definitions/oci2.drop.sql +2 -0
- data/test/fixtures/db_definitions/oci2.sql +6 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +18 -0
- data/test/fixtures/db_definitions/postgresql.sql +2 -1
- data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/postgresql2.sql +2 -1
- data/test/fixtures/db_definitions/sqlite.drop.sql +18 -0
- data/test/fixtures/db_definitions/sqlite.sql +2 -1
- data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlite2.sql +1 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +18 -0
- data/test/fixtures/db_definitions/sqlserver.sql +1 -0
- data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlserver2.sql +1 -0
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
- data/test/fixtures/topics.yml +3 -3
- data/test/lifecycle_test.rb +0 -1
- data/test/modules_test.rb +0 -1
- data/test/reflection_test.rb +0 -1
- data/test/validations_test.rb +229 -41
- metadata +36 -28
- data/dev-utils/eval_debugger.rb +0 -14
- data/lib/active_record/support/binding_of_caller.rb +0 -83
- data/lib/active_record/support/breakpoint.rb +0 -518
- data/lib/active_record/support/class_attribute_accessors.rb +0 -57
- data/lib/active_record/support/class_inheritable_attributes.rb +0 -117
- data/lib/active_record/support/clean_logger.rb +0 -10
- data/lib/active_record/support/core_ext.rb +0 -1
- data/lib/active_record/support/core_ext/hash.rb +0 -5
- data/lib/active_record/support/core_ext/hash/keys.rb +0 -35
- data/lib/active_record/support/core_ext/numeric.rb +0 -7
- data/lib/active_record/support/core_ext/numeric/bytes.rb +0 -33
- data/lib/active_record/support/core_ext/numeric/time.rb +0 -59
- data/lib/active_record/support/core_ext/object_and_class.rb +0 -24
- data/lib/active_record/support/core_ext/string.rb +0 -5
- data/lib/active_record/support/core_ext/string/inflections.rb +0 -45
- data/lib/active_record/support/dependencies.rb +0 -63
- data/lib/active_record/support/inflector.rb +0 -84
- data/lib/active_record/support/misc.rb +0 -8
- data/lib/active_record/support/module_attribute_accessors.rb +0 -57
data/CHANGELOG
CHANGED
@@ -1,3 +1,81 @@
|
|
1
|
+
*1.7.0* (24th February, 2005)
|
2
|
+
|
3
|
+
* Changed the auto-timestamping feature to use ActiveRecord::Base.default_timezone instead of entertaining the parallel ActiveRecord::Base.timestamps_gmt method. The latter is now deprecated and will throw a warning on use (but still work) #710 [Jamis Buck]
|
4
|
+
|
5
|
+
* Added a OCI8-based Oracle adapter that has been verified to work with Oracle 8 and 9 #629 [Graham Jenkins]. Usage notes:
|
6
|
+
|
7
|
+
1. Key generation uses a sequence "rails_sequence" for all tables. (I couldn't find a simple
|
8
|
+
and safe way of passing table-specific sequence information to the adapter.)
|
9
|
+
2. Oracle uses DATE or TIMESTAMP datatypes for both dates and times. Consequently I have had to
|
10
|
+
resort to some hacks to get data converted to Date or Time in Ruby.
|
11
|
+
If the column_name ends in _at (like created_at, updated_at) it's created as a Ruby Time. Else if the
|
12
|
+
hours/minutes/seconds are 0, I make it a Ruby Date. Else it's a Ruby Time.
|
13
|
+
This is nasty - but if you use Duck Typing you'll probably not care very much.
|
14
|
+
In 9i it's tempting to map DATE to Date and TIMESTAMP to Time but I don't think that is
|
15
|
+
valid - too many databases use DATE for both.
|
16
|
+
Timezones and sub-second precision on timestamps are not supported.
|
17
|
+
3. Default values that are functions (such as "SYSDATE") are not supported. This is a
|
18
|
+
restriction of the way active record supports default values.
|
19
|
+
4. Referential integrity constraints are not fully supported. Under at least
|
20
|
+
some circumstances, active record appears to delete parent and child records out of
|
21
|
+
sequence and out of transaction scope. (Or this may just be a problem of test setup.)
|
22
|
+
|
23
|
+
The OCI8 driver can be retrieved from http://rubyforge.org/projects/ruby-oci8/
|
24
|
+
|
25
|
+
* Added option :schema_order to the PostgreSQL adapter to support the use of multiple schemas per database #697 [YuriSchimke]
|
26
|
+
|
27
|
+
* Optimized the SQL used to generate has_and_belongs_to_many queries by listing the join table first #693 [yerejm]
|
28
|
+
|
29
|
+
* Fixed that when using validation macros with a custom message, if you happened to use single quotes in the message string you would get a parsing error #657 [tonka]
|
30
|
+
|
31
|
+
* Fixed that Active Record would throw Broken Pipe errors with FCGI when the MySQL connection timed out instead of reconnecting #428 [Nicholas Seckar]
|
32
|
+
|
33
|
+
* Added options to specify an SSL connection for MySQL. Define the following attributes in the connection config (config/database.yml in Rails) to use it: sslkey, sslcert, sslca, sslcapath, sslcipher. To use SSL with no client certs, just set :sslca = '/dev/null'. http://dev.mysql.com/doc/mysql/en/secure-connections.html #604 [daniel@nightrunner.com]
|
34
|
+
|
35
|
+
* Added automatic dropping/creating of test tables for running the unit tests on all databases #587 [adelle@bullet.net.au]
|
36
|
+
|
37
|
+
* Fixed that find_by_* would fail when column names had numbers #670 [demetrius]
|
38
|
+
|
39
|
+
* Fixed the SQL Server adapter on a bunch of issues #667 [DeLynn]
|
40
|
+
|
41
|
+
1. Created a new columns method that is much cleaner.
|
42
|
+
2. Corrected a problem with the select and select_all methods
|
43
|
+
that didn't account for the LIMIT clause being passed into raw SQL statements.
|
44
|
+
3. Implemented the string_to_time method in order to create proper instances of the time class.
|
45
|
+
4. Added logic to the simplified_type method that allows the database to specify the scale of float data.
|
46
|
+
5. Adjusted the quote_column_name to account for the fact that MS SQL is bothered by a forward slash in the data string.
|
47
|
+
|
48
|
+
* Fixed that the dynamic finder like find_all_by_something_boolean(false) didn't work #649 [lmarlow@yahoo.com]
|
49
|
+
|
50
|
+
* Added validates_each that validates each specified attribute against a block #610 [bitsweat]. Example:
|
51
|
+
|
52
|
+
class Person < ActiveRecord::Base
|
53
|
+
validates_each :first_name, :last_name do |record, attr|
|
54
|
+
record.errors.add attr, 'starts with z.' if attr[0] == ?z
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
* Added :allow_nil as an explicit option for validates_length_of, so unless that's set to true having the attribute as nil will also return an error if a range is specified as :within #610 [bitsweat]
|
59
|
+
|
60
|
+
* Added that validates_* now accept blocks to perform validations #618 [Tim Bates]. Example:
|
61
|
+
|
62
|
+
class Person < ActiveRecord::Base
|
63
|
+
validate { |person| person.errors.add("title", "will never be valid") if SHOULD_NEVER_BE_VALID }
|
64
|
+
end
|
65
|
+
|
66
|
+
* Addded validation for validate all the associated objects before declaring failure with validates_associated #618 [Tim Bates]
|
67
|
+
|
68
|
+
* Added keyword-style approach to defining the custom relational bindings #545 [Jamis Buck]. Example:
|
69
|
+
|
70
|
+
class Project < ActiveRecord::Base
|
71
|
+
primary_key "sysid"
|
72
|
+
table_name "XYZ_PROJECT"
|
73
|
+
inheritance_column { original_inheritance_column + "_id" }
|
74
|
+
end
|
75
|
+
|
76
|
+
* Fixed Base#clone for use with PostgreSQL #565 [hanson@surgery.wisc.edu]
|
77
|
+
|
78
|
+
|
1
79
|
*1.6.0* (January 25th, 2005)
|
2
80
|
|
3
81
|
* Added that has_many association build and create methods can take arrays of record data like Base#create and Base#build to build/create multiple records at once.
|
data/README
CHANGED
@@ -29,7 +29,7 @@ A short rundown of the major features:
|
|
29
29
|
|
30
30
|
...which again gives Product#name and Product#name=(new_name)
|
31
31
|
|
32
|
-
Learn more
|
32
|
+
{Learn more}[link:classes/ActiveRecord/Base.html]
|
33
33
|
|
34
34
|
|
35
35
|
* Associations between objects controlled by simple meta-programming macros.
|
@@ -40,7 +40,7 @@ A short rundown of the major features:
|
|
40
40
|
belongs_to :conglomorate
|
41
41
|
end
|
42
42
|
|
43
|
-
Learn more
|
43
|
+
{Learn more}[link:classes/ActiveRecord/Associations/ClassMethods.html]
|
44
44
|
|
45
45
|
|
46
46
|
* Aggregations of value objects controlled by simple meta-programming macros.
|
@@ -52,7 +52,7 @@ A short rundown of the major features:
|
|
52
52
|
:mapping => [%w(address_street street), %w(address_city city)]
|
53
53
|
end
|
54
54
|
|
55
|
-
Learn more
|
55
|
+
{Learn more}[link:classes/ActiveRecord/Aggregations/ClassMethods.html]
|
56
56
|
|
57
57
|
|
58
58
|
* Validation rules that can differ for new or existing objects.
|
@@ -64,7 +64,7 @@ A short rundown of the major features:
|
|
64
64
|
validates_confirmation_of :password, :email_address, :on => :create
|
65
65
|
end
|
66
66
|
|
67
|
-
Learn more
|
67
|
+
{Learn more}[link:classes/ActiveRecord/Validations.html]
|
68
68
|
|
69
69
|
|
70
70
|
* Acts that can make records work as lists or trees:
|
@@ -77,6 +77,8 @@ A short rundown of the major features:
|
|
77
77
|
item.move_higher
|
78
78
|
item.move_to_bottom
|
79
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]
|
80
82
|
|
81
83
|
* Callbacks as methods or queues on the entire lifecycle (instantiation, saving, destroying, validating, etc).
|
82
84
|
|
@@ -90,18 +92,18 @@ A short rundown of the major features:
|
|
90
92
|
after_find :eager_load, 'self.class.announce(#{id})'
|
91
93
|
end
|
92
94
|
|
93
|
-
Learn more
|
95
|
+
{Learn more}[link:classes/ActiveRecord/Callbacks.html]
|
94
96
|
|
95
97
|
|
96
98
|
* Observers for the entire lifecycle
|
97
99
|
|
98
100
|
class CommentObserver < ActiveRecord::Observer
|
99
101
|
def after_create(comment) # is called just after Comment#save
|
100
|
-
|
102
|
+
Notifications.deliver_new_comment("david@loudthinking.com", comment)
|
101
103
|
end
|
102
104
|
end
|
103
105
|
|
104
|
-
Learn more
|
106
|
+
{Learn more}[link:classes/ActiveRecord/Observer.html]
|
105
107
|
|
106
108
|
|
107
109
|
* Inheritance hierarchies
|
@@ -111,7 +113,7 @@ A short rundown of the major features:
|
|
111
113
|
class Client < Company; end
|
112
114
|
class PriorityClient < Client; end
|
113
115
|
|
114
|
-
Learn more
|
116
|
+
{Learn more}[link:classes/ActiveRecord/Base.html]
|
115
117
|
|
116
118
|
|
117
119
|
* Transaction support on both a database and object level. The latter is implemented
|
@@ -129,7 +131,7 @@ A short rundown of the major features:
|
|
129
131
|
mary.deposit(100)
|
130
132
|
end
|
131
133
|
|
132
|
-
Learn more
|
134
|
+
{Learn more}[link:classes/ActiveRecord/Transactions/ClassMethods.html]
|
133
135
|
|
134
136
|
|
135
137
|
* Reflections on columns, associations, and aggregations
|
@@ -138,7 +140,7 @@ A short rundown of the major features:
|
|
138
140
|
reflection.klass # => Client (class)
|
139
141
|
Firm.columns # Returns an array of column descriptors for the firms table
|
140
142
|
|
141
|
-
Learn more
|
143
|
+
{Learn more}[link:classes/ActiveRecord/Reflection/ClassMethods.html]
|
142
144
|
|
143
145
|
|
144
146
|
* Direct manipulation (instead of service invocation)
|
@@ -158,7 +160,7 @@ A short rundown of the major features:
|
|
158
160
|
# something even more interesting involving a the same cat...
|
159
161
|
cat.save
|
160
162
|
|
161
|
-
Learn more
|
163
|
+
{Learn more}[link:classes/ActiveRecord/Base.html]
|
162
164
|
|
163
165
|
|
164
166
|
* Database abstraction through simple adapters (~100 lines) with a shared connector
|
@@ -173,7 +175,8 @@ A short rundown of the major features:
|
|
173
175
|
:database => "activerecord"
|
174
176
|
)
|
175
177
|
|
176
|
-
Learn more
|
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].
|
177
180
|
|
178
181
|
|
179
182
|
* Logging support for Log4r[http://log4r.sourceforge.net] and Logger[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc]
|
@@ -295,17 +298,6 @@ the examples themselves.
|
|
295
298
|
It's also highly recommended to have a look at the unit tests. Read more in link:files/RUNNING_UNIT_TESTS.html
|
296
299
|
|
297
300
|
|
298
|
-
== Database support
|
299
|
-
|
300
|
-
Active Record ships with adapters for MySQL/Ruby[http://www.tmtm.org/en/mysql/ruby/]
|
301
|
-
(compatible with Ruby/MySQL[http://www.tmtm.org/ruby/mysql/README_en.html]),
|
302
|
-
PostgreSQL[http://www.postgresql.jp/interfaces/ruby/], and
|
303
|
-
SQLite[http://rubyforge.org/projects/sqlite-ruby/] (needs SQLite 2.8.13+ and SQLite-Ruby 1.1.2+).
|
304
|
-
The adapters are around 100 lines of code fulfilling the interface specified by
|
305
|
-
ActiveRecord::ConnectionAdapters::AbstractAdapter. Writing a new adapter should be a small task --
|
306
|
-
especially considering the extensive test suite that'll make sure you're fulfilling the contract.
|
307
|
-
|
308
|
-
|
309
301
|
== Philosophy
|
310
302
|
|
311
303
|
Active Record attempts to provide a coherent wrapping for the inconvenience that is
|
@@ -332,7 +324,7 @@ The latest version of Active Record can be found at
|
|
332
324
|
|
333
325
|
Documentation can be found at
|
334
326
|
|
335
|
-
* http://ar.rubyonrails.
|
327
|
+
* http://ar.rubyonrails.com
|
336
328
|
|
337
329
|
|
338
330
|
== Installation
|
@@ -341,7 +333,7 @@ The prefered method of installing Active Record is through its GEM file. You'll
|
|
341
333
|
RubyGems[http://rubygems.rubyforge.org/wiki/wiki.pl] installed for that, though. If you have,
|
342
334
|
then use:
|
343
335
|
|
344
|
-
% [sudo] gem install activerecord-
|
336
|
+
% [sudo] gem install activerecord-1.7.0.gem
|
345
337
|
|
346
338
|
You can also install Active Record the old-fashion way with the following command:
|
347
339
|
|
@@ -352,12 +344,12 @@ from its distribution directory.
|
|
352
344
|
|
353
345
|
== License
|
354
346
|
|
355
|
-
Active Record is released under the
|
347
|
+
Active Record is released under the MIT license.
|
356
348
|
|
357
349
|
|
358
350
|
== Support
|
359
351
|
|
360
|
-
The Active Record homepage is http://
|
352
|
+
The Active Record homepage is http://www.rubyonrails.com. You can find the Active Record
|
361
353
|
RubyForge page at http://rubyforge.org/projects/activerecord. And as Jim from Rake says:
|
362
354
|
|
363
355
|
Feel free to submit commits or feature requests. If you send a patch,
|
@@ -365,5 +357,4 @@ RubyForge page at http://rubyforge.org/projects/activerecord. And as Jim from Ra
|
|
365
357
|
new feature to be submitted in the form of new unit tests.
|
366
358
|
|
367
359
|
For other information, feel free to ask on the ruby-talk mailing list
|
368
|
-
(which is mirrored to comp.lang.ruby) or contact mailto:david@loudthinking.com.
|
369
|
-
|
360
|
+
(which is mirrored to comp.lang.ruby) or contact mailto:david@loudthinking.com.
|
data/RUNNING_UNIT_TESTS
CHANGED
@@ -8,8 +8,7 @@ When you have the database online, you can import the fixture tables with
|
|
8
8
|
the test/fixtures/db_definitions/*.sql files.
|
9
9
|
|
10
10
|
Make sure that you create database objects with the same user that you specified in i
|
11
|
-
connection.rb otherwise (on Postgres, at least) tests for default values will fail
|
12
|
-
(see http://dev.rubyonrails.org/trac.cgi/ticket/118)
|
11
|
+
connection.rb otherwise (on Postgres, at least) tests for default values will fail.
|
13
12
|
|
14
13
|
== Running with Rake
|
15
14
|
|
data/examples/validation.rb
CHANGED
@@ -16,9 +16,6 @@ logger.info "\nCreate tables"
|
|
16
16
|
# Class setup ---------------
|
17
17
|
|
18
18
|
class Person < ActiveRecord::Base
|
19
|
-
# Active Record can only guess simple table names like Card/cards, Company/companies
|
20
|
-
def self.table_name() "people" end
|
21
|
-
|
22
19
|
# Using
|
23
20
|
def self.authenticate(name, pass)
|
24
21
|
# find_first "name = '#{name}' AND pass = '#{pass}'" would be open to sql-injection (in a web-app scenario)
|
data/install.rb
CHANGED
@@ -18,7 +18,7 @@ unless $sitedir
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
makedirs = %w{ active_record/associations active_record/connection_adapters active_record/support active_record/vendor active_record/acts
|
21
|
+
makedirs = %w{ active_record/associations active_record/connection_adapters active_record/support active_record/vendor active_record/acts }
|
22
22
|
makedirs.each {|f| File::makedirs(File.join($sitedir, *f.split(/\//)))}
|
23
23
|
|
24
24
|
# deprecated files that should be removed
|
@@ -37,6 +37,7 @@ files = %w-
|
|
37
37
|
active_record/connection_adapters/abstract_adapter.rb
|
38
38
|
active_record/connection_adapters/db2_adapter.rb
|
39
39
|
active_record/connection_adapters/mysql_adapter.rb
|
40
|
+
active_record/connection_adapters/oracle_adapter.rb
|
40
41
|
active_record/connection_adapters/postgresql_adapter.rb
|
41
42
|
active_record/connection_adapters/sqlite_adapter.rb
|
42
43
|
active_record/connection_adapters/sqlserver_adapter.rb
|
@@ -47,24 +48,10 @@ files = %w-
|
|
47
48
|
active_record/reflection.rb
|
48
49
|
active_record/acts/list.rb
|
49
50
|
active_record/acts/tree.rb
|
50
|
-
active_record/support/class_attribute_accessors.rb
|
51
|
-
active_record/support/class_inheritable_attributes.rb
|
52
|
-
active_record/support/clean_logger.rb
|
53
|
-
active_record/support/core_ext/hash/keys.rb
|
54
|
-
active_record/support/core_ext/hash.rb
|
55
|
-
active_record/support/core_ext/object_and_class.rb
|
56
|
-
active_record/support/core_ext/numeric/bytes.rb
|
57
|
-
active_record/support/core_ext/numeric/time.rb
|
58
|
-
active_record/support/core_ext/numeric.rb
|
59
|
-
active_record/support/core_ext/string/inflections.rb
|
60
|
-
active_record/support/core_ext/string.rb
|
61
|
-
active_record/support/core_ext.rb
|
62
|
-
active_record/support/inflector.rb
|
63
|
-
active_record/support/misc.rb
|
64
|
-
active_record/support/module_attribute_accessors.rb
|
65
51
|
active_record/timestamp.rb
|
66
52
|
active_record/transactions.rb
|
67
53
|
active_record/validations.rb
|
54
|
+
active_record/vendor/db2.rb
|
68
55
|
active_record/vendor/mysql.rb
|
69
56
|
active_record/vendor/mysql411.rb
|
70
57
|
active_record/vendor/simple.rb
|
data/lib/active_record.rb
CHANGED
@@ -24,10 +24,16 @@
|
|
24
24
|
|
25
25
|
$:.unshift(File.dirname(__FILE__))
|
26
26
|
|
27
|
-
|
28
|
-
require '
|
29
|
-
|
30
|
-
|
27
|
+
begin
|
28
|
+
require 'active_support'
|
29
|
+
rescue LoadError
|
30
|
+
begin
|
31
|
+
require File.dirname(__FILE__) + '/../../activesupport/lib/active_support'
|
32
|
+
rescue LoadError
|
33
|
+
require 'rubygems'
|
34
|
+
require_gem 'activesupport'
|
35
|
+
end
|
36
|
+
end
|
31
37
|
|
32
38
|
require 'active_record/base'
|
33
39
|
require 'active_record/observer'
|
@@ -60,3 +66,4 @@ require 'active_record/connection_adapters/postgresql_adapter'
|
|
60
66
|
require 'active_record/connection_adapters/sqlite_adapter'
|
61
67
|
require 'active_record/connection_adapters/sqlserver_adapter'
|
62
68
|
require 'active_record/connection_adapters/db2_adapter'
|
69
|
+
require 'active_record/connection_adapters/oci_adapter'
|
@@ -94,7 +94,7 @@ module ActiveRecord
|
|
94
94
|
# relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects.
|
95
95
|
#
|
96
96
|
# It's also important to treat the value objects as immutable. Don't allow the Money object to have its amount changed after
|
97
|
-
# creation. Create a new money object with the new value instead. This is
|
97
|
+
# creation. Create a new money object with the new value instead. This is exemplified by the Money#exchanged_to method that
|
98
98
|
# returns a new value object instead of changing its own values. Active Record won't persist value objects that have been
|
99
99
|
# changed through other means than the writer method.
|
100
100
|
#
|
@@ -108,7 +108,7 @@ module ActiveRecord
|
|
108
108
|
# <tt>composed_of :address</tt> would add <tt>address</tt> and <tt>address=(new_address)</tt>.
|
109
109
|
#
|
110
110
|
# Options are:
|
111
|
-
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be
|
111
|
+
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
|
112
112
|
# from the part id. So <tt>composed_of :address</tt> will by default be linked to the +Address+ class, but
|
113
113
|
# if the real class name is +CompanyAddress+, you'll have to specify it with this option.
|
114
114
|
# * <tt>:mapping</tt> - specifies a number of mapping arrays (attribute, parameter) that bind an attribute name
|
@@ -43,7 +43,7 @@ module ActiveRecord
|
|
43
43
|
#
|
44
44
|
# == Example
|
45
45
|
#
|
46
|
-
# link
|
46
|
+
# link:../../examples/associations.png
|
47
47
|
#
|
48
48
|
# == Is it belongs_to or has_one?
|
49
49
|
#
|
@@ -160,7 +160,7 @@ module ActiveRecord
|
|
160
160
|
# * <tt>collection.find(id)</tt> - finds an associated object responding to the +id+ and that
|
161
161
|
# meets the condition that it has to be associated with this object.
|
162
162
|
# * <tt>collection.find_all(conditions = nil, orderings = nil, limit = nil, joins = nil)</tt> - finds all associated objects responding
|
163
|
-
#
|
163
|
+
# criteria mentioned (like in the standard find_all) and that meets the condition that it has to be associated with this object.
|
164
164
|
# * <tt>collection.build(attributes = {})</tt> - returns a new object of the collection type that has been instantiated
|
165
165
|
# with +attributes+ and linked to this object through a foreign key but has not yet been saved.
|
166
166
|
# * <tt>collection.create(attributes = {})</tt> - returns a new object of the collection type that has been instantiated
|
@@ -180,7 +180,7 @@ module ActiveRecord
|
|
180
180
|
# The declaration can also include an options hash to specialize the behavior of the association.
|
181
181
|
#
|
182
182
|
# Options are:
|
183
|
-
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be
|
183
|
+
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
|
184
184
|
# from the association name. So <tt>has_many :products</tt> will by default be linked to the +Product+ class, but
|
185
185
|
# if the real class name is +SpecialProduct+, you'll have to specify it with this option.
|
186
186
|
# * <tt>:conditions</tt> - specify the conditions that the associated objects must meet in order to be included as a "WHERE"
|
@@ -263,7 +263,7 @@ module ActiveRecord
|
|
263
263
|
# The declaration can also include an options hash to specialize the behavior of the association.
|
264
264
|
#
|
265
265
|
# Options are:
|
266
|
-
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be
|
266
|
+
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
|
267
267
|
# from the association name. So <tt>has_one :manager</tt> will by default be linked to the +Manager+ class, but
|
268
268
|
# if the real class name is +Person+, you'll have to specify it with this option.
|
269
269
|
# * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a "WHERE"
|
@@ -320,7 +320,7 @@ module ActiveRecord
|
|
320
320
|
# * <tt>association.create(attributes = {})</tt> - returns a new object of the associated type that has been instantiated
|
321
321
|
# with +attributes+ and linked to this object through a foreign key and that has already been saved (if it passed the validation).
|
322
322
|
#
|
323
|
-
# Example: A Post class declares <tt>
|
323
|
+
# Example: A Post class declares <tt>belongs_to :author</tt>, which will add:
|
324
324
|
# * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>)
|
325
325
|
# * <tt>Post#author=(author)</tt> (similar to <tt>post.author_id = author.id</tt>)
|
326
326
|
# * <tt>Post#author?</tt> (similar to <tt>post.author == some_author</tt>)
|
@@ -330,7 +330,7 @@ module ActiveRecord
|
|
330
330
|
# The declaration can also include an options hash to specialize the behavior of the association.
|
331
331
|
#
|
332
332
|
# Options are:
|
333
|
-
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be
|
333
|
+
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
|
334
334
|
# from the association name. So <tt>has_one :author</tt> will by default be linked to the +Author+ class, but
|
335
335
|
# if the real class name is +Person+, you'll have to specify it with this option.
|
336
336
|
# * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a "WHERE"
|
@@ -403,7 +403,7 @@ module ActiveRecord
|
|
403
403
|
#
|
404
404
|
# Adds the following methods for retrieval and query.
|
405
405
|
# +collection+ is replaced with the symbol passed as the first argument, so
|
406
|
-
# <tt>has_and_belongs_to_many :categories</tt> would add among others
|
406
|
+
# <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
|
407
407
|
# * <tt>collection(force_reload = false)</tt> - returns an array of all the associated objects.
|
408
408
|
# An empty array is returned if none is found.
|
409
409
|
# * <tt>collection<<(object, ...)</tt> - adds one or more objects to the collection by creating associations in the join table
|
@@ -432,7 +432,7 @@ module ActiveRecord
|
|
432
432
|
# The declaration may include an options hash to specialize the behavior of the association.
|
433
433
|
#
|
434
434
|
# Options are:
|
435
|
-
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be
|
435
|
+
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
|
436
436
|
# from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the
|
437
437
|
# +Project+ class, but if the real class name is +SuperProject+, you'll have to specify it with this option.
|
438
438
|
# * <tt>:join_table</tt> - specify the name of the join table if the default based on lexical order isn't what you want.
|
@@ -99,7 +99,7 @@ module ActiveRecord
|
|
99
99
|
false
|
100
100
|
end
|
101
101
|
|
102
|
-
# Array#flatten has problems with
|
102
|
+
# Array#flatten has problems with recursive arrays. Going one level deeper solves the majority of the problems.
|
103
103
|
def flatten_deeper(array)
|
104
104
|
array.collect { |element| element.respond_to?(:flatten) ? element.flatten : element }.flatten
|
105
105
|
end
|
@@ -147,7 +147,7 @@ module ActiveRecord
|
|
147
147
|
def construct_sql
|
148
148
|
interpolate_sql_options!(@options, :finder_sql, :delete_sql)
|
149
149
|
@finder_sql = @options[:finder_sql] ||
|
150
|
-
"SELECT t.*, j.* FROM #{@
|
150
|
+
"SELECT t.*, j.* FROM #{@join_table} j, #{@association_table_name} t " +
|
151
151
|
"WHERE t.#{@association_class.primary_key} = j.#{@association_foreign_key} AND " +
|
152
152
|
"j.#{@association_class_primary_key_name} = #{@owner.quoted_id} " +
|
153
153
|
(@options[:conditions] ? " AND " + interpolate_sql(@options[:conditions]) : "") + " " +
|
data/lib/active_record/base.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require '
|
1
|
+
require 'active_support/class_attribute_accessors'
|
2
|
+
require 'active_support/class_inheritable_attributes'
|
3
|
+
require 'active_support/inflector'
|
4
4
|
require 'yaml'
|
5
5
|
|
6
6
|
module ActiveRecord #:nodoc:
|
@@ -97,6 +97,16 @@ module ActiveRecord #:nodoc:
|
|
97
97
|
# end
|
98
98
|
# end
|
99
99
|
#
|
100
|
+
# == Accessing attributes before they have been type casted
|
101
|
+
#
|
102
|
+
# Some times you want to be able to read the raw attribute data without having the column-determined type cast run its course first.
|
103
|
+
# That can be done by using the <attribute>_before_type_cast accessors that all attributes have. For example, if your Account model
|
104
|
+
# has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast.
|
105
|
+
#
|
106
|
+
# This is especially useful in validation situations where the user might supply a string for an integer field and you want to display
|
107
|
+
# the original string back in an error message. Accessing the attribute normally would type cast the string to 0, which isn't what you
|
108
|
+
# want.
|
109
|
+
#
|
100
110
|
# == Dynamic attribute-based finders
|
101
111
|
#
|
102
112
|
# Dynamic attribute-based finders are a cleaner way of getting objects by simple queries without turning to SQL. They work by
|
@@ -112,7 +122,7 @@ module ActiveRecord #:nodoc:
|
|
112
122
|
# is actually Payment.find_all_by_amount(amount, orderings = nil, limit = nil, joins = nil). And the full interface to Person.find_by_user_name is
|
113
123
|
# actually Person.find_by_user_name(user_name, orderings = nil)
|
114
124
|
#
|
115
|
-
# == Saving arrays, hashes, and other non-
|
125
|
+
# == Saving arrays, hashes, and other non-mappable objects in text columns
|
116
126
|
#
|
117
127
|
# Active Record can serialize any object in text columns using YAML. To do so, you must specify this with a call to the class method +serialize+.
|
118
128
|
# This makes it possible to store arrays, hashes, and other non-mappeable objects without doing any additional work. Example:
|
@@ -144,7 +154,7 @@ module ActiveRecord #:nodoc:
|
|
144
154
|
# class Client < Company; end
|
145
155
|
# class PriorityClient < Client; end
|
146
156
|
#
|
147
|
-
# When you do Firm.create("name" => "37signals"), this record
|
157
|
+
# When you do Firm.create("name" => "37signals"), this record will be saved in the companies table with type = "Firm". You can then
|
148
158
|
# fetch this row again using Company.find_first "name = '37signals'" and it will return a Firm object.
|
149
159
|
#
|
150
160
|
# If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just
|
@@ -168,7 +178,7 @@ module ActiveRecord #:nodoc:
|
|
168
178
|
# * +ActiveRecordError+ -- generic error class and superclass of all other errors raised by Active Record
|
169
179
|
# * +AdapterNotSpecified+ -- the configuration hash used in <tt>establish_connection</tt> didn't include a
|
170
180
|
# <tt>:adapter</tt> key.
|
171
|
-
# * +AdapterNotSpecified+ -- the <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified an
|
181
|
+
# * +AdapterNotSpecified+ -- the <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified an non-existent adapter
|
172
182
|
# (or a bad spelling of an existing one).
|
173
183
|
# * +AssociationTypeMismatch+ -- the object assigned to the association wasn't of the type specified in the association definition.
|
174
184
|
# * +SerializationTypeMismatch+ -- the object serialized wasn't of the class specified as the second parameter.
|
@@ -221,7 +231,7 @@ module ActiveRecord #:nodoc:
|
|
221
231
|
@@primary_key_prefix_type = nil
|
222
232
|
|
223
233
|
# Accessor for the name of the prefix string to prepend to every table name. So if set to "basecamp_", all
|
224
|
-
# table names will be named like "basecamp_projects", "basecamp_people", etc. This is a
|
234
|
+
# table names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient way of creating a namespace
|
225
235
|
# for tables in a shared database. By default, the prefix is the empty string.
|
226
236
|
cattr_accessor :table_name_prefix
|
227
237
|
@@table_name_prefix = ""
|
@@ -447,7 +457,7 @@ module ActiveRecord #:nodoc:
|
|
447
457
|
write_inheritable_array("attr_protected", attributes)
|
448
458
|
end
|
449
459
|
|
450
|
-
# Returns an array of all the attributes that have been protected from mass-
|
460
|
+
# Returns an array of all the attributes that have been protected from mass-assignment.
|
451
461
|
def protected_attributes # :nodoc:
|
452
462
|
read_inheritable_attribute("attr_protected")
|
453
463
|
end
|
@@ -460,14 +470,14 @@ module ActiveRecord #:nodoc:
|
|
460
470
|
write_inheritable_array("attr_accessible", attributes)
|
461
471
|
end
|
462
472
|
|
463
|
-
# Returns an array of all the attributes that have been made accessible to mass-
|
473
|
+
# Returns an array of all the attributes that have been made accessible to mass-assignment.
|
464
474
|
def accessible_attributes # :nodoc:
|
465
475
|
read_inheritable_attribute("attr_accessible")
|
466
476
|
end
|
467
477
|
|
468
478
|
# Specifies that the attribute by the name of +attr_name+ should be serialized before saving to the database and unserialized
|
469
479
|
# after loading from the database. The serialization is done through YAML. If +class_name+ is specified, the serialized
|
470
|
-
# object must be of that class on
|
480
|
+
# object must be of that class on retrieval or +SerializationTypeMismatch+ will be raised.
|
471
481
|
def serialize(attr_name, class_name = Object)
|
472
482
|
write_inheritable_attribute("attr_serialized", serialized_attributes.update(attr_name.to_s => class_name))
|
473
483
|
end
|
@@ -479,20 +489,8 @@ module ActiveRecord #:nodoc:
|
|
479
489
|
|
480
490
|
# Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending
|
481
491
|
# directly from ActiveRecord. So if the hierarchy looks like: Reply < Message < ActiveRecord, then Message is used
|
482
|
-
# to guess the table name from even when called on Reply. The
|
483
|
-
#
|
484
|
-
# * Class name ends in "x", "ch" or "ss": "es" is appended, so a Search class becomes a searches table.
|
485
|
-
# * Class name ends in "y" preceded by a consonant or "qu": The "y" is replaced with "ies", so a Category class becomes a categories table.
|
486
|
-
# * Class name ends in "fe": The "fe" is replaced with "ves", so a Wife class becomes a wives table.
|
487
|
-
# * Class name ends in "lf" or "rf": The "f" is replaced with "ves", so a Half class becomes a halves table.
|
488
|
-
# * Class name ends in "person": The "person" is replaced with "people", so a Salesperson class becomes a salespeople table.
|
489
|
-
# * Class name ends in "man": The "man" is replaced with "men", so a Spokesman class becomes a spokesmen table.
|
490
|
-
# * Class name ends in "sis": The "i" is replaced with an "e", so a Basis class becomes a bases table.
|
491
|
-
# * Class name ends in "tum" or "ium": The "um" is replaced with an "a", so a Datum class becomes a data table.
|
492
|
-
# * Class name ends in "child": The "child" is replaced with "children", so a NodeChild class becomes a node_children table.
|
493
|
-
# * Class name ends in an "s": No additional characters are added or removed.
|
494
|
-
# * Class name doesn't end in "s": An "s" is appended, so a Comment class becomes a comments table.
|
495
|
-
# * Class name with word compositions: Compositions are underscored, so CreditCard class becomes a credit_cards table.
|
492
|
+
# to guess the table name from even when called on Reply. The rules used to do the guess are handled by the Inflector class
|
493
|
+
# in Active Support, which knows almost all common English inflections (report a bug if your inflection isn't covered).
|
496
494
|
#
|
497
495
|
# Additionally, the class-level table_name_prefix is prepended to the table_name and the table_name_suffix is appended.
|
498
496
|
# So if you have "myapp_" as a prefix, the table name guess for an Account class becomes "myapp_accounts".
|
@@ -501,13 +499,13 @@ module ActiveRecord #:nodoc:
|
|
501
499
|
# "mice" table. Example:
|
502
500
|
#
|
503
501
|
# class Mouse < ActiveRecord::Base
|
504
|
-
#
|
502
|
+
# table_name "mice"
|
505
503
|
# end
|
506
504
|
def table_name
|
507
505
|
table_name_prefix + undecorated_table_name(class_name_of_active_record_descendant(self)) + table_name_suffix
|
508
506
|
end
|
509
507
|
|
510
|
-
# Defines the primary key field -- can be overridden in subclasses.
|
508
|
+
# Defines the primary key field -- can be overridden in subclasses. Overwriting will negate any effect of the
|
511
509
|
# primary_key_prefix_type setting, though.
|
512
510
|
def primary_key
|
513
511
|
case primary_key_prefix_type
|
@@ -525,6 +523,49 @@ module ActiveRecord #:nodoc:
|
|
525
523
|
"type"
|
526
524
|
end
|
527
525
|
|
526
|
+
# Sets the table name to use to the given value, or (if the value
|
527
|
+
# is nil or false) to the value returned by the given block.
|
528
|
+
#
|
529
|
+
# Example:
|
530
|
+
#
|
531
|
+
# class Project < ActiveRecord::Base
|
532
|
+
# set_table_name "project"
|
533
|
+
# end
|
534
|
+
def set_table_name( value=nil, &block )
|
535
|
+
define_attr_method :table_name, value, &block
|
536
|
+
end
|
537
|
+
alias :table_name= :set_table_name
|
538
|
+
|
539
|
+
# Sets the name of the primary key column to use to the given value,
|
540
|
+
# or (if the value is nil or false) to the value returned by the given
|
541
|
+
# block.
|
542
|
+
#
|
543
|
+
# Example:
|
544
|
+
#
|
545
|
+
# class Project < ActiveRecord::Base
|
546
|
+
# set_primary_key "sysid"
|
547
|
+
# end
|
548
|
+
def set_primary_key( value=nil, &block )
|
549
|
+
define_attr_method :primary_key, value, &block
|
550
|
+
end
|
551
|
+
alias :primary_key= :set_primary_key
|
552
|
+
|
553
|
+
# Sets the name of the inheritance column to use to the given value,
|
554
|
+
# or (if the value # is nil or false) to the value returned by the
|
555
|
+
# given block.
|
556
|
+
#
|
557
|
+
# Example:
|
558
|
+
#
|
559
|
+
# class Project < ActiveRecord::Base
|
560
|
+
# set_inheritance_column do
|
561
|
+
# original_inheritance_column + "_id"
|
562
|
+
# end
|
563
|
+
# end
|
564
|
+
def set_inheritance_column( value=nil, &block )
|
565
|
+
define_attr_method :inheritance_column, value, &block
|
566
|
+
end
|
567
|
+
alias :inheritance_column= :set_inheritance_column
|
568
|
+
|
528
569
|
# Turns the +table_name+ back into a class name following the reverse rules of +table_name+.
|
529
570
|
def class_name(table_name = table_name) # :nodoc:
|
530
571
|
# remove any prefix and/or suffix from the table name
|
@@ -567,13 +608,14 @@ module ActiveRecord #:nodoc:
|
|
567
608
|
@columns = @columns_hash = @content_columns = @dynamic_methods_hash = nil
|
568
609
|
end
|
569
610
|
|
570
|
-
def reset_column_information_and_inheritable_attributes_for_all_subclasses
|
611
|
+
def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc:
|
571
612
|
subclasses.each { |klass| klass.reset_inheritable_attributes; klass.reset_column_information }
|
572
613
|
end
|
573
614
|
|
574
615
|
# Transforms attribute key names into a more humane format, such as "First name" instead of "first_name". Example:
|
575
616
|
# Person.human_attribute_name("first_name") # => "First name"
|
576
|
-
|
617
|
+
# Deprecated in favor of just calling "first_name".humanize
|
618
|
+
def human_attribute_name(attribute_key_name) #:nodoc:
|
577
619
|
attribute_key_name.humanize
|
578
620
|
end
|
579
621
|
|
@@ -581,12 +623,12 @@ module ActiveRecord #:nodoc:
|
|
581
623
|
superclass == Base || !columns_hash.has_key?(inheritance_column)
|
582
624
|
end
|
583
625
|
|
584
|
-
def quote(object)
|
626
|
+
def quote(object) #:nodoc:
|
585
627
|
connection.quote(object)
|
586
628
|
end
|
587
629
|
|
588
630
|
# Used to sanitize objects before they're used in an SELECT SQL-statement. Delegates to <tt>connection.quote</tt>.
|
589
|
-
def sanitize(object)
|
631
|
+
def sanitize(object) #:nodoc:
|
590
632
|
connection.quote(object)
|
591
633
|
end
|
592
634
|
|
@@ -599,11 +641,18 @@ module ActiveRecord #:nodoc:
|
|
599
641
|
# project.milestones << Milestone.find_all
|
600
642
|
# end
|
601
643
|
def benchmark(title)
|
644
|
+
result = nil
|
645
|
+
bm = Benchmark.measure { result = silence { yield } }
|
646
|
+
logger.info "#{title} (#{sprintf("%f", bm.real)})"
|
647
|
+
return result
|
648
|
+
end
|
649
|
+
|
650
|
+
# Silences the logger for the duration of the block.
|
651
|
+
def silence
|
602
652
|
result = nil
|
603
653
|
logger.level = Logger::ERROR
|
604
|
-
|
654
|
+
result = yield
|
605
655
|
logger.level = Logger::DEBUG
|
606
|
-
logger.info "#{title} (#{sprintf("%f", bm.real)})"
|
607
656
|
return result
|
608
657
|
end
|
609
658
|
|
@@ -674,18 +723,43 @@ module ActiveRecord #:nodoc:
|
|
674
723
|
def method_missing(method_id, *arguments)
|
675
724
|
method_name = method_id.id2name
|
676
725
|
|
677
|
-
if method_name =~ /find_(all_by|by)_([_a-z]
|
726
|
+
if method_name =~ /find_(all_by|by)_([_a-z][_a-z\d]*)/
|
678
727
|
finder, attributes = ($1 == "all_by" ? :find_all : :find_first), $2.split("_and_")
|
679
728
|
attributes.each { |attr_name| super unless column_methods_hash[attr_name.intern] }
|
680
729
|
|
681
730
|
attr_index = -1
|
682
|
-
conditions = attributes.collect { |attr_name| attr_index += 1; "#{attr_name} #{arguments[attr_index] ? "
|
731
|
+
conditions = attributes.collect { |attr_name| attr_index += 1; "#{attr_name} #{arguments[attr_index].nil? ? "IS" : "="} ? " }.join(" AND ")
|
683
732
|
send(finder, [conditions, *arguments[0...attributes.length]], *arguments[attributes.length..-1])
|
684
733
|
else
|
685
734
|
super
|
686
735
|
end
|
687
736
|
end
|
688
737
|
|
738
|
+
# Defines an "attribute" method (like #inheritance_column or
|
739
|
+
# #table_name). A new (class) method will be created with the
|
740
|
+
# given name. If a value is specified, the new method will
|
741
|
+
# return that value (as a string). Otherwise, the given block
|
742
|
+
# will be used to compute the value of the method.
|
743
|
+
#
|
744
|
+
# The original method will be aliased, with the new name being
|
745
|
+
# prefixed with "original_". This allows the new method to
|
746
|
+
# access the original value.
|
747
|
+
#
|
748
|
+
# Example:
|
749
|
+
#
|
750
|
+
# class A < ActiveRecord::Base
|
751
|
+
# define_attr_method :primary_key, "sysid"
|
752
|
+
# define_attr_method( :inheritance_column ) do
|
753
|
+
# original_inheritance_column + "_id"
|
754
|
+
# end
|
755
|
+
# end
|
756
|
+
def define_attr_method(name, value=nil, &block)
|
757
|
+
sing = class << self; self; end
|
758
|
+
block = proc { value.to_s } if value
|
759
|
+
sing.send( :alias_method, "original_#{name}", name )
|
760
|
+
sing.send( :define_method, name, &block )
|
761
|
+
end
|
762
|
+
|
689
763
|
protected
|
690
764
|
def subclasses
|
691
765
|
@@subclasses[self] ||= []
|
@@ -792,11 +866,11 @@ module ActiveRecord #:nodoc:
|
|
792
866
|
read_attribute(self.class.primary_key)
|
793
867
|
end
|
794
868
|
|
795
|
-
def id_before_type_cast
|
869
|
+
def id_before_type_cast #:nodoc:
|
796
870
|
read_attribute_before_type_cast(self.class.primary_key)
|
797
871
|
end
|
798
872
|
|
799
|
-
def quoted_id
|
873
|
+
def quoted_id #:nodoc:
|
800
874
|
quote(id, self.class.columns_hash[self.class.primary_key])
|
801
875
|
end
|
802
876
|
|
@@ -832,9 +906,9 @@ module ActiveRecord #:nodoc:
|
|
832
906
|
|
833
907
|
# Returns a clone of the record that hasn't been assigned an id yet and is treated as a new record.
|
834
908
|
def clone
|
835
|
-
|
836
|
-
|
837
|
-
cloned_record
|
909
|
+
attrs = self.attributes
|
910
|
+
attrs.delete(self.class.primary_key)
|
911
|
+
cloned_record = self.class.new(attrs)
|
838
912
|
cloned_record
|
839
913
|
end
|
840
914
|
|
@@ -1047,7 +1121,7 @@ module ActiveRecord #:nodoc:
|
|
1047
1121
|
|
1048
1122
|
# Returns the value of attribute identified by <tt>attr_name</tt> after it has been type cast (for example,
|
1049
1123
|
# "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).
|
1050
|
-
def read_attribute(attr_name)
|
1124
|
+
def read_attribute(attr_name)
|
1051
1125
|
if @attributes.keys.include? attr_name
|
1052
1126
|
if column = column_for_attribute(attr_name)
|
1053
1127
|
unserializable_attribute?(attr_name, column) ?
|
@@ -1086,7 +1160,7 @@ module ActiveRecord #:nodoc:
|
|
1086
1160
|
|
1087
1161
|
# Updates the attribute identified by <tt>attr_name</tt> with the specified +value+. Empty strings for fixnum and float
|
1088
1162
|
# columns are turned into nil.
|
1089
|
-
def write_attribute(attr_name, value)
|
1163
|
+
def write_attribute(attr_name, value)
|
1090
1164
|
@attributes[attr_name] = empty_string_for_number_column?(attr_name, value) ? nil : value
|
1091
1165
|
end
|
1092
1166
|
|
@@ -1170,7 +1244,7 @@ module ActiveRecord #:nodoc:
|
|
1170
1244
|
# by calling new on the column type or aggregation type (through composed_of) object with these parameters.
|
1171
1245
|
# So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
|
1172
1246
|
# written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
|
1173
|
-
#
|
1247
|
+
# parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum, f for Float,
|
1174
1248
|
# s for String, and a for Array. If all the values for a given attribute is empty, the attribute will be set to nil.
|
1175
1249
|
def assign_multiparameter_attributes(pairs)
|
1176
1250
|
execute_callstack_for_multiparameter_attributes(
|
@@ -1253,4 +1327,4 @@ module ActiveRecord #:nodoc:
|
|
1253
1327
|
string[0..3] == "--- "
|
1254
1328
|
end
|
1255
1329
|
end
|
1256
|
-
end
|
1330
|
+
end
|