Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 1791 lines (1587 sloc) 80.259 kb
db045db David Heinemeier Hansson Initial
dhh authored
1 require 'yaml'
aabf909 Jeremy Kemper Correct reader method generation for primary key attribute: handle case ...
jeremy authored
2 require 'set'
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
3 require 'active_record/deprecated_finders'
db045db David Heinemeier Hansson Initial
dhh authored
4
5 module ActiveRecord #:nodoc:
6 class ActiveRecordError < StandardError #:nodoc:
7 end
605bc77 David Heinemeier Hansson Added a better exception for when a type column is used in a table witho...
dhh authored
8 class SubclassNotFound < ActiveRecordError #:nodoc:
9 end
db045db David Heinemeier Hansson Initial
dhh authored
10 class AssociationTypeMismatch < ActiveRecordError #:nodoc:
11 end
12 class SerializationTypeMismatch < ActiveRecordError #:nodoc:
13 end
14 class AdapterNotSpecified < ActiveRecordError # :nodoc:
15 end
16 class AdapterNotFound < ActiveRecordError # :nodoc:
17 end
18 class ConnectionNotEstablished < ActiveRecordError #:nodoc:
19 end
20 class ConnectionFailed < ActiveRecordError #:nodoc:
21 end
22 class RecordNotFound < ActiveRecordError #:nodoc:
23 end
24 class StatementInvalid < ActiveRecordError #:nodoc:
25 end
554597d David Heinemeier Hansson Added named bind-style variable interpolation #281 [Michael Koziarski]
dhh authored
26 class PreparedStatementInvalid < ActiveRecordError #:nodoc:
27 end
fbf9281 David Heinemeier Hansson Added automated optimistic locking if the field lock_version is present ...
dhh authored
28 class StaleObjectError < ActiveRecordError #:nodoc:
29 end
5b9b904 David Heinemeier Hansson Added support for limit and offset with eager loading of has_one and bel...
dhh authored
30 class ConfigurationError < StandardError #:nodoc:
31 end
64fcb75 Jeremy Kemper r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
32 class ReadOnlyRecord < StandardError #:nodoc:
33 end
5707027 David Heinemeier Hansson Added better exception error when unknown column types are used with mig...
dhh authored
34
d2fefbe David Heinemeier Hansson Added MultiparameterAssignmentErrors and AttributeAssignmentError except...
dhh authored
35 class AttributeAssignmentError < ActiveRecordError #:nodoc:
36 attr_reader :exception, :attribute
37 def initialize(message, exception, attribute)
38 @exception = exception
39 @attribute = attribute
40 @message = message
41 end
42 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
43
d2fefbe David Heinemeier Hansson Added MultiparameterAssignmentErrors and AttributeAssignmentError except...
dhh authored
44 class MultiparameterAssignmentErrors < ActiveRecordError #:nodoc:
45 attr_reader :errors
46 def initialize(errors)
47 @errors = errors
48 end
49 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
50
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
51 # Active Record objects don't specify their attributes directly, but rather infer them from the table definition with
db045db David Heinemeier Hansson Initial
dhh authored
52 # which they're linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change
53 # is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
54 # database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.
55 #
db045db David Heinemeier Hansson Initial
dhh authored
56 # See the mapping rules in table_name and the full example in link:files/README.html for more insight.
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
57 #
db045db David Heinemeier Hansson Initial
dhh authored
58 # == Creation
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
59 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
60 # Active Records accept constructor parameters either in a hash or as a block. The hash method is especially useful when
db045db David Heinemeier Hansson Initial
dhh authored
61 # you're receiving the data from somewhere else, like a HTTP request. It works like this:
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
62 #
0591c53 David Heinemeier Hansson Made the dynamic finders use the new find API and updated the examples h...
dhh authored
63 # user = User.new(:name => "David", :occupation => "Code Artist")
db045db David Heinemeier Hansson Initial
dhh authored
64 # user.name # => "David"
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
65 #
db045db David Heinemeier Hansson Initial
dhh authored
66 # You can also use block initialization:
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
67 #
db045db David Heinemeier Hansson Initial
dhh authored
68 # user = User.new do |u|
69 # u.name = "David"
70 # u.occupation = "Code Artist"
71 # end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
72 #
db045db David Heinemeier Hansson Initial
dhh authored
73 # And of course you can just create a bare object and specify the attributes after the fact:
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
74 #
db045db David Heinemeier Hansson Initial
dhh authored
75 # user = User.new
76 # user.name = "David"
77 # user.occupation = "Code Artist"
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
78 #
db045db David Heinemeier Hansson Initial
dhh authored
79 # == Conditions
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
80 #
db045db David Heinemeier Hansson Initial
dhh authored
81 # Conditions can either be specified as a string or an array representing the WHERE-part of an SQL statement.
82 # The array form is to be used when the condition input is tainted and requires sanitization. The string form can
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
83 # be used for statements that don't involve tainted data. Examples:
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
84 #
db045db David Heinemeier Hansson Initial
dhh authored
85 # User < ActiveRecord::Base
86 # def self.authenticate_unsafely(user_name, password)
3dfa56c David Heinemeier Hansson Updated all references to the old find_first and find_all to use the new...
dhh authored
87 # find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'")
db045db David Heinemeier Hansson Initial
dhh authored
88 # end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
89 #
db045db David Heinemeier Hansson Initial
dhh authored
90 # def self.authenticate_safely(user_name, password)
3dfa56c David Heinemeier Hansson Updated all references to the old find_first and find_all to use the new...
dhh authored
91 # find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ])
db045db David Heinemeier Hansson Initial
dhh authored
92 # end
93 # end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
94 #
2575b3b David Heinemeier Hansson Added extra words of caution for guarding against SQL-injection attacks
dhh authored
95 # The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query and is thus susceptible to SQL-injection
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
96 # attacks if the <tt>user_name</tt> and +password+ parameters come directly from a HTTP request. The <tt>authenticate_safely</tt> method,
2575b3b David Heinemeier Hansson Added extra words of caution for guarding against SQL-injection attacks
dhh authored
97 # on the other hand, will sanitize the <tt>user_name</tt> and +password+ before inserting them in the query, which will ensure that
db045db David Heinemeier Hansson Initial
dhh authored
98 # an attacker can't escape the query and fake the login (or worse).
2575b3b David Heinemeier Hansson Added extra words of caution for guarding against SQL-injection attacks
dhh authored
99 #
5cd38ca David Heinemeier Hansson Added documentation about named bind variables
dhh authored
100 # When using multiple parameters in the conditions, it can easily become hard to read exactly what the fourth or fifth
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
101 # question mark is supposed to represent. In those cases, you can resort to named bind variables instead. That's done by replacing
5cd38ca David Heinemeier Hansson Added documentation about named bind variables
dhh authored
102 # the question marks with symbols and supplying a hash with values for the matching symbol keys:
103 #
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
104 # Company.find(:first, [
105 # "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
5cd38ca David Heinemeier Hansson Added documentation about named bind variables
dhh authored
106 # { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' }
107 # ])
108 #
db045db David Heinemeier Hansson Initial
dhh authored
109 # == Overwriting default accessors
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
110 #
db045db David Heinemeier Hansson Initial
dhh authored
111 # All column values are automatically available through basic accessors on the Active Record object, but some times you
112 # want to specialize this behavior. This can be done by either by overwriting the default accessors (using the same
113 # name as the attribute) calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things.
114 # Example:
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
115 #
db045db David Heinemeier Hansson Initial
dhh authored
116 # class Song < ActiveRecord::Base
117 # # Uses an integer of seconds to hold the length of the song
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
118 #
db045db David Heinemeier Hansson Initial
dhh authored
119 # def length=(minutes)
0591c53 David Heinemeier Hansson Made the dynamic finders use the new find API and updated the examples h...
dhh authored
120 # write_attribute(:length, minutes * 60)
db045db David Heinemeier Hansson Initial
dhh authored
121 # end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
122 #
db045db David Heinemeier Hansson Initial
dhh authored
123 # def length
0591c53 David Heinemeier Hansson Made the dynamic finders use the new find API and updated the examples h...
dhh authored
124 # read_attribute(:length) / 60
db045db David Heinemeier Hansson Initial
dhh authored
125 # end
126 # end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
127 #
0591c53 David Heinemeier Hansson Made the dynamic finders use the new find API and updated the examples h...
dhh authored
128 # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, vaule) and
129 # read_attribute(:attribute) as a shorter form.
130 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
131 # == Accessing attributes before they have been typecasted
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
132 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
133 # Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first.
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
134 # That can be done by using the <attribute>_before_type_cast accessors that all attributes have. For example, if your Account model
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
135 # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast.
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
136 #
137 # This is especially useful in validation situations where the user might supply a string for an integer field and you want to display
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
138 # the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
139 # want.
140 #
ac8fd7d David Heinemeier Hansson Added dynamic attribute-based finders as a cleaner way of getting object...
dhh authored
141 # == Dynamic attribute-based finders
142 #
a5a82d9 David Heinemeier Hansson Added extension capabilities to has_many and has_and_belongs_to_many pro...
dhh authored
143 # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by
302c23d David Heinemeier Hansson Fixed Base#find to honor the documentation on how :joins work and make t...
dhh authored
144 # appending the name of an attribute to <tt>find_by_</tt> or <tt>find_all_by_</tt>, so you get finders like Person.find_by_user_name,
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
145 # Person.find_all_by_last_name, Payment.find_by_transaction_id. So instead of writing
146 # <tt>Person.find(:first, ["user_name = ?", user_name])</tt>, you just do <tt>Person.find_by_user_name(user_name)</tt>.
302c23d David Heinemeier Hansson Fixed Base#find to honor the documentation on how :joins work and make t...
dhh authored
147 # And instead of writing <tt>Person.find(:all, ["last_name = ?", last_name])</tt>, you just do <tt>Person.find_all_by_last_name(last_name)</tt>.
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
148 #
ac8fd7d David Heinemeier Hansson Added dynamic attribute-based finders as a cleaner way of getting object...
dhh authored
149 # It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders like
150 # <tt>Person.find_by_user_name_and_password</tt> or even <tt>Payment.find_by_purchaser_and_state_and_country</tt>. So instead of writing
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
151 # <tt>Person.find(:first, ["user_name = ? AND password = ?", user_name, password])</tt>, you just do
ac8fd7d David Heinemeier Hansson Added dynamic attribute-based finders as a cleaner way of getting object...
dhh authored
152 # <tt>Person.find_by_user_name_and_password(user_name, password)</tt>.
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
153 #
0591c53 David Heinemeier Hansson Made the dynamic finders use the new find API and updated the examples h...
dhh authored
154 # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount
155 # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is
156 # actually Person.find_by_user_name(user_name, options). So you could call <tt>Payment.find_all_by_amount(50, :order => "created_on")</tt>.
959f362 David Heinemeier Hansson Added find_all style to the new dynamic finders
dhh authored
157 #
a5a82d9 David Heinemeier Hansson Added extension capabilities to has_many and has_and_belongs_to_many pro...
dhh authored
158 # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with
159 # <tt>find_or_create_by_</tt> and will return the object if it already exists and otherwise creates it, then returns it. Example:
160 #
161 # # No 'Summer' tag exists
162 # Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")
163 #
164 # # Now the 'Summer' tag does exist
165 # Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
166 #
098fa94 David Heinemeier Hansson Fixed documentation snafus #575, #576, #577, #585
dhh authored
167 # == Saving arrays, hashes, and other non-mappable objects in text columns
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
168 #
169 # 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+.
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
170 # This makes it possible to store arrays, hashes, and other non-mappable objects without doing any additional work. Example:
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
171 #
db045db David Heinemeier Hansson Initial
dhh authored
172 # class User < ActiveRecord::Base
173 # serialize :preferences
174 # end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
175 #
0591c53 David Heinemeier Hansson Made the dynamic finders use the new find API and updated the examples h...
dhh authored
176 # user = User.create(:preferences) => { "background" => "black", "display" => large })
db045db David Heinemeier Hansson Initial
dhh authored
177 # User.find(user.id).preferences # => { "background" => "black", "display" => large }
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
178 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
179 # You can also specify a class option as the second parameter that'll raise an exception if a serialized object is retrieved as a
db045db David Heinemeier Hansson Initial
dhh authored
180 # descendent of a class not in the hierarchy. Example:
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
181 #
db045db David Heinemeier Hansson Initial
dhh authored
182 # class User < ActiveRecord::Base
66f44e6 David Heinemeier Hansson Updated documentation for serialize
dhh authored
183 # serialize :preferences, Hash
db045db David Heinemeier Hansson Initial
dhh authored
184 # end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
185 #
0591c53 David Heinemeier Hansson Made the dynamic finders use the new find API and updated the examples h...
dhh authored
186 # user = User.create(:preferences => %w( one two three ))
db045db David Heinemeier Hansson Initial
dhh authored
187 # User.find(user.id).preferences # raises SerializationTypeMismatch
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
188 #
db045db David Heinemeier Hansson Initial
dhh authored
189 # == Single table inheritance
190 #
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
191 # Active Record allows inheritance by storing the name of the class in a column that by default is called "type" (can be changed
db045db David Heinemeier Hansson Initial
dhh authored
192 # by overwriting <tt>Base.inheritance_column</tt>). This means that an inheritance looking like this:
193 #
194 # class Company < ActiveRecord::Base; end
195 # class Firm < Company; end
196 # class Client < Company; end
197 # class PriorityClient < Client; end
198 #
0591c53 David Heinemeier Hansson Made the dynamic finders use the new find API and updated the examples h...
dhh authored
199 # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then
200 # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object.
db045db David Heinemeier Hansson Initial
dhh authored
201 #
f033833 David Heinemeier Hansson Improving documentation...
dhh authored
202 # 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
203 # like normal subclasses with no special magic for differentiating between them or reloading the right type with find.
204 #
db045db David Heinemeier Hansson Initial
dhh authored
205 # Note, all the attributes for all the cases are kept in the same table. Read more:
206 # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
207 #
db045db David Heinemeier Hansson Initial
dhh authored
208 # == Connection to multiple databases in different models
209 #
210 # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection.
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
211 # All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection.
db045db David Heinemeier Hansson Initial
dhh authored
212 # For example, if Course is a ActiveRecord::Base, but resides in a different database you can just say Course.establish_connection
213 # and Course *and all its subclasses* will use this connection instead.
214 #
215 # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is
216 # requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool.
217 #
218 # == Exceptions
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
219 #
db045db David Heinemeier Hansson Initial
dhh authored
220 # * +ActiveRecordError+ -- generic error class and superclass of all other errors raised by Active Record
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
221 # * +AdapterNotSpecified+ -- the configuration hash used in <tt>establish_connection</tt> didn't include a
db045db David Heinemeier Hansson Initial
dhh authored
222 # <tt>:adapter</tt> key.
1aab0e2 David Heinemeier Hansson Doc fixes #1775, #1776 [jon@instance-design.co.uk]
dhh authored
223 # * +AdapterNotFound+ -- the <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified an non-existent adapter
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
224 # (or a bad spelling of an existing one).
225 # * +AssociationTypeMismatch+ -- the object assigned to the association wasn't of the type specified in the association definition.
226 # * +SerializationTypeMismatch+ -- the object serialized wasn't of the class specified as the second parameter.
db045db David Heinemeier Hansson Initial
dhh authored
227 # * +ConnectionNotEstablished+ -- no connection has been established. Use <tt>establish_connection</tt> before querying.
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
228 # * +RecordNotFound+ -- no record responded to the find* method.
db045db David Heinemeier Hansson Initial
dhh authored
229 # Either the row with the given ID doesn't exist or the row didn't meet the additional restrictions.
230 # * +StatementInvalid+ -- the database server rejected the SQL statement. The precise error is added in the message.
231 # Either the record with the given ID doesn't exist or the record didn't meet the additional restrictions.
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
232 # * +MultiparameterAssignmentErrors+ -- collection of errors that occurred during a mass assignment using the
233 # +attributes=+ method. The +errors+ property of this exception contains an array of +AttributeAssignmentError+
d2fefbe David Heinemeier Hansson Added MultiparameterAssignmentErrors and AttributeAssignmentError except...
dhh authored
234 # objects that should be inspected to determine which attributes triggered the errors.
235 # * +AttributeAssignmentError+ -- an error occurred while doing a mass assignment through the +attributes=+ method.
236 # You can inspect the +attribute+ property of the exception object to determine which attribute triggered the error.
5707027 David Heinemeier Hansson Added better exception error when unknown column types are used with mig...
dhh authored
237 #
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
238 # *Note*: The attributes listed are class-level attributes (accessible from both the class and instance level).
db045db David Heinemeier Hansson Initial
dhh authored
239 # So it's possible to assign a logger to the class through Base.logger= which will then be used by all
240 # instances in the current object space.
241 class Base
242 # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then passed
243 # on to any new database connections made and which can be retrieved on both a class and instance level by calling +logger+.
244 cattr_accessor :logger
1bce58b Nicholas Seckar Add Reloadable::OnlySubclasses which handles the common case where a bas...
seckar authored
245
ed08086 David Heinemeier Hansson Just go with Subclasses instead of OnlySubclasses
dhh authored
246 include Reloadable::Subclasses
1bce58b Nicholas Seckar Add Reloadable::OnlySubclasses which handles the common case where a bas...
seckar authored
247
db045db David Heinemeier Hansson Initial
dhh authored
248 def self.inherited(child) #:nodoc:
249 @@subclasses[self] ||= []
250 @@subclasses[self] << child
251 super
252 end
bfbf6bb Jamis Buck Allow ARStore::Session to indicate that it should not be reloaded in dev...
jamis authored
253
3c0129a David Heinemeier Hansson Fixed memory leak with Active Record classes when Dependencies.mechanism...
dhh authored
254 def self.reset_subclasses
bfbf6bb Jamis Buck Allow ARStore::Session to indicate that it should not be reloaded in dev...
jamis authored
255 nonreloadables = []
e7f61ea Jamis Buck squash the memleak in dev mode finally (fingers crossed, here)
jamis authored
256 subclasses.each do |klass|
bfbf6bb Jamis Buck Allow ARStore::Session to indicate that it should not be reloaded in dev...
jamis authored
257 unless klass.reloadable?
258 nonreloadables << klass
259 next
260 end
e7f61ea Jamis Buck squash the memleak in dev mode finally (fingers crossed, here)
jamis authored
261 klass.instance_variables.each { |var| klass.send(:remove_instance_variable, var) }
262 klass.instance_methods(false).each { |m| klass.send :undef_method, m }
263 end
bfbf6bb Jamis Buck Allow ARStore::Session to indicate that it should not be reloaded in dev...
jamis authored
264 @@subclasses = {}
265 nonreloadables.each { |klass| (@@subclasses[klass.superclass] ||= []) << klass }
3c0129a David Heinemeier Hansson Fixed memory leak with Active Record classes when Dependencies.mechanism...
dhh authored
266 end
267
db045db David Heinemeier Hansson Initial
dhh authored
268 @@subclasses = {}
c4a3634 Jeremy Kemper Corrected @@configurations typo. #1410 [david@ruppconsulting.com]
jeremy authored
269
db045db David Heinemeier Hansson Initial
dhh authored
270 cattr_accessor :configurations
c4a3634 Jeremy Kemper Corrected @@configurations typo. #1410 [david@ruppconsulting.com]
jeremy authored
271 @@configurations = {}
272
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
273 # Accessor for the prefix type that will be prepended to every primary key column name. The options are :table_name and
db045db David Heinemeier Hansson Initial
dhh authored
274 # :table_name_with_underscore. If the first is specified, the Product class will look for "productid" instead of "id" as
275 # the primary column. If the latter is specified, the Product class will look for "product_id" instead of "id". Remember
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
276 # that this is a global setting for all Active Records.
db045db David Heinemeier Hansson Initial
dhh authored
277 cattr_accessor :primary_key_prefix_type
278 @@primary_key_prefix_type = nil
279
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
280 # Accessor for the name of the prefix string to prepend to every table name. So if set to "basecamp_", all
098fa94 David Heinemeier Hansson Fixed documentation snafus #575, #576, #577, #585
dhh authored
281 # table names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient way of creating a namespace
db045db David Heinemeier Hansson Initial
dhh authored
282 # for tables in a shared database. By default, the prefix is the empty string.
283 cattr_accessor :table_name_prefix
284 @@table_name_prefix = ""
285
286 # Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
287 # "people_basecamp"). By default, the suffix is the empty string.
288 cattr_accessor :table_name_suffix
289 @@table_name_suffix = ""
290
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
291 # Indicates whether or not table names should be the pluralized versions of the corresponding class names.
292 # If true, the default table name for a +Product+ class will be +products+. If false, it would just be +product+.
db045db David Heinemeier Hansson Initial
dhh authored
293 # See table_name for the full rules on table/class naming. This is true, by default.
294 cattr_accessor :pluralize_table_names
295 @@pluralize_table_names = true
296
911614d David Heinemeier Hansson Added ActiveRecord::Base.colorize_logging to control whether to use colo...
dhh authored
297 # Determines whether or not to use ANSI codes to colorize the logging statements committed by the connection adapter. These colors
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
298 # make it much easier to overview things during debugging (when used through a reader like +tail+ and on a black background), but
911614d David Heinemeier Hansson Added ActiveRecord::Base.colorize_logging to control whether to use colo...
dhh authored
299 # may complicate matters if you use software like syslog. This is true, by default.
300 cattr_accessor :colorize_logging
301 @@colorize_logging = true
302
60de8c1 David Heinemeier Hansson Added Base.default_timezone accessor that determines whether to use Time...
dhh authored
303 # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling dates and times from the database.
304 # This is set to :local by default.
305 cattr_accessor :default_timezone
306 @@default_timezone = :local
6049977 David Heinemeier Hansson Fixed that each request with the WEBrick adapter would open a new databa...
dhh authored
307
308 # Determines whether or not to use a connection for each thread, or a single shared connection for all threads.
309 # Defaults to true; Railties' WEBrick server sets this to false.
b840e4e Deprecated ActiveRecord::Base.threaded_connection in favor of ActiveReco...
Marcel Molina authored
310 cattr_accessor :allow_concurrency
311 @@allow_concurrency = true
312
f218771 Add option (true by default) to generate reader methods for each attribu...
Marcel Molina authored
313 # Determines whether to speed up access by generating optimized reader
314 # methods to avoid expensive calls to method_missing when accessing
315 # attributes by name. You might want to set this to false in development
316 # mode, because the methods would be regenerated on each request.
317 cattr_accessor :generate_read_methods
318 @@generate_read_methods = true
24c3599 Sam Stephenson Support using different database adapters for development and test with ...
sstephenson authored
319
320 # Specifies the format to use when dumping the database schema with Rails'
321 # Rakefile. If :sql, the schema is dumped as (potentially database-
322 # specific) SQL statements. If :ruby, the schema is dumped as an
323 # ActiveRecord::Schema file which can be loaded into any database that
324 # supports migrations. Use :ruby if you want to have different database
325 # adapters for, e.g., your development and test environments.
326 cattr_accessor :schema_format
327 @@schema_format = :sql
f218771 Add option (true by default) to generate reader methods for each attribu...
Marcel Molina authored
328
db045db David Heinemeier Hansson Initial
dhh authored
329 class << self # Class methods
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
330 # Find operates with three different retrieval approaches:
7669011 David Heinemeier Hansson Fixes for postgresql testing #1129, #1130, #1131
dhh authored
331 #
332 # * Find by id: This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
333 # If no record can be found for all of the listed ids, then RecordNotFound will be raised.
334 # * Find first: This will return the first record matched by the options used. These options can either be specific
335 # conditions or merely an order. If no record can matched, nil is returned.
7d01005 David Heinemeier Hansson Fixed documentation and prepared for release of 0.12
dhh authored
336 # * Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned.
7669011 David Heinemeier Hansson Fixes for postgresql testing #1129, #1130, #1131
dhh authored
337 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
338 # All approaches accept an option hash as their last parameter. The options are:
7669011 David Heinemeier Hansson Fixes for postgresql testing #1129, #1130, #1131
dhh authored
339 #
515886a David Heinemeier Hansson Added documentation for new Base.find API and eager association loading
dhh authored
340 # * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
341 # * <tt>:order</tt>: An SQL fragment like "created_at DESC, name".
3309268 Jeremy Kemper Add :group option, correspond to GROUP BY, to the find method and to the...
jeremy authored
342 # * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
515886a David Heinemeier Hansson Added documentation for new Base.find API and eager association loading
dhh authored
343 # * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned.
344 # * <tt>:offset</tt>: An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows.
345 # * <tt>:joins</tt>: An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". (Rarely needed).
64fcb75 Jeremy Kemper r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
346 # The records will be returned read-only since they will have attributes that do not correspond to the table's columns.
7219e82 Jeremy Kemper HABTM finder sets :readonly => false. Closes #2525.
jeremy authored
347 # Pass :readonly => false to override.
515886a David Heinemeier Hansson Added documentation for new Base.find API and eager association loading
dhh authored
348 # * <tt>:include</tt>: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer
349 # to already defined associations. See eager loading under Associations.
6f05696 David Heinemeier Hansson Added :select option to find which can specify a different value than th...
dhh authored
350 # * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you for example want to do a join, but not
351 # include the joined columns.
64fcb75 Jeremy Kemper r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
352 # * <tt>:readonly</tt>: Mark the returned records read-only so they cannot be saved or updated.
7669011 David Heinemeier Hansson Fixes for postgresql testing #1129, #1130, #1131
dhh authored
353 #
515886a David Heinemeier Hansson Added documentation for new Base.find API and eager association loading
dhh authored
354 # Examples for find by id:
db045db David Heinemeier Hansson Initial
dhh authored
355 # Person.find(1) # returns the object for ID = 1
356 # Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
357 # Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
57ed93e David Heinemeier Hansson Fixed that Base#find will return an array if given an array -- regardles...
dhh authored
358 # Person.find([1]) # returns an array for objects the object with ID = 1
515886a David Heinemeier Hansson Added documentation for new Base.find API and eager association loading
dhh authored
359 # Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC")
360 #
361 # Examples for find first:
7d01005 David Heinemeier Hansson Fixed documentation and prepared for release of 0.12
dhh authored
362 # Person.find(:first) # returns the first object fetched by SELECT * FROM people
515886a David Heinemeier Hansson Added documentation for new Base.find API and eager association loading
dhh authored
363 # Person.find(:first, :conditions => [ "user_name = ?", user_name])
364 # Person.find(:first, :order => "created_on DESC", :offset => 5)
365 #
366 # Examples for find all:
7d01005 David Heinemeier Hansson Fixed documentation and prepared for release of 0.12
dhh authored
367 # Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people
515886a David Heinemeier Hansson Added documentation for new Base.find API and eager association loading
dhh authored
368 # Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50)
369 # Person.find(:all, :offset => 10, :limit => 10)
370 # Person.find(:all, :include => [ :account, :friends ])
3309268 Jeremy Kemper Add :group option, correspond to GROUP BY, to the find method and to the...
jeremy authored
371 # Person.find(:all, :group => "category")
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
372 def find(*args)
373 options = extract_options_from_args!(args)
db045db David Heinemeier Hansson Initial
dhh authored
374
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
375 # Inherit :readonly from finder scope if set. Otherwise,
e7cd7e9 Jeremy Kemper r3800@sedna: jeremy | 2005-10-28 00:39:05 -0700
jeremy authored
376 # if :joins is not blank then :readonly defaults to true.
377 unless options.has_key?(:readonly)
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
378 if scoped?(:find, :readonly)
379 options[:readonly] = scope(:find, :readonly)
e7cd7e9 Jeremy Kemper r3800@sedna: jeremy | 2005-10-28 00:39:05 -0700
jeremy authored
380 elsif !options[:joins].blank?
381 options[:readonly] = true
382 end
7219e82 Jeremy Kemper HABTM finder sets :readonly => false. Closes #2525.
jeremy authored
383 end
64fcb75 Jeremy Kemper r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
384
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
385 case args.first
386 when :first
5b9b904 David Heinemeier Hansson Added support for limit and offset with eager loading of has_one and bel...
dhh authored
387 find(:all, options.merge(options[:include] ? { } : { :limit => 1 })).first
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
388 when :all
64fcb75 Jeremy Kemper r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
389 records = options[:include] ? find_with_associations(options) : find_by_sql(construct_finder_sql(options))
390 records.each { |record| record.readonly! } if options[:readonly]
391 records
db045db David Heinemeier Hansson Initial
dhh authored
392 else
a9fd639 David Heinemeier Hansson Fixed that calling Model.find([]) returns [] and doesn't throw an except...
dhh authored
393 return args.first if args.first.kind_of?(Array) && args.first.empty?
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
394 expects_array = args.first.kind_of?(Array)
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
395
2a35baa Jamis Buck Wrap :conditions in parentheses to prevent problems with OR's #1871
jamis authored
396 conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
397
398 ids = args.flatten.compact.uniq
399 case ids.size
400 when 0
401 raise RecordNotFound, "Couldn't find #{name} without an ID#{conditions}"
402 when 1
9e799e7 David Heinemeier Hansson Prefix primary key with table name so it works as part of a joined fetch
dhh authored
403 if result = find(:first, options.merge({ :conditions => "#{table_name}.#{primary_key} = #{sanitize(ids.first)}#{conditions}" }))
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
404 return expects_array ? [ result ] : result
405 else
406 raise RecordNotFound, "Couldn't find #{name} with ID=#{ids.first}#{conditions}"
407 end
408 else
409 # Find multiple ids
410 ids_list = ids.map { |id| sanitize(id) }.join(',')
7879513 David Heinemeier Hansson Fixed incompatibility with Base#find with an array of ids that would fai...
dhh authored
411 result = find(:all, options.merge({ :conditions => "#{table_name}.#{primary_key} IN (#{ids_list})#{conditions}"}))
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
412 if result.size == ids.size
413 return result
414 else
415 raise RecordNotFound, "Couldn't find all #{name.pluralize} with IDs (#{ids_list})#{conditions}"
416 end
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
417 end
db045db David Heinemeier Hansson Initial
dhh authored
418 end
419 end
420
3dfa56c David Heinemeier Hansson Updated all references to the old find_first and find_all to use the new...
dhh authored
421 # Works like find(:all), but requires a complete SQL string. Examples:
db045db David Heinemeier Hansson Initial
dhh authored
422 # Post.find_by_sql "SELECT p.*, c.author FROM posts p, comments c WHERE p.id = c.post_id"
a775cb1 David Heinemeier Hansson Added the option for sanitizing find_by_sql and the offset parts in regu...
dhh authored
423 # Post.find_by_sql ["SELECT * FROM posts WHERE author = ? AND created > ?", author_id, start_date]
db045db David Heinemeier Hansson Initial
dhh authored
424 def find_by_sql(sql)
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
425 connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) }
db045db David Heinemeier Hansson Initial
dhh authored
426 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
427
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
428 # Returns true if the given +id+ represents the primary key of a record in the database, false otherwise.
429 # Example:
430 # Person.exists?(5)
431 def exists?(id)
0591c53 David Heinemeier Hansson Made the dynamic finders use the new find API and updated the examples h...
dhh authored
432 !find(:first, :conditions => ["#{primary_key} = ?", id]).nil? rescue false
db045db David Heinemeier Hansson Initial
dhh authored
433 end
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
434
db045db David Heinemeier Hansson Initial
dhh authored
435 # Creates an object, instantly saves it as a record (if the validation permits it), and returns it. If the save
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
436 # fails under validations, the unsaved object is still returned.
db045db David Heinemeier Hansson Initial
dhh authored
437 def create(attributes = nil)
efa81da David Heinemeier Hansson Added the option of supplying an array of ids and attributes to Base#upd...
dhh authored
438 if attributes.is_a?(Array)
439 attributes.collect { |attr| create(attr) }
440 else
441 object = new(attributes)
ed08086 David Heinemeier Hansson Just go with Subclasses instead of OnlySubclasses
dhh authored
442 scope(:create).each { |att,value| object.send("#{att}=", value) } if scoped?(:create)
efa81da David Heinemeier Hansson Added the option of supplying an array of ids and attributes to Base#upd...
dhh authored
443 object.save
444 object
445 end
db045db David Heinemeier Hansson Initial
dhh authored
446 end
447
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
448 # Finds the record from the passed +id+, instantly saves it with the passed +attributes+ (if the validation permits it),
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
449 # and returns it. If the save fails under validations, the unsaved object is still returned.
5e99422 David Heinemeier Hansson Updated docs (closes #3799) [ruby@bobsilva.com]
dhh authored
450 #
451 # The arguments may also be given as arrays in which case the update method is called for each pair of +id+ and
452 # +attributes+ and an array of objects is returned.
453 #
454 # Example of updating one record:
455 # Person.update(15, {:user_name => 'Samuel', :group => 'expert'})
456 #
457 # Example of updating multiple records:
458 # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy"} }
459 # Person.update(people.keys, people.values)
db045db David Heinemeier Hansson Initial
dhh authored
460 def update(id, attributes)
efa81da David Heinemeier Hansson Added the option of supplying an array of ids and attributes to Base#upd...
dhh authored
461 if id.is_a?(Array)
462 idx = -1
463 id.collect { |id| idx += 1; update(id, attributes[idx]) }
464 else
465 object = find(id)
466 object.update_attributes(attributes)
467 object
468 end
db045db David Heinemeier Hansson Initial
dhh authored
469 end
470
efa81da David Heinemeier Hansson Added the option of supplying an array of ids and attributes to Base#upd...
dhh authored
471 # Deletes the record with the given +id+ without instantiating an object first. If an array of ids is provided, all of them
472 # are deleted.
648b8fd David Heinemeier Hansson Added Base.destroy and Base.delete to remove records without holding a r...
dhh authored
473 def delete(id)
efa81da David Heinemeier Hansson Added the option of supplying an array of ids and attributes to Base#upd...
dhh authored
474 delete_all([ "#{primary_key} IN (?)", id ])
648b8fd David Heinemeier Hansson Added Base.destroy and Base.delete to remove records without holding a r...
dhh authored
475 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
476
648b8fd David Heinemeier Hansson Added Base.destroy and Base.delete to remove records without holding a r...
dhh authored
477 # Destroys the record with the given +id+ by instantiating the object and calling #destroy (all the callbacks are the triggered).
efa81da David Heinemeier Hansson Added the option of supplying an array of ids and attributes to Base#upd...
dhh authored
478 # If an array of ids is provided, all of them are destroyed.
648b8fd David Heinemeier Hansson Added Base.destroy and Base.delete to remove records without holding a r...
dhh authored
479 def destroy(id)
efa81da David Heinemeier Hansson Added the option of supplying an array of ids and attributes to Base#upd...
dhh authored
480 id.is_a?(Array) ? id.each { |id| destroy(id) } : find(id).destroy
648b8fd David Heinemeier Hansson Added Base.destroy and Base.delete to remove records without holding a r...
dhh authored
481 end
482
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
483 # Updates all records with the SET-part of an SQL update statement in +updates+ and returns an integer with the number of rows updated.
69cb942 David Heinemeier Hansson Changed the interface on AbstractAdapter to require that adapters return...
dhh authored
484 # A subset of the records can be selected by specifying +conditions+. Example:
db045db David Heinemeier Hansson Initial
dhh authored
485 # Billing.update_all "category = 'authorized', approved = 1", "author = 'David'"
486 def update_all(updates, conditions = nil)
566a369 David Heinemeier Hansson Added that update_all calls sanitize_sql on its updates argument, so stu...
dhh authored
487 sql = "UPDATE #{table_name} SET #{sanitize_sql(updates)} "
db045db David Heinemeier Hansson Initial
dhh authored
488 add_conditions!(sql, conditions)
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
489 connection.update(sql, "#{name} Update")
db045db David Heinemeier Hansson Initial
dhh authored
490 end
0d2db8a David Heinemeier Hansson Added Base.update_collection that can update an array of id/attribute pa...
dhh authored
491
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
492 # Destroys the objects for all the records that match the +condition+ by instantiating each object and calling
db045db David Heinemeier Hansson Initial
dhh authored
493 # the destroy method. Example:
494 # Person.destroy_all "last_login < '2004-04-04'"
495 def destroy_all(conditions = nil)
3dfa56c David Heinemeier Hansson Updated all references to the old find_first and find_all to use the new...
dhh authored
496 find(:all, :conditions => conditions).each { |object| object.destroy }
db045db David Heinemeier Hansson Initial
dhh authored
497 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
498
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
499 # Deletes all the records that match the +condition+ without instantiating the objects first (and hence not
db045db David Heinemeier Hansson Initial
dhh authored
500 # calling the destroy method). Example:
090bfce Jeremy Kemper Correct documentation for Base.delete_all. References #1568.
jeremy authored
501 # Post.delete_all "person_id = 5 AND (category = 'Something' OR category = 'Else')"
db045db David Heinemeier Hansson Initial
dhh authored
502 def delete_all(conditions = nil)
503 sql = "DELETE FROM #{table_name} "
504 add_conditions!(sql, conditions)
505 connection.delete(sql, "#{name} Delete all")
506 end
507
508 # Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
e17bf81 Jamis Buck Fix typo in count_by_sql documentation #1969 [Alexey Verkhovsky]
jamis authored
509 # Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
db045db David Heinemeier Hansson Initial
dhh authored
510 def count_by_sql(sql)
a775cb1 David Heinemeier Hansson Added the option for sanitizing find_by_sql and the offset parts in regu...
dhh authored
511 sql = sanitize_conditions(sql)
caaf40d David Heinemeier Hansson Added AbstractAdapter#select_value and AbstractAdapter#select_values as ...
dhh authored
512 connection.select_value(sql, "#{name} Count").to_i
db045db David Heinemeier Hansson Initial
dhh authored
513 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
514
515 # Increments the specified counter by one. So <tt>DiscussionBoard.increment_counter("post_count",
db045db David Heinemeier Hansson Initial
dhh authored
516 # discussion_board_id)</tt> would increment the "post_count" counter on the board responding to discussion_board_id.
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
517 # This is used for caching aggregate values, so that they don't need to be computed every time. Especially important
db045db David Heinemeier Hansson Initial
dhh authored
518 # for looping over a collection where each element require a number of aggregate values. Like the DiscussionBoard
519 # that needs to list both the number of posts and comments.
520 def increment_counter(counter_name, id)
4940383 David Heinemeier Hansson Fixed value quoting in all generated SQL statements, so that integers ar...
dhh authored
521 update_all "#{counter_name} = #{counter_name} + 1", "#{primary_key} = #{quote(id)}"
db045db David Heinemeier Hansson Initial
dhh authored
522 end
523
524 # Works like increment_counter, but decrements instead.
525 def decrement_counter(counter_name, id)
4940383 David Heinemeier Hansson Fixed value quoting in all generated SQL statements, so that integers ar...
dhh authored
526 update_all "#{counter_name} = #{counter_name} - 1", "#{primary_key} = #{quote(id)}"
db045db David Heinemeier Hansson Initial
dhh authored
527 end
528
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
529 # Attributes named in this macro are protected from mass-assignment, such as <tt>new(attributes)</tt> and
db045db David Heinemeier Hansson Initial
dhh authored
530 # <tt>attributes=(attributes)</tt>. Their assignment will simply be ignored. Instead, you can use the direct writer
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
531 # methods to do assignment. This is meant to protect sensitive attributes from being overwritten by URL/form hackers. Example:
db045db David Heinemeier Hansson Initial
dhh authored
532 #
533 # class Customer < ActiveRecord::Base
534 # attr_protected :credit_rating
535 # end
536 #
537 # customer = Customer.new("name" => David, "credit_rating" => "Excellent")
538 # customer.credit_rating # => nil
539 # customer.attributes = { "description" => "Jolly fellow", "credit_rating" => "Superb" }
540 # customer.credit_rating # => nil
541 #
542 # customer.credit_rating = "Average"
543 # customer.credit_rating # => "Average"
544 def attr_protected(*attributes)
0e0e774 Protect id attribute from mass assigment even when the primary key is se...
Marcel Molina authored
545 write_inheritable_array("attr_protected", attributes - (protected_attributes || []))
db045db David Heinemeier Hansson Initial
dhh authored
546 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
547
098fa94 David Heinemeier Hansson Fixed documentation snafus #575, #576, #577, #585
dhh authored
548 # Returns an array of all the attributes that have been protected from mass-assignment.
db045db David Heinemeier Hansson Initial
dhh authored
549 def protected_attributes # :nodoc:
550 read_inheritable_attribute("attr_protected")
551 end
552
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
553 # If this macro is used, only those attributes named in it will be accessible for mass-assignment, such as
db045db David Heinemeier Hansson Initial
dhh authored
554 # <tt>new(attributes)</tt> and <tt>attributes=(attributes)</tt>. This is the more conservative choice for mass-assignment
555 # protection. If you'd rather start from an all-open default and restrict attributes as needed, have a look at
556 # attr_protected.
557 def attr_accessible(*attributes)
0e0e774 Protect id attribute from mass assigment even when the primary key is se...
Marcel Molina authored
558 write_inheritable_array("attr_accessible", attributes - (accessible_attributes || []))
db045db David Heinemeier Hansson Initial
dhh authored
559 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
560
098fa94 David Heinemeier Hansson Fixed documentation snafus #575, #576, #577, #585
dhh authored
561 # Returns an array of all the attributes that have been made accessible to mass-assignment.
db045db David Heinemeier Hansson Initial
dhh authored
562 def accessible_attributes # :nodoc:
563 read_inheritable_attribute("attr_accessible")
564 end
565
566 # Specifies that the attribute by the name of +attr_name+ should be serialized before saving to the database and unserialized
567 # after loading from the database. The serialization is done through YAML. If +class_name+ is specified, the serialized
098fa94 David Heinemeier Hansson Fixed documentation snafus #575, #576, #577, #585
dhh authored
568 # object must be of that class on retrieval or +SerializationTypeMismatch+ will be raised.
db045db David Heinemeier Hansson Initial
dhh authored
569 def serialize(attr_name, class_name = Object)
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
570 serialized_attributes[attr_name.to_s] = class_name
db045db David Heinemeier Hansson Initial
dhh authored
571 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
572
db045db David Heinemeier Hansson Initial
dhh authored
573 # Returns a hash of all the attributes that have been specified for serialization as keys and their class restriction as values.
574 def serialized_attributes
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
575 read_inheritable_attribute("attr_serialized") or write_inheritable_attribute("attr_serialized", {})
db045db David Heinemeier Hansson Initial
dhh authored
576 end
577
578 # Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending
579 # directly from ActiveRecord. So if the hierarchy looks like: Reply < Message < ActiveRecord, then Message is used
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
580 # to guess the table name from even when called on Reply. The rules used to do the guess are handled by the Inflector class
581 # in Active Support, which knows almost all common English inflections (report a bug if your inflection isn't covered).
db045db David Heinemeier Hansson Initial
dhh authored
582 #
583 # Additionally, the class-level table_name_prefix is prepended to the table_name and the table_name_suffix is appended.
584 # So if you have "myapp_" as a prefix, the table name guess for an Account class becomes "myapp_accounts".
585 #
586 # You can also overwrite this class method to allow for unguessable links, such as a Mouse class with a link to a
587 # "mice" table. Example:
588 #
589 # class Mouse < ActiveRecord::Base
9982578 David Heinemeier Hansson Doc fix #805
dhh authored
590 # set_table_name "mice"
db045db David Heinemeier Hansson Initial
dhh authored
591 # end
dcc4868 David Heinemeier Hansson Fixed that Base.table_name would expect a parameter when used in has_and...
dhh authored
592 def table_name
d736568 Speed up the setting of table_name. Closes #2428.
Marcel Molina authored
593 reset_table_name
594 end
595
596 def reset_table_name
597 name = "#{table_name_prefix}#{undecorated_table_name(class_name_of_active_record_descendant(self))}#{table_name_suffix}"
598 set_table_name name
599 name
db045db David Heinemeier Hansson Initial
dhh authored
600 end
601
098fa94 David Heinemeier Hansson Fixed documentation snafus #575, #576, #577, #585
dhh authored
602 # Defines the primary key field -- can be overridden in subclasses. Overwriting will negate any effect of the
db045db David Heinemeier Hansson Initial
dhh authored
603 # primary_key_prefix_type setting, though.
604 def primary_key
c0899bc Add convenience predicate methods on Column class. In partial fullfilmen...
Marcel Molina authored
605 reset_primary_key
606 end
607
608 def reset_primary_key
609 key = 'id'
db045db David Heinemeier Hansson Initial
dhh authored
610 case primary_key_prefix_type
611 when :table_name
c0899bc Add convenience predicate methods on Column class. In partial fullfilmen...
Marcel Molina authored
612 key = Inflector.foreign_key(class_name_of_active_record_descendant(self), false)
db045db David Heinemeier Hansson Initial
dhh authored
613 when :table_name_with_underscore
c0899bc Add convenience predicate methods on Column class. In partial fullfilmen...
Marcel Molina authored
614 key = Inflector.foreign_key(class_name_of_active_record_descendant(self))
db045db David Heinemeier Hansson Initial
dhh authored
615 end
c0899bc Add convenience predicate methods on Column class. In partial fullfilmen...
Marcel Molina authored
616 set_primary_key(key)
617 key
db045db David Heinemeier Hansson Initial
dhh authored
618 end
619
620 # Defines the column name for use with single table inheritance -- can be overridden in subclasses.
621 def inheritance_column
622 "type"
623 end
624
7c8f3ed Jeremy Kemper r4325@asus: jeremy | 2005-11-12 03:57:46 -0800
jeremy authored
625 # Lazy-set the sequence name to the connection's default. This method
626 # is only ever called once since set_sequence_name overrides it.
14ea312 David Heinemeier Hansson Made Oracle a first-class connection adapter by adhering closer to idiom...
dhh authored
627 def sequence_name
7c8f3ed Jeremy Kemper r4325@asus: jeremy | 2005-11-12 03:57:46 -0800
jeremy authored
628 reset_sequence_name
629 end
630
631 def reset_sequence_name
632 default = connection.default_sequence_name(table_name, primary_key)
633 set_sequence_name(default)
634 default
14ea312 David Heinemeier Hansson Made Oracle a first-class connection adapter by adhering closer to idiom...
dhh authored
635 end
636
1aa82b3 David Heinemeier Hansson Added keyword-style approach to defining the custom relational bindings ...
dhh authored
637 # Sets the table name to use to the given value, or (if the value
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
638 # is nil or false) to the value returned by the given block.
1aa82b3 David Heinemeier Hansson Added keyword-style approach to defining the custom relational bindings ...
dhh authored
639 #
640 # Example:
641 #
642 # class Project < ActiveRecord::Base
643 # set_table_name "project"
644 # end
645 def set_table_name( value=nil, &block )
646 define_attr_method :table_name, value, &block
647 end
648 alias :table_name= :set_table_name
649
650 # Sets the name of the primary key column to use to the given value,
651 # or (if the value is nil or false) to the value returned by the given
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
652 # block.
1aa82b3 David Heinemeier Hansson Added keyword-style approach to defining the custom relational bindings ...
dhh authored
653 #
654 # Example:
655 #
656 # class Project < ActiveRecord::Base
657 # set_primary_key "sysid"
658 # end
659 def set_primary_key( value=nil, &block )
660 define_attr_method :primary_key, value, &block
661 end
662 alias :primary_key= :set_primary_key
663
664 # Sets the name of the inheritance column to use to the given value,
665 # or (if the value # is nil or false) to the value returned by the
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
666 # given block.
1aa82b3 David Heinemeier Hansson Added keyword-style approach to defining the custom relational bindings ...
dhh authored
667 #
668 # Example:
669 #
670 # class Project < ActiveRecord::Base
671 # set_inheritance_column do
672 # original_inheritance_column + "_id"
673 # end
674 # end
675 def set_inheritance_column( value=nil, &block )
676 define_attr_method :inheritance_column, value, &block
677 end
678 alias :inheritance_column= :set_inheritance_column
679
14ea312 David Heinemeier Hansson Made Oracle a first-class connection adapter by adhering closer to idiom...
dhh authored
680 # Sets the name of the sequence to use when generating ids to the given
681 # value, or (if the value is nil or false) to the value returned by the
7117fdb Jeremy Kemper r3616@asus: jeremy | 2005-09-26 23:09:28 -0700
jeremy authored
682 # given block. This is required for Oracle and is useful for any
683 # database which relies on sequences for primary key generation.
14ea312 David Heinemeier Hansson Made Oracle a first-class connection adapter by adhering closer to idiom...
dhh authored
684 #
2076dca Jeremy Kemper r3095@asus: jeremy | 2005-11-15 22:40:51 -0800
jeremy authored
685 # If a sequence name is not explicitly set when using Oracle or Firebird,
686 # it will default to the commonly used pattern of: #{table_name}_seq
687 #
688 # If a sequence name is not explicitly set when using PostgreSQL, it
689 # will discover the sequence corresponding to your primary key for you.
14ea312 David Heinemeier Hansson Made Oracle a first-class connection adapter by adhering closer to idiom...
dhh authored
690 #
691 # Example:
692 #
693 # class Project < ActiveRecord::Base
694 # set_sequence_name "projectseq" # default would have been "project_seq"
695 # end
696 def set_sequence_name( value=nil, &block )
697 define_attr_method :sequence_name, value, &block
698 end
699 alias :sequence_name= :set_sequence_name
700
db045db David Heinemeier Hansson Initial
dhh authored
701 # Turns the +table_name+ back into a class name following the reverse rules of +table_name+.
702 def class_name(table_name = table_name) # :nodoc:
703 # remove any prefix and/or suffix from the table name
81737fc Jeremy Kemper r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
704 class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].camelize
705 class_name = class_name.singularize if pluralize_table_names
706 class_name
db045db David Heinemeier Hansson Initial
dhh authored
707 end
708
816f37a David Heinemeier Hansson Added migration support to SQL Server adapter (please someone do the sam...
dhh authored
709 # Indicates whether the table associated with this class exists
710 def table_exists?
711 if connection.respond_to?(:tables)
712 connection.tables.include? table_name
713 else
714 # if the connection adapter hasn't implemented tables, there are two crude tests that can be
715 # used - see if getting column info raises an error, or if the number of columns returned is zero
716 begin
717 reset_column_information
718 columns.size > 0
719 rescue ActiveRecord::StatementInvalid
720 false
721 end
722 end
723 end
724
db045db David Heinemeier Hansson Initial
dhh authored
725 # Returns an array of column objects for the table associated with this class.
726 def columns
c0899bc Add convenience predicate methods on Column class. In partial fullfilmen...
Marcel Molina authored
727 unless @columns
728 @columns = connection.columns(table_name, "#{name} Columns")
729 @columns.each {|column| column.primary = column.name == primary_key}
730 end
731 @columns
db045db David Heinemeier Hansson Initial
dhh authored
732 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
733
db045db David Heinemeier Hansson Initial
dhh authored
734 # Returns an array of column objects for the table associated with this class.
735 def columns_hash
736 @columns_hash ||= columns.inject({}) { |hash, column| hash[column.name] = column; hash }
737 end
d0bd3b5 Jeremy Kemper Return PostgreSQL columns in the order they are declared #1374 (perlguy@...
jeremy authored
738
49d0f0c David Heinemeier Hansson Speeded up eager loading a whole bunch
dhh authored
739 def column_names
d0bd3b5 Jeremy Kemper Return PostgreSQL columns in the order they are declared #1374 (perlguy@...
jeremy authored
740 @column_names ||= columns.map { |column| column.name }
49d0f0c David Heinemeier Hansson Speeded up eager loading a whole bunch
dhh authored
741 end
db045db David Heinemeier Hansson Initial
dhh authored
742
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
743 # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
744 # and columns used for single table inheritance have been removed.
db045db David Heinemeier Hansson Initial
dhh authored
745 def content_columns
c0899bc Add convenience predicate methods on Column class. In partial fullfilmen...
Marcel Molina authored
746 @content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
db045db David Heinemeier Hansson Initial
dhh authored
747 end
748
749 # Returns a hash of all the methods added to query each of the columns in the table with the name of the method as the key
750 # and true as the value. This makes it possible to do O(1) lookups in respond_to? to check if a given method for attribute
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
751 # is available.
db045db David Heinemeier Hansson Initial
dhh authored
752 def column_methods_hash
d0bd3b5 Jeremy Kemper Return PostgreSQL columns in the order they are declared #1374 (perlguy@...
jeremy authored
753 @dynamic_methods_hash ||= column_names.inject(Hash.new(false)) do |methods, attr|
3ab3a70 Jeremy Kemper Clarify semantics of ActiveRecord::Base#respond_to? Closes #2560.
jeremy authored
754 attr_name = attr.to_s
755 methods[attr.to_sym] = attr_name
756 methods["#{attr}=".to_sym] = attr_name
757 methods["#{attr}?".to_sym] = attr_name
758 methods["#{attr}_before_type_cast".to_sym] = attr_name
db045db David Heinemeier Hansson Initial
dhh authored
759 methods
760 end
761 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
762
f218771 Add option (true by default) to generate reader methods for each attribu...
Marcel Molina authored
763 # Contains the names of the generated reader methods.
764 def read_methods
aabf909 Jeremy Kemper Correct reader method generation for primary key attribute: handle case ...
jeremy authored
765 @read_methods ||= Set.new
f218771 Add option (true by default) to generate reader methods for each attribu...
Marcel Molina authored
766 end
aabf909 Jeremy Kemper Correct reader method generation for primary key attribute: handle case ...
jeremy authored
767
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
768 # Resets all the cached information about columns, which will cause them to be reloaded on the next request.
1314f48 David Heinemeier Hansson Added methods for resetting the cached information on classes that you w...
dhh authored
769 def reset_column_information
aabf909 Jeremy Kemper Correct reader method generation for primary key attribute: handle case ...
jeremy authored
770 read_methods.each { |name| undef_method(name) }
f218771 Add option (true by default) to generate reader methods for each attribu...
Marcel Molina authored
771 @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = @read_methods = nil
1314f48 David Heinemeier Hansson Added methods for resetting the cached information on classes that you w...
dhh authored
772 end
773
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
774 def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc:
1314f48 David Heinemeier Hansson Added methods for resetting the cached information on classes that you w...
dhh authored
775 subclasses.each { |klass| klass.reset_inheritable_attributes; klass.reset_column_information }
776 end
db045db David Heinemeier Hansson Initial
dhh authored
777
778 # Transforms attribute key names into a more humane format, such as "First name" instead of "first_name". Example:
779 # Person.human_attribute_name("first_name") # => "First name"
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
780 # Deprecated in favor of just calling "first_name".humanize
781 def human_attribute_name(attribute_key_name) #:nodoc:
1f7e72f David Heinemeier Hansson Made human_attribute_name(attribute_key_name) use Inflector.humanize
dhh authored
782 attribute_key_name.humanize
db045db David Heinemeier Hansson Initial
dhh authored
783 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
784
db045db David Heinemeier Hansson Initial
dhh authored
785 def descends_from_active_record? # :nodoc:
81737fc Jeremy Kemper r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
786 superclass == Base || !columns_hash.include?(inheritance_column)
db045db David Heinemeier Hansson Initial
dhh authored
787 end
788
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
789 def quote(object) #:nodoc:
4940383 David Heinemeier Hansson Fixed value quoting in all generated SQL statements, so that integers ar...
dhh authored
790 connection.quote(object)
791 end
792
793 # Used to sanitize objects before they're used in an SELECT SQL-statement. Delegates to <tt>connection.quote</tt>.
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
794 def sanitize(object) #:nodoc:
4940383 David Heinemeier Hansson Fixed value quoting in all generated SQL statements, so that integers ar...
dhh authored
795 connection.quote(object)
db045db David Heinemeier Hansson Initial
dhh authored
796 end
797
f2a89d7 David Heinemeier Hansson Give AR the new benchmark method too
dhh authored
798 # Log and benchmark multiple statements in a single block. Example:
db045db David Heinemeier Hansson Initial
dhh authored
799 #
800 # Project.benchmark("Creating project") do
801 # project = Project.create("name" => "stuff")
802 # project.create_manager("name" => "David")
3dfa56c David Heinemeier Hansson Updated all references to the old find_first and find_all to use the new...
dhh authored
803 # project.milestones << Milestone.find(:all)
db045db David Heinemeier Hansson Initial
dhh authored
804 # end
5e8e8d6 David Heinemeier Hansson Added use_silence parameter to ActiveRecord::Base.benchmark that can be ...
dhh authored
805 #
f2a89d7 David Heinemeier Hansson Give AR the new benchmark method too
dhh authored
806 # The benchmark is only recorded if the current level of the logger matches the <tt>log_level</tt>, which makes it
807 # easy to include benchmarking statements in production software that will remain inexpensive because the benchmark
808 # will only be conducted if the log level is low enough.
809 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
810 # The logging of the multiple statements is turned off unless <tt>use_silence</tt> is set to false.
f2a89d7 David Heinemeier Hansson Give AR the new benchmark method too
dhh authored
811 def benchmark(title, log_level = Logger::DEBUG, use_silence = true)
812 if logger && logger.level == log_level
5e8e8d6 David Heinemeier Hansson Added use_silence parameter to ActiveRecord::Base.benchmark that can be ...
dhh authored
813 result = nil
814 seconds = Benchmark.realtime { result = use_silence ? silence { yield } : yield }
f2a89d7 David Heinemeier Hansson Give AR the new benchmark method too
dhh authored
815 logger.add(log_level, "#{title} (#{'%.5f' % seconds})")
5e8e8d6 David Heinemeier Hansson Added use_silence parameter to ActiveRecord::Base.benchmark that can be ...
dhh authored
816 result
817 else
818 yield
819 end
c00bf5f David Heinemeier Hansson Fixed the verbosity of using the AR store
dhh authored
820 end
81737fc Jeremy Kemper r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
821
c00bf5f David Heinemeier Hansson Fixed the verbosity of using the AR store
dhh authored
822 # Silences the logger for the duration of the block.
823 def silence
81737fc Jeremy Kemper r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
824 old_logger_level, logger.level = logger.level, Logger::ERROR if logger
825 yield
826 ensure
908e9a1 David Heinemeier Hansson Fixed that Base.silence should restore the old logger level when done, n...
dhh authored
827 logger.level = old_logger_level if logger
db045db David Heinemeier Hansson Initial
dhh authored
828 end
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
829
830 # Scope parameters to method calls within the block. Takes a hash of method_name => parameters hash.
831 # method_name may be :find or :create.
832 # :find parameters may include the <tt>:conditions</tt>, <tt>:joins</tt>,
833 # <tt>:offset</tt>, <tt>:limit</tt>, and <tt>:readonly</tt> options.
834 # :create parameters are an attributes hash.
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
835 #
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
836 # Article.with_scope(:find => { :conditions => "blog_id = 1" }, :create => { :blog_id => 1 }) do
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
837 # Article.find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
838 # a = Article.create(1)
839 # a.blog_id == 1
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
840 # end
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
841 def with_scope(method_scoping = {})
842 # Dup first and second level of hash (method and params).
843 method_scoping = method_scoping.inject({}) do |hash, (method, params)|
844 hash[method] = params.dup
845 hash
846 end
847
43f6643 David Heinemeier Hansson Fix form_for use of datetime_select and date_select as well as a few sty...
dhh authored
848 method_scoping.assert_valid_keys([ :find, :create ])
849
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
850 if f = method_scoping[:find]
43f6643 David Heinemeier Hansson Fix form_for use of datetime_select and date_select as well as a few sty...
dhh authored
851 f.assert_valid_keys([ :conditions, :joins, :from, :offset, :limit, :readonly ])
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
852 f[:readonly] = true if !f[:joins].blank? && !f.has_key?(:readonly)
853 end
a5a82d9 David Heinemeier Hansson Added extension capabilities to has_many and has_and_belongs_to_many pro...
dhh authored
854
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
855 raise ArgumentError, "Nested scopes are not yet supported: #{scoped_methods.inspect}" unless scoped_methods.nil?
a5a82d9 David Heinemeier Hansson Added extension capabilities to has_many and has_and_belongs_to_many pro...
dhh authored
856
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
857 self.scoped_methods = method_scoping
858 yield
e7cd7e9 Jeremy Kemper r3800@sedna: jeremy | 2005-10-28 00:39:05 -0700
jeremy authored
859 ensure
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
860 self.scoped_methods = nil
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
861 end
db045db David Heinemeier Hansson Initial
dhh authored
862
97849de David Heinemeier Hansson Fixed that association proxies would fail === tests like PremiumSubscrip...
dhh authored
863 # Overwrite the default class equality method to provide support for association proxies.
864 def ===(object)
865 object.is_a?(self)
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
866 end
b840e4e Deprecated ActiveRecord::Base.threaded_connection in favor of ActiveReco...
Marcel Molina authored
867
868 # Deprecated
869 def threaded_connections
870 allow_concurrency
871 end
872
873 # Deprecated
874 def threaded_connections=(value)
875 self.allow_concurrency = value
876 end
877
d2f4750 Jamis Buck Add AR::Base.base_class for querying the ancestor AR::Base subclass [Jam...
jamis authored
878 # Returns the base AR subclass that this class descends from. If A
879 # extends AR::Base, A.base_class will return A. If B descends from A
880 # through some arbitrarily deep hierarchy, B.base_class will return A.
881 def base_class
882 class_of_active_record_descendant(self)
883 end
884
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
885
db045db David Heinemeier Hansson Initial
dhh authored
886 private
887 # Finder methods must instantiate through this method to work with the single-table inheritance model
888 # that makes it possible to create objects of different types from the same table.
889 def instantiate(record)
eb2fbf0 Optimize instantiation of STI subclass records. In partial fullfilment o...
Marcel Molina authored
890 object =
891 if subclass_name = record[inheritance_column]
892 if subclass_name.empty?
893 allocate
894 else
895 require_association_class(subclass_name)
896 begin
897 compute_type(subclass_name).allocate
898 rescue NameError
899 raise SubclassNotFound,
900 "The single-table inheritance mechanism failed to locate the subclass: '#{record[inheritance_column]}'. " +
901 "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
902 "Please rename this column if you didn't intend it to be used for storing the inheritance class " +
903 "or overwrite #{self.to_s}.inheritance_column to use another column for that information."
904 end
905 end
906 else
907 allocate
81737fc Jeremy Kemper r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
908 end
605bc77 David Heinemeier Hansson Added a better exception for when a type column is used in a table witho...
dhh authored
909
db045db David Heinemeier Hansson Initial
dhh authored
910 object.instance_variable_set("@attributes", record)
81737fc Jeremy Kemper r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
911 object
db045db David Heinemeier Hansson Initial
dhh authored
912 end
81737fc Jeremy Kemper r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
913
c7d6d68 Jeremy Kemper Reflections don't attempt to resolve module nesting of association class...
jeremy authored
914 # Nest the type name in the same module as this class.
915 # Bar is "MyApp::Business::Bar" relative to MyApp::Business::Foo
db045db David Heinemeier Hansson Initial
dhh authored
916 def type_name_with_module(type_name)
c7d6d68 Jeremy Kemper Reflections don't attempt to resolve module nesting of association class...
jeremy authored
917 "#{self.name.sub(/(::)?[^:]+$/, '')}#{$1}#{type_name}"
db045db David Heinemeier Hansson Initial
dhh authored
918 end
919
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
920 def construct_finder_sql(options)
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
921 sql = "SELECT #{options[:select] || '*'} "
90099e9 made .find() and class method delegation work on :through relations
Tobias Lütke authored
922 sql << "FROM #{scope(:find, :from) || options[:from] || table_name} "
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
923
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
924 add_joins!(sql, options)
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
925 add_conditions!(sql, options[:conditions])
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
926
3309268 Jeremy Kemper Add :group option, correspond to GROUP BY, to the find method and to the...
jeremy authored
927 sql << " GROUP BY #{options[:group]} " if options[:group]
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
928 sql << " ORDER BY #{options[:order]} " if options[:order]
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
929
efb55d1 David Heinemeier Hansson Allow order, conditions, and joins in finds that include associations
dhh authored
930 add_limit!(sql, options)
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
931
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
932 sql
efb55d1 David Heinemeier Hansson Allow order, conditions, and joins in finds that include associations
dhh authored
933 end
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
934
efb55d1 David Heinemeier Hansson Allow order, conditions, and joins in finds that include associations
dhh authored
935 def add_limit!(sql, options)
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
936 options[:limit] ||= scope(:find, :limit)
937 options[:offset] ||= scope(:find, :offset)
f2a29ca David Heinemeier Hansson Added support for ODBC connections to MS SQL Server so you can connect f...
dhh authored
938 connection.add_limit_offset!(sql, options)
abc895b David Heinemeier Hansson Added new Base.find API and deprecated find_all, find_first. Added preli...
dhh authored
939 end
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
940
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
941 def add_joins!(sql, options)
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
942 join = scope(:find, :joins) || options[:joins]
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
943 sql << " #{join} " if join
944 end
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
945
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
946 # Adds a sanitized version of +conditions+ to the +sql+ string. Note that the passed-in +sql+ string is changed.
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
947 def add_conditions!(sql, conditions)
bbec3ae Sanitize scoped conditions.
Marcel Molina authored
948 segments = [sanitize_sql(scope(:find, :conditions))]
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
949 segments << sanitize_sql(conditions) unless conditions.nil?
950 segments << type_condition unless descends_from_active_record?
951 segments.compact!
952 sql << "WHERE (#{segments.join(") AND (")}) " unless segments.empty?
db045db David Heinemeier Hansson Initial
dhh authored
953 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
954
db045db David Heinemeier Hansson Initial
dhh authored
955 def type_condition
2076dca Jeremy Kemper r3095@asus: jeremy | 2005-11-15 22:40:51 -0800
jeremy authored
956 quoted_inheritance_column = connection.quote_column_name(inheritance_column)
957 type_condition = subclasses.inject("#{table_name}.#{quoted_inheritance_column} = '#{name.demodulize}' ") do |condition, subclass|
958 condition << "OR #{table_name}.#{quoted_inheritance_column} = '#{subclass.name.demodulize}' "
fdd2681 David Heinemeier Hansson Made eager loading work with inheritance hierarchies #1065 [Ryan Carver]
dhh authored
959 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
960
961 " (#{type_condition}) "
db045db David Heinemeier Hansson Initial
dhh authored
962 end
963
964 # Guesses the table name, but does not decorate it with prefix and suffix information.
965 def undecorated_table_name(class_name = class_name_of_active_record_descendant(self))
966 table_name = Inflector.underscore(Inflector.demodulize(class_name))
967 table_name = Inflector.pluralize(table_name) if pluralize_table_names
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
968 table_name
db045db David Heinemeier Hansson Initial
dhh authored
969 end
970
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
971 # Enables dynamic finders like find_by_user_name(user_name) and find_by_user_name_and_password(user_name, password) that are turned into
972 # find(:first, :conditions => ["user_name = ?", user_name]) and find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password])
3dfa56c David Heinemeier Hansson Updated all references to the old find_first and find_all to use the new...
dhh authored
973 # respectively. Also works for find(:all), but using find_all_by_amount(50) that are turned into find(:all, :conditions => ["amount = ?", 50]).
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
974 #
0591c53 David Heinemeier Hansson Made the dynamic finders use the new find API and updated the examples h...
dhh authored
975 # It's even possible to use all the additional parameters to find. For example, the full interface for find_all_by_amount
976 # is actually find_all_by_amount(amount, options).
ac8fd7d David Heinemeier Hansson Added dynamic attribute-based finders as a cleaner way of getting object...
dhh authored
977 def method_missing(method_id, *arguments)
a5a82d9 David Heinemeier Hansson Added extension capabilities to has_many and has_and_belongs_to_many pro...
dhh authored
978 if match = /find_(all_by|by)_([_a-zA-Z]\w*)/.match(method_id.to_s)
979 finder = determine_finder(match)
ac8fd7d David Heinemeier Hansson Added dynamic attribute-based finders as a cleaner way of getting object...
dhh authored
980
a5a82d9 David Heinemeier Hansson Added extension capabilities to has_many and has_and_belongs_to_many pro...
dhh authored
981 attribute_names = extract_attribute_names_from_match(match)
982 super unless all_attributes_exists?(attribute_names)
93ec130 David Heinemeier Hansson Fixed that the dynamic finders didnt treat nil as a "IS NULL" but rather...
dhh authored
983
a5a82d9 David Heinemeier Hansson Added extension capabilities to has_many and has_and_belongs_to_many pro...
dhh authored
984 conditions = construct_conditions_from_arguments(attribute_names, arguments)
81737fc Jeremy Kemper r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
985
297618b Make dynamic finders honor additional passed in :conditions. Closes #356...
Marcel Molina authored
986 if (extra_options = arguments[attribute_names.size]).is_a?(Hash)
987 finder_options = extra_options.merge(:conditions => conditions)
988 if extra_options[:conditions]
989 with_scope(:find => {:conditions => extra_options[:conditions]}) do
990 find(finder, finder_options)
991 end
992 else
993 find(finder, finder_options)
994 end
0591c53 David Heinemeier Hansson Made the dynamic finders use the new find API and updated the examples h...
dhh authored
995 else
a5a82d9 David Heinemeier Hansson Added extension capabilities to has_many and has_and_belongs_to_many pro...
dhh authored
996 send("find_#{finder}", conditions, *arguments[attribute_names.length..-1]) # deprecated API
0591c53 David Heinemeier Hansson Made the dynamic finders use the new find API and updated the examples h...
dhh authored
997 end
a5a82d9 David Heinemeier Hansson Added extension capabilities to has_many and has_and_belongs_to_many pro...
dhh authored
998 elsif match = /find_or_create_by_([_a-zA-Z]\w*)/.match(method_id.to_s)
999 attribute_names = extract_attribute_names_from_match(match)
1000 super unless all_attributes_exists?(attribute_names)
1001
1002 find(:first, :conditions => construct_conditions_from_arguments(attribute_names, arguments)) ||
1003 create(construct_attributes_from_arguments(attribute_names, arguments))
ac8fd7d David Heinemeier Hansson Added dynamic attribute-based finders as a cleaner way of getting object...
dhh authored
1004 else
1005 super
1006 end
1007 end
db045db David Heinemeier Hansson Initial
dhh authored
1008
a5a82d9 David Heinemeier Hansson Added extension capabilities to has_many and has_and_belongs_to_many pro...
dhh authored
1009 def determine_finder(match)
1010 match.captures.first == 'all_by' ? :all : :first
1011 end
1012
1013 def extract_attribute_names_from_match(match)
1014 match.captures.last.split('_and_')
1015 end
1016
1017 def construct_conditions_from_arguments(attribute_names, arguments)
1018 conditions = []
2076dca Jeremy Kemper r3095@asus: jeremy | 2005-11-15 22:40:51 -0800
jeremy authored
1019 attribute_names.each_with_index { |name, idx| conditions << "#{table_name}.#{connection.quote_column_name(name)} #{attribute_condition(arguments[idx])} " }
a5a82d9 David Heinemeier Hansson Added extension capabilities to has_many and has_and_belongs_to_many pro...
dhh authored
1020 [ conditions.join(" AND "), *arguments[0...attribute_names.length] ]
1021 end
1022
1023 def construct_attributes_from_arguments(attribute_names, arguments)
1024 attributes = {}
1025 attribute_names.each_with_index { |name, idx| attributes[name] = arguments[idx] }
1026 attributes
1027 end
1028
1029 def all_attributes_exists?(attribute_names)
1030 attribute_names.all? { |name| column_methods_hash.include?(name.to_sym) }
1031 end
1032
5f77f64 David Heinemeier Hansson Added option for passing an array to the find_all version of the dynamic...
dhh authored
1033 def attribute_condition(argument)
1034 case argument
1035 when nil then "IS ?"
1036 when Array then "IN (?)"
1037 else "= ?"
1038 end
1039 end
1040
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
1041 # Defines an "attribute" method (like #inheritance_column or
1042 # #table_name). A new (class) method will be created with the
1043 # given name. If a value is specified, the new method will
1044 # return that value (as a string). Otherwise, the given block
1045 # will be used to compute the value of the method.
1046 #
1047 # The original method will be aliased, with the new name being
1048 # prefixed with "original_". This allows the new method to
1049 # access the original value.
1050 #
1051 # Example:
1052 #
1053 # class A < ActiveRecord::Base
1054 # define_attr_method :primary_key, "sysid"
1055 # define_attr_method( :inheritance_column ) do
1056 # original_inheritance_column + "_id"
1057 # end
1058 # end
1059 def define_attr_method(name, value=nil, &block)
1060 sing = class << self; self; end
e2fc88e Jamis Buck Avoid memleak in dev mode with fastcgi
jamis authored
1061 sing.send :alias_method, "original_#{name}", name
7c8f3ed Jeremy Kemper r4325@asus: jeremy | 2005-11-12 03:57:46 -0800
jeremy authored
1062 if block_given?
1063 sing.send :define_method, name, &block
1064 else
e2fc88e Jamis Buck Avoid memleak in dev mode with fastcgi
jamis authored
1065 # use eval instead of a block to work around a memory leak in dev
1066 # mode in fcgi
1067 sing.class_eval "def #{name}; #{value.to_s.inspect}; end"
1068 end
4eab375 David Heinemeier Hansson Finished polishing API docs
dhh authored
1069 end
1070
db045db David Heinemeier Hansson Initial
dhh authored
1071 protected
1072 def subclasses
1073 @@subclasses[self] ||= []
1074 @@subclasses[self] + extra = @@subclasses[self].inject([]) {|list, subclass| list + subclass.subclasses }
1075 end
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
1076
1077 # Test whether the given method and optional key are scoped.
1078 def scoped?(method, key = nil)
1079 scoped_methods and scoped_methods.has_key?(method) and (key.nil? or scope(method).has_key?(key))
1080 end
1081
1082 # Retrieve the scope for the given method and optional key.
1083 def scope(method, key = nil)
1084 if scoped_methods and scope = scoped_methods[method]
1085 key ? scope[key] : scope
1086 end
1087 end
1088
1089 def scoped_methods
b840e4e Deprecated ActiveRecord::Base.threaded_connection in favor of ActiveReco...
Marcel Molina authored
1090 if allow_concurrency
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
1091 Thread.current[:scoped_methods] ||= {}
1092 Thread.current[:scoped_methods][self] ||= nil
dcc2263 Speed up for unthreaded environments. Closes #2431.
Marcel Molina authored
1093 else
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
1094 @scoped_methods ||= nil
dcc2263 Speed up for unthreaded environments. Closes #2431.
Marcel Molina authored
1095 end
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
1096 end
f4d1af3 Fix typo of 'constrains' to 'contraints'. Closes #2069.
Marcel Molina authored
1097
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
1098 def scoped_methods=(value)
b840e4e Deprecated ActiveRecord::Base.threaded_connection in favor of ActiveReco...
Marcel Molina authored
1099 if allow_concurrency
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
1100 Thread.current[:scoped_methods] ||= {}
1101 Thread.current[:scoped_methods][self] = value
dcc2263 Speed up for unthreaded environments. Closes #2431.
Marcel Molina authored
1102 else
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
1103 @scoped_methods = value
dcc2263 Speed up for unthreaded environments. Closes #2431.
Marcel Molina authored
1104 end
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
1105 end
390e6d2 Jeremy Kemper r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
1106
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
1107 # Returns the class type of the record using the current module as a prefix. So descendents of
1108 # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
db045db David Heinemeier Hansson Initial
dhh authored
1109 def compute_type(type_name)
c7d6d68 Jeremy Kemper Reflections don't attempt to resolve module nesting of association class...
jeremy authored
1110 begin
1111 instance_eval(type_name_with_module(type_name))
1112 rescue Object
1113 instance_eval(type_name)
db045db David Heinemeier Hansson Initial
dhh authored
1114 end
1115 end
1116
d2f4750 Jamis Buck Add AR::Base.base_class for querying the ancestor AR::Base subclass [Jam...
jamis authored
1117 # Returns the class descending directly from ActiveRecord in the inheritance hierarchy.
1118 def class_of_active_record_descendant(klass)
db045db David Heinemeier Hansson Initial
dhh authored
1119 if klass.superclass == Base
d2f4750 Jamis Buck Add AR::Base.base_class for querying the ancestor AR::Base subclass [Jam...
jamis authored
1120 klass
db045db David Heinemeier Hansson Initial
dhh authored
1121 elsif klass.superclass.nil?
1122 raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
1123 else
d2f4750 Jamis Buck Add AR::Base.base_class for querying the ancestor AR::Base subclass [Jam...
jamis authored
1124 class_of_active_record_descendant(klass.superclass)
db045db David Heinemeier Hansson Initial
dhh authored
1125 end
1126 end
1127
d2f4750 Jamis Buck Add AR::Base.base_class for querying the ancestor AR::Base subclass [Jam...
jamis authored
1128 # Returns the name of the class descending directly from ActiveRecord in the inheritance hierarchy.
1129 def class_name_of_active_record_descendant(klass)
1130 class_of_active_record_descendant(klass).name
1131 end
1132
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
1133 # Accepts an array or string. The string is returned untouched, but the array has each value
1134 # sanitized and interpolated into the sql statement.
1135 # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
1136 def sanitize_sql(ary)
1137 return ary unless ary.is_a?(Array)
3e7d191 David Heinemeier Hansson Added bind-style variable interpolation for the condition arrays that us...
dhh authored
1138
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
1139 statement, *values = ary
1140 if values.first.is_a?(Hash) and statement =~ /:\w+/
1141 replace_named_bind_variables(statement, values.first)
1142 elsif statement.include?('?')
554597d David Heinemeier Hansson Added named bind-style variable interpolation #281 [Michael Koziarski]
dhh authored
1143 replace_bind_variables(statement, values)
1144 else
4940383 David Heinemeier Hansson Fixed value quoting in all generated SQL statements, so that integers ar...
dhh authored
1145 statement % values.collect { |value| connection.quote_string(value.to_s) }
554597d David Heinemeier Hansson Added named bind-style variable interpolation #281 [Michael Koziarski]
dhh authored
1146 end
3e7d191 David Heinemeier Hansson Added bind-style variable interpolation for the condition arrays that us...
dhh authored
1147 end
1148
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
1149 alias_method :sanitize_conditions, :sanitize_sql
1150
3e7d191 David Heinemeier Hansson Added bind-style variable interpolation for the condition arrays that us...
dhh authored
1151 def replace_bind_variables(statement, values)
9322168 David Heinemeier Hansson Restored bind arity checking #412 [bitsweat]
dhh authored
1152 raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
1153 bound = values.dup
872ddaf David Heinemeier Hansson Added bind-named arrays for interpolating a group of ids or strings in c...
dhh authored
1154 statement.gsub('?') { quote_bound_value(bound.shift) }
554597d David Heinemeier Hansson Added named bind-style variable interpolation #281 [Michael Koziarski]
dhh authored
1155 end
1156
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
1157 def replace_named_bind_variables(statement, bind_vars)
1158 statement.gsub(/:(\w+)/) do
1159 match = $1.to_sym
81737fc Jeremy Kemper r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
1160 if bind_vars.include?(match)
872ddaf David Heinemeier Hansson Added bind-named arrays for interpolating a group of ids or strings in c...
dhh authored
1161 quote_bound_value(bind_vars[match])
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
1162 else
1163 raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
554597d David Heinemeier Hansson Added named bind-style variable interpolation #281 [Michael Koziarski]
dhh authored
1164 end
1165 end
9322168 David Heinemeier Hansson Restored bind arity checking #412 [bitsweat]
dhh authored
1166 end
1167
872ddaf David Heinemeier Hansson Added bind-named arrays for interpolating a group of ids or strings in c...
dhh authored
1168 def quote_bound_value(value)
c2ed453 David Heinemeier Hansson Fix quote_bound_value to not map Strings #1416 [htonl]
dhh authored
1169 if (value.respond_to?(:map) && !value.is_a?(String))
1170 value.map { |v| connection.quote(v) }.join(',')
1171 else
1172 connection.quote(value)
872ddaf David Heinemeier Hansson Added bind-named arrays for interpolating a group of ids or strings in c...
dhh authored
1173 end
1174 end
1175
9322168 David Heinemeier Hansson Restored bind arity checking #412 [bitsweat]
dhh authored
1176 def raise_if_bind_arity_mismatch(statement, expected, provided)
1177 unless expected == provided
1178 raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}"
1179 end
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
1180 end
554597d David Heinemeier Hansson Added named bind-style variable interpolation #281 [Michael Koziarski]
dhh authored
1181
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
1182 def extract_options_from_args!(args)
e8b427c Raise an exception when invalid options are passed to ActiveRecord::Base...
Marcel Molina authored
1183 options = args.last.is_a?(Hash) ? args.pop : {}
1184 validate_find_options(options)
1185 options
1186 end
64fcb75 Jeremy Kemper r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
1187
e8b427c Raise an exception when invalid options are passed to ActiveRecord::Base...
Marcel Molina authored
1188 def validate_find_options(options)
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
1189 options.assert_valid_keys [:conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :group, :from]
db045db David Heinemeier Hansson Initial
dhh authored
1190 end
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
1191
aaf9a45 David Heinemeier Hansson Added Base.validate_uniqueness thatv alidates whether the value of the s...
dhh authored
1192 def encode_quoted_value(value)
1193 quoted_value = connection.quote(value)
3ab3a70 Jeremy Kemper Clarify semantics of ActiveRecord::Base#respond_to? Closes #2560.
jeremy authored
1194 quoted_value = "'#{quoted_value[1..-2].gsub(/\'/, "\\\\'")}'" if quoted_value.include?("\\\'") # (for ruby mode) "
1195 quoted_value
aaf9a45 David Heinemeier Hansson Added Base.validate_uniqueness thatv alidates whether the value of the s...
dhh authored
1196 end
db045db David Heinemeier Hansson Initial
dhh authored
1197 end
1198
1199 public
1200 # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
1201 # attributes but not yet saved (pass a hash with key names matching the associated table column names).
6e39c9e Jeremy Kemper r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
1202 # In both instances, valid attribute keys are determined by the column names of the associated table --
db045db David Heinemeier Hansson Initial
dhh authored
1203 # hence you can't have attributes that aren't part of the table columns.
1204 def initialize(attributes = nil)
1205 @attributes = attributes_from_column_definition
1206 @new_record = true
1207 ensure_proper_type
1208 self.attributes = attributes unless attributes.nil?
1209 yield self if block_given?
1210 end
6e39c9e Jeremy Kemper