Skip to content
Newer
Older
100755 2298 lines (2034 sloc) 99 KB
48052d7 @jeremy to_xml fixes, features, and speedup. Closes #4989.
jeremy authored
1 require 'base64'
db045db @dhh Initial
dhh authored
2 require 'yaml'
aabf909 @jeremy Correct reader method generation for primary key attribute: handle ca…
jeremy authored
3 require 'set'
abc895b @dhh Added new Base.find API and deprecated find_all, find_first. Added pr…
dhh authored
4 require 'active_record/deprecated_finders'
db045db @dhh Initial
dhh authored
5
6 module ActiveRecord #:nodoc:
7 class ActiveRecordError < StandardError #:nodoc:
8 end
605bc77 @dhh Added a better exception for when a type column is used in a table wi…
dhh authored
9 class SubclassNotFound < ActiveRecordError #:nodoc:
10 end
db045db @dhh Initial
dhh authored
11 class AssociationTypeMismatch < ActiveRecordError #:nodoc:
12 end
13 class SerializationTypeMismatch < ActiveRecordError #:nodoc:
14 end
15 class AdapterNotSpecified < ActiveRecordError # :nodoc:
16 end
17 class AdapterNotFound < ActiveRecordError # :nodoc:
18 end
19 class ConnectionNotEstablished < ActiveRecordError #:nodoc:
20 end
21 class ConnectionFailed < ActiveRecordError #:nodoc:
22 end
23 class RecordNotFound < ActiveRecordError #:nodoc:
24 end
4c7555a @dhh Fixed that Base.save should always return false if the save didn't su…
dhh authored
25 class RecordNotSaved < ActiveRecordError #:nodoc:
26 end
db045db @dhh Initial
dhh authored
27 class StatementInvalid < ActiveRecordError #:nodoc:
28 end
554597d @dhh Added named bind-style variable interpolation #281 [Michael Koziarski]
dhh authored
29 class PreparedStatementInvalid < ActiveRecordError #:nodoc:
30 end
fbf9281 @dhh Added automated optimistic locking if the field lock_version is present
dhh authored
31 class StaleObjectError < ActiveRecordError #:nodoc:
32 end
5b9b904 @dhh Added support for limit and offset with eager loading of has_one and …
dhh authored
33 class ConfigurationError < StandardError #:nodoc:
34 end
64fcb75 @jeremy r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
35 class ReadOnlyRecord < StandardError #:nodoc:
36 end
ebbe4fb @NZKoz Replace the transaction {|transaction|..} semantics with a new Except…
NZKoz authored
37 class Rollback < StandardError #:nodoc:
38 end
e48b062 @jeremy Sanitize Base#inspect. Closes #8392.
jeremy authored
39
d2fefbe @dhh Added MultiparameterAssignmentErrors and AttributeAssignmentError exc…
dhh authored
40 class AttributeAssignmentError < ActiveRecordError #:nodoc:
41 attr_reader :exception, :attribute
42 def initialize(message, exception, attribute)
43 @exception = exception
44 @attribute = attribute
45 @message = message
46 end
47 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
48
d2fefbe @dhh Added MultiparameterAssignmentErrors and AttributeAssignmentError exc…
dhh authored
49 class MultiparameterAssignmentErrors < ActiveRecordError #:nodoc:
50 attr_reader :errors
51 def initialize(errors)
52 @errors = errors
53 end
54 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
55
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
56 # Active Record objects don't specify their attributes directly, but rather infer them from the table definition with
db045db @dhh Initial
dhh authored
57 # which they're linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change
58 # is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
59 # database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.
60 #
db045db @dhh Initial
dhh authored
61 # See the mapping rules in table_name and the full example in link:files/README.html for more insight.
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
62 #
db045db @dhh Initial
dhh authored
63 # == Creation
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
64 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
65 # Active Records accept constructor parameters either in a hash or as a block. The hash method is especially useful when
db045db @dhh Initial
dhh authored
66 # you're receiving the data from somewhere else, like a HTTP request. It works like this:
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
67 #
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
68 # user = User.new(:name => "David", :occupation => "Code Artist")
db045db @dhh Initial
dhh authored
69 # user.name # => "David"
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
70 #
db045db @dhh Initial
dhh authored
71 # You can also use block initialization:
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
72 #
db045db @dhh Initial
dhh authored
73 # user = User.new do |u|
74 # u.name = "David"
75 # u.occupation = "Code Artist"
76 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
77 #
db045db @dhh Initial
dhh authored
78 # And of course you can just create a bare object and specify the attributes after the fact:
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
79 #
db045db @dhh Initial
dhh authored
80 # user = User.new
81 # user.name = "David"
82 # user.occupation = "Code Artist"
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
83 #
db045db @dhh Initial
dhh authored
84 # == Conditions
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
85 #
c5ec16e @dhh Added simple hash conditions to find that'll just convert hash to an …
dhh authored
86 # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement.
db045db @dhh Initial
dhh authored
87 # The array form is to be used when the condition input is tainted and requires sanitization. The string form can
c5ec16e @dhh Added simple hash conditions to find that'll just convert hash to an …
dhh authored
88 # be used for statements that don't involve tainted data. The hash form works much like the array form, except
2876707 @jeremy Pass a range in :conditions to use the SQL BETWEEN operator. Closes #…
jeremy authored
89 # only equality and range is possible. Examples:
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
90 #
48052d7 @jeremy to_xml fixes, features, and speedup. Closes #4989.
jeremy authored
91 # class User < ActiveRecord::Base
db045db @dhh Initial
dhh authored
92 # def self.authenticate_unsafely(user_name, password)
3dfa56c @dhh Updated all references to the old find_first and find_all to use the …
dhh authored
93 # find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'")
db045db @dhh Initial
dhh authored
94 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
95 #
db045db @dhh Initial
dhh authored
96 # def self.authenticate_safely(user_name, password)
3dfa56c @dhh Updated all references to the old find_first and find_all to use the …
dhh authored
97 # find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ])
db045db @dhh Initial
dhh authored
98 # end
c5ec16e @dhh Added simple hash conditions to find that'll just convert hash to an …
dhh authored
99 #
100 # def self.authenticate_safely_simply(user_name, password)
101 # find(:first, :conditions => { :user_name => user_name, :password => password })
102 # end
db045db @dhh Initial
dhh authored
103 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
104 #
2575b3b @dhh Added extra words of caution for guarding against SQL-injection attacks
dhh authored
105 # The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query and is thus susceptible to SQL-injection
c5ec16e @dhh Added simple hash conditions to find that'll just convert hash to an …
dhh authored
106 # attacks if the <tt>user_name</tt> and +password+ parameters come directly from a HTTP request. The <tt>authenticate_safely</tt> and
107 # <tt>authenticate_safely_simply</tt> both will sanitize the <tt>user_name</tt> and +password+ before inserting them in the query,
108 # which will ensure that an attacker can't escape the query and fake the login (or worse).
2575b3b @dhh Added extra words of caution for guarding against SQL-injection attacks
dhh authored
109 #
5cd38ca @dhh Added documentation about named bind variables
dhh authored
110 # When using multiple parameters in the conditions, it can easily become hard to read exactly what the fourth or fifth
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
111 # question mark is supposed to represent. In those cases, you can resort to named bind variables instead. That's done by replacing
5cd38ca @dhh Added documentation about named bind variables
dhh authored
112 # the question marks with symbols and supplying a hash with values for the matching symbol keys:
113 #
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
114 # Company.find(:first, [
115 # "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
5cd38ca @dhh Added documentation about named bind variables
dhh authored
116 # { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' }
117 # ])
118 #
c5ec16e @dhh Added simple hash conditions to find that'll just convert hash to an …
dhh authored
119 # Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND
120 # operator. For instance:
121 #
122 # Student.find(:all, :conditions => { :first_name => "Harvey", :status => 1 })
123 # Student.find(:all, :conditions => params[:student])
124 #
2876707 @jeremy Pass a range in :conditions to use the SQL BETWEEN operator. Closes #…
jeremy authored
125 # A range may be used in the hash to use the SQL BETWEEN operator:
126 #
127 # Student.find(:all, :conditions => { :grade => 9..12 })
c5ec16e @dhh Added simple hash conditions to find that'll just convert hash to an …
dhh authored
128 #
db045db @dhh Initial
dhh authored
129 # == Overwriting default accessors
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
130 #
db045db @dhh Initial
dhh authored
131 # All column values are automatically available through basic accessors on the Active Record object, but some times you
132 # want to specialize this behavior. This can be done by either by overwriting the default accessors (using the same
133 # name as the attribute) calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things.
134 # Example:
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
135 #
db045db @dhh Initial
dhh authored
136 # class Song < ActiveRecord::Base
137 # # Uses an integer of seconds to hold the length of the song
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
138 #
db045db @dhh Initial
dhh authored
139 # def length=(minutes)
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
140 # write_attribute(:length, minutes * 60)
db045db @dhh Initial
dhh authored
141 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
142 #
db045db @dhh Initial
dhh authored
143 # def length
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
144 # read_attribute(:length) / 60
db045db @dhh Initial
dhh authored
145 # end
146 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
147 #
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
148 # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, vaule) and
149 # read_attribute(:attribute) as a shorter form.
150 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
151 # == Accessing attributes before they have been typecasted
4eab375 @dhh Finished polishing API docs
dhh authored
152 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
153 # Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first.
4eab375 @dhh Finished polishing API docs
dhh authored
154 # That can be done by using the <attribute>_before_type_cast accessors that all attributes have. For example, if your Account model
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
155 # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast.
4eab375 @dhh Finished polishing API docs
dhh authored
156 #
157 # 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
158 # the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you
4eab375 @dhh Finished polishing API docs
dhh authored
159 # want.
160 #
ac8fd7d @dhh Added dynamic attribute-based finders as a cleaner way of getting obj…
dhh authored
161 # == Dynamic attribute-based finders
162 #
a5a82d9 @dhh Added extension capabilities to has_many and has_and_belongs_to_many …
dhh authored
163 # 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 @dhh Fixed Base#find to honor the documentation on how :joins work and mak…
dhh authored
164 # 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 r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
165 # Person.find_all_by_last_name, Payment.find_by_transaction_id. So instead of writing
166 # <tt>Person.find(:first, ["user_name = ?", user_name])</tt>, you just do <tt>Person.find_by_user_name(user_name)</tt>.
302c23d @dhh Fixed Base#find to honor the documentation on how :joins work and mak…
dhh authored
167 # 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 r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
168 #
ac8fd7d @dhh Added dynamic attribute-based finders as a cleaner way of getting obj…
dhh authored
169 # It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders like
170 # <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 r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
171 # <tt>Person.find(:first, ["user_name = ? AND password = ?", user_name, password])</tt>, you just do
ac8fd7d @dhh Added dynamic attribute-based finders as a cleaner way of getting obj…
dhh authored
172 # <tt>Person.find_by_user_name_and_password(user_name, password)</tt>.
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
173 #
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
174 # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount
175 # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is
176 # 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 @dhh Added find_all style to the new dynamic finders
dhh authored
177 #
a5a82d9 @dhh Added extension capabilities to has_many and has_and_belongs_to_many …
dhh authored
178 # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with
179 # <tt>find_or_create_by_</tt> and will return the object if it already exists and otherwise creates it, then returns it. Example:
180 #
181 # # No 'Summer' tag exists
182 # Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")
183 #
184 # # Now the 'Summer' tag does exist
185 # Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
186 #
d19e464 @sstephenson Added find_or_initialize_by_X which works like find_or_create_by_X bu…
sstephenson authored
187 # Use the <tt>find_or_initialize_by_</tt> finder if you want to return a new record without saving it first. Example:
188 #
189 # # No 'Winter' tag exists
190 # winter = Tag.find_or_initialize_by_name("Winter")
85fbb22 @dhh Backed out of new_record? to new? transformation as it would screw up…
dhh authored
191 # winter.new_record? # true
d19e464 @sstephenson Added find_or_initialize_by_X which works like find_or_create_by_X bu…
sstephenson authored
192 #
14cc8d2 @jeremy find_or_create_by_* takes a hash so you can create with more attribut…
jeremy authored
193 # To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of
194 # a list of parameters. For example:
195 #
196 # Tag.find_or_create_by_name(:name => "rails", :creator => current_user)
197 #
198 # That will either find an existing tag named "rails", or create a new one while setting the user that created it.
199 #
098fa94 @dhh Fixed documentation snafus #575, #576, #577, #585
dhh authored
200 # == Saving arrays, hashes, and other non-mappable objects in text columns
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
201 #
202 # 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
203 # This makes it possible to store arrays, hashes, and other non-mappable objects without doing any additional work. Example:
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
204 #
db045db @dhh Initial
dhh authored
205 # class User < ActiveRecord::Base
206 # serialize :preferences
207 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
208 #
ca2eb16 Fix syntax error in documentation. Closes #4679. [mislav@nippur.irb.hr]
Marcel Molina authored
209 # user = User.create(:preferences => { "background" => "black", "display" => large })
db045db @dhh Initial
dhh authored
210 # User.find(user.id).preferences # => { "background" => "black", "display" => large }
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
211 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
212 # 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 @dhh Initial
dhh authored
213 # descendent of a class not in the hierarchy. Example:
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
214 #
db045db @dhh Initial
dhh authored
215 # class User < ActiveRecord::Base
66f44e6 @dhh Updated documentation for serialize
dhh authored
216 # serialize :preferences, Hash
db045db @dhh Initial
dhh authored
217 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
218 #
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
219 # user = User.create(:preferences => %w( one two three ))
db045db @dhh Initial
dhh authored
220 # User.find(user.id).preferences # raises SerializationTypeMismatch
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
221 #
db045db @dhh Initial
dhh authored
222 # == Single table inheritance
223 #
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
224 # Active Record allows inheritance by storing the name of the class in a column that by default is called "type" (can be changed
db045db @dhh Initial
dhh authored
225 # by overwriting <tt>Base.inheritance_column</tt>). This means that an inheritance looking like this:
226 #
227 # class Company < ActiveRecord::Base; end
228 # class Firm < Company; end
229 # class Client < Company; end
230 # class PriorityClient < Client; end
231 #
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
232 # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then
233 # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object.
db045db @dhh Initial
dhh authored
234 #
f033833 @dhh Improving documentation...
dhh authored
235 # 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
236 # like normal subclasses with no special magic for differentiating between them or reloading the right type with find.
237 #
db045db @dhh Initial
dhh authored
238 # Note, all the attributes for all the cases are kept in the same table. Read more:
239 # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
240 #
db045db @dhh Initial
dhh authored
241 # == Connection to multiple databases in different models
242 #
243 # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection.
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
244 # All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection.
db045db @dhh Initial
dhh authored
245 # For example, if Course is a ActiveRecord::Base, but resides in a different database you can just say Course.establish_connection
246 # and Course *and all its subclasses* will use this connection instead.
247 #
248 # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is
249 # requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool.
250 #
251 # == Exceptions
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
252 #
db045db @dhh Initial
dhh authored
253 # * +ActiveRecordError+ -- generic error class and superclass of all other errors raised by Active Record
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
254 # * +AdapterNotSpecified+ -- the configuration hash used in <tt>establish_connection</tt> didn't include a
db045db @dhh Initial
dhh authored
255 # <tt>:adapter</tt> key.
1aab0e2 @dhh Doc fixes #1775, #1776 [jon@instance-design.co.uk]
dhh authored
256 # * +AdapterNotFound+ -- the <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified an non-existent adapter
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
257 # (or a bad spelling of an existing one).
258 # * +AssociationTypeMismatch+ -- the object assigned to the association wasn't of the type specified in the association definition.
259 # * +SerializationTypeMismatch+ -- the object serialized wasn't of the class specified as the second parameter.
db045db @dhh Initial
dhh authored
260 # * +ConnectionNotEstablished+ -- no connection has been established. Use <tt>establish_connection</tt> before querying.
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
261 # * +RecordNotFound+ -- no record responded to the find* method.
db045db @dhh Initial
dhh authored
262 # Either the row with the given ID doesn't exist or the row didn't meet the additional restrictions.
263 # * +StatementInvalid+ -- the database server rejected the SQL statement. The precise error is added in the message.
264 # Either the record with the given ID doesn't exist or the record didn't meet the additional restrictions.
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
265 # * +MultiparameterAssignmentErrors+ -- collection of errors that occurred during a mass assignment using the
266 # +attributes=+ method. The +errors+ property of this exception contains an array of +AttributeAssignmentError+
d2fefbe @dhh Added MultiparameterAssignmentErrors and AttributeAssignmentError exc…
dhh authored
267 # objects that should be inspected to determine which attributes triggered the errors.
268 # * +AttributeAssignmentError+ -- an error occurred while doing a mass assignment through the +attributes=+ method.
269 # You can inspect the +attribute+ property of the exception object to determine which attribute triggered the error.
5707027 @dhh Added better exception error when unknown column types are used with …
dhh authored
270 #
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
271 # *Note*: The attributes listed are class-level attributes (accessible from both the class and instance level).
db045db @dhh Initial
dhh authored
272 # So it's possible to assign a logger to the class through Base.logger= which will then be used by all
273 # instances in the current object space.
274 class Base
275 # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then passed
276 # on to any new database connections made and which can be retrieved on both a class and instance level by calling +logger+.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7401
technoweenie authored
277 cattr_accessor :logger, :instance_writer => false
1bce58b @seckar Add Reloadable::OnlySubclasses which handles the common case where a …
seckar authored
278
74165eb @seckar New dependencies implementation
seckar authored
279 include Reloadable::Deprecated
1bce58b @seckar Add Reloadable::OnlySubclasses which handles the common case where a …
seckar authored
280
db045db @dhh Initial
dhh authored
281 def self.inherited(child) #:nodoc:
282 @@subclasses[self] ||= []
283 @@subclasses[self] << child
284 super
285 end
bfbf6bb @jamis Allow ARStore::Session to indicate that it should not be reloaded in …
jamis authored
286
fed7d33 @dhh Fixed documentation
dhh authored
287 def self.reset_subclasses #:nodoc:
bfbf6bb @jamis Allow ARStore::Session to indicate that it should not be reloaded in …
jamis authored
288 nonreloadables = []
e7f61ea @jamis squash the memleak in dev mode finally (fingers crossed, here)
jamis authored
289 subclasses.each do |klass|
74165eb @seckar New dependencies implementation
seckar authored
290 unless Dependencies.autoloaded? klass
bfbf6bb @jamis Allow ARStore::Session to indicate that it should not be reloaded in …
jamis authored
291 nonreloadables << klass
292 next
293 end
e7f61ea @jamis squash the memleak in dev mode finally (fingers crossed, here)
jamis authored
294 klass.instance_variables.each { |var| klass.send(:remove_instance_variable, var) }
295 klass.instance_methods(false).each { |m| klass.send :undef_method, m }
296 end
bfbf6bb @jamis Allow ARStore::Session to indicate that it should not be reloaded in …
jamis authored
297 @@subclasses = {}
298 nonreloadables.each { |klass| (@@subclasses[klass.superclass] ||= []) << klass }
3c0129a @dhh Fixed memory leak with Active Record classes when Dependencies.mechan…
dhh authored
299 end
300
db045db @dhh Initial
dhh authored
301 @@subclasses = {}
c4a3634 @jeremy Corrected @@configurations typo. #1410 [david@ruppconsulting.com]
jeremy authored
302
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7401
technoweenie authored
303 cattr_accessor :configurations, :instance_writer => false
c4a3634 @jeremy Corrected @@configurations typo. #1410 [david@ruppconsulting.com]
jeremy authored
304 @@configurations = {}
305
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
306 # Accessor for the prefix type that will be prepended to every primary key column name. The options are :table_name and
db045db @dhh Initial
dhh authored
307 # :table_name_with_underscore. If the first is specified, the Product class will look for "productid" instead of "id" as
308 # the primary column. If the latter is specified, the Product class will look for "product_id" instead of "id". Remember
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
309 # that this is a global setting for all Active Records.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7401
technoweenie authored
310 cattr_accessor :primary_key_prefix_type, :instance_writer => false
db045db @dhh Initial
dhh authored
311 @@primary_key_prefix_type = nil
312
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
313 # Accessor for the name of the prefix string to prepend to every table name. So if set to "basecamp_", all
098fa94 @dhh Fixed documentation snafus #575, #576, #577, #585
dhh authored
314 # table names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient way of creating a namespace
db045db @dhh Initial
dhh authored
315 # for tables in a shared database. By default, the prefix is the empty string.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7401
technoweenie authored
316 cattr_accessor :table_name_prefix, :instance_writer => false
db045db @dhh Initial
dhh authored
317 @@table_name_prefix = ""
318
319 # Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
320 # "people_basecamp"). By default, the suffix is the empty string.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7401
technoweenie authored
321 cattr_accessor :table_name_suffix, :instance_writer => false
db045db @dhh Initial
dhh authored
322 @@table_name_suffix = ""
323
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
324 # Indicates whether or not table names should be the pluralized versions of the corresponding class names.
325 # If true, the default table name for a +Product+ class will be +products+. If false, it would just be +product+.
db045db @dhh Initial
dhh authored
326 # See table_name for the full rules on table/class naming. This is true, by default.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7401
technoweenie authored
327 cattr_accessor :pluralize_table_names, :instance_writer => false
db045db @dhh Initial
dhh authored
328 @@pluralize_table_names = true
329
911614d @dhh Added ActiveRecord::Base.colorize_logging to control whether to use c…
dhh authored
330 # 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
331 # make it much easier to overview things during debugging (when used through a reader like +tail+ and on a black background), but
911614d @dhh Added ActiveRecord::Base.colorize_logging to control whether to use c…
dhh authored
332 # may complicate matters if you use software like syslog. This is true, by default.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7401
technoweenie authored
333 cattr_accessor :colorize_logging, :instance_writer => false
911614d @dhh Added ActiveRecord::Base.colorize_logging to control whether to use c…
dhh authored
334 @@colorize_logging = true
335
60de8c1 @dhh Added Base.default_timezone accessor that determines whether to use T…
dhh authored
336 # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling dates and times from the database.
337 # This is set to :local by default.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7401
technoweenie authored
338 cattr_accessor :default_timezone, :instance_writer => false
60de8c1 @dhh Added Base.default_timezone accessor that determines whether to use T…
dhh authored
339 @@default_timezone = :local
d8641ca @jeremy CHANGED DEFAULT: set ActiveRecord::Base.allow_concurrency to false. M…
jeremy authored
340
6049977 @dhh Fixed that each request with the WEBrick adapter would open a new dat…
dhh authored
341 # Determines whether or not to use a connection for each thread, or a single shared connection for all threads.
d8641ca @jeremy CHANGED DEFAULT: set ActiveRecord::Base.allow_concurrency to false. M…
jeremy authored
342 # Defaults to false. Set to true if you're writing a threaded application.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7401
technoweenie authored
343 cattr_accessor :allow_concurrency, :instance_writer => false
25fb2db @jeremy Dynamically set allow_concurrency. Closes #4044.
jeremy authored
344 @@allow_concurrency = false
d8641ca @jeremy CHANGED DEFAULT: set ActiveRecord::Base.allow_concurrency to false. M…
jeremy authored
345
f218771 Add option (true by default) to generate reader methods for each attr…
Marcel Molina authored
346 # Determines whether to speed up access by generating optimized reader
347 # methods to avoid expensive calls to method_missing when accessing
348 # attributes by name. You might want to set this to false in development
349 # mode, because the methods would be regenerated on each request.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7401
technoweenie authored
350 cattr_accessor :generate_read_methods, :instance_writer => false
f218771 Add option (true by default) to generate reader methods for each attr…
Marcel Molina authored
351 @@generate_read_methods = true
24c3599 @sstephenson Support using different database adapters for development and test wi…
sstephenson authored
352
353 # Specifies the format to use when dumping the database schema with Rails'
354 # Rakefile. If :sql, the schema is dumped as (potentially database-
355 # specific) SQL statements. If :ruby, the schema is dumped as an
356 # ActiveRecord::Schema file which can be loaded into any database that
357 # supports migrations. Use :ruby if you want to have different database
358 # adapters for, e.g., your development and test environments.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7401
technoweenie authored
359 cattr_accessor :schema_format , :instance_writer => false
660952e @dhh CHANGED DEFAULT: ActiveRecord::Base.schema_format is now :ruby by def…
dhh authored
360 @@schema_format = :ruby
f218771 Add option (true by default) to generate reader methods for each attr…
Marcel Molina authored
361
db045db @dhh Initial
dhh authored
362 class << self # Class methods
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
363 # Find operates with three different retrieval approaches:
7669011 @dhh Fixes for postgresql testing #1129, #1130, #1131
dhh authored
364 #
365 # * 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]).
366 # If no record can be found for all of the listed ids, then RecordNotFound will be raised.
367 # * Find first: This will return the first record matched by the options used. These options can either be specific
368 # conditions or merely an order. If no record can matched, nil is returned.
7d01005 @dhh Fixed documentation and prepared for release of 0.12
dhh authored
369 # * Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned.
7669011 @dhh Fixes for postgresql testing #1129, #1130, #1131
dhh authored
370 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
371 # All approaches accept an option hash as their last parameter. The options are:
7669011 @dhh Fixes for postgresql testing #1129, #1130, #1131
dhh authored
372 #
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
373 # * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
374 # * <tt>:order</tt>: An SQL fragment like "created_at DESC, name".
3309268 @jeremy Add :group option, correspond to GROUP BY, to the find method and to …
jeremy authored
375 # * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
376 # * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned.
377 # * <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.
378 # * <tt>:joins</tt>: An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". (Rarely needed).
64fcb75 @jeremy r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
379 # The records will be returned read-only since they will have attributes that do not correspond to the table's columns.
7219e82 @jeremy HABTM finder sets :readonly => false. Closes #2525.
jeremy authored
380 # Pass :readonly => false to override.
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
381 # * <tt>:include</tt>: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer
382 # to already defined associations. See eager loading under Associations.
6f05696 @dhh Added :select option to find which can specify a different value than…
dhh authored
383 # * <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
384 # include the joined columns.
d3cf2a6 Document find's :from option. Closes #5762. [andrew@redlinesoftware.com]
Marcel Molina authored
385 # * <tt>:from</tt>: By default, this is the table name of the class, but can be changed to an alternate table name (or even the name
386 # of a database view).
64fcb75 @jeremy r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
387 # * <tt>:readonly</tt>: Mark the returned records read-only so they cannot be saved or updated.
15aa6e0 @jeremy r4644@asus: jeremy | 2006-06-16 14:57:03 -0700
jeremy authored
388 # * <tt>:lock</tt>: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE".
389 # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE".
7669011 @dhh Fixes for postgresql testing #1129, #1130, #1131
dhh authored
390 #
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
391 # Examples for find by id:
db045db @dhh Initial
dhh authored
392 # Person.find(1) # returns the object for ID = 1
393 # Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
394 # Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
57ed93e @dhh Fixed that Base#find will return an array if given an array -- regard…
dhh authored
395 # Person.find([1]) # returns an array for objects the object with ID = 1
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
396 # Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC")
397 #
1e9e198 @jeremy Note that find results may not be in the same order as the id argumen…
jeremy authored
398 # Note that returned records may not be in the same order as the ids you
399 # provide since database rows are unordered. Give an explicit :order
400 # to ensure the results are sorted.
401 #
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
402 # Examples for find first:
7d01005 @dhh Fixed documentation and prepared for release of 0.12
dhh authored
403 # Person.find(:first) # returns the first object fetched by SELECT * FROM people
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
404 # Person.find(:first, :conditions => [ "user_name = ?", user_name])
405 # Person.find(:first, :order => "created_on DESC", :offset => 5)
406 #
407 # Examples for find all:
7d01005 @dhh Fixed documentation and prepared for release of 0.12
dhh authored
408 # Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
409 # Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50)
410 # Person.find(:all, :offset => 10, :limit => 10)
411 # Person.find(:all, :include => [ :account, :friends ])
3309268 @jeremy Add :group option, correspond to GROUP BY, to the find method and to …
jeremy authored
412 # Person.find(:all, :group => "category")
15aa6e0 @jeremy r4644@asus: jeremy | 2006-06-16 14:57:03 -0700
jeremy authored
413 #
414 # Example for find with a lock. Imagine two concurrent transactions:
415 # each will read person.visits == 2, add 1 to it, and save, resulting
416 # in two saves of person.visits = 3. By locking the row, the second
417 # transaction has to wait until the first is finished; we get the
418 # expected person.visits == 4.
419 # Person.transaction do
420 # person = Person.find(1, :lock => true)
421 # person.visits += 1
422 # person.save!
423 # end
6bd672e @dhh Added that Base#find takes an optional options hash, including :condi…
dhh authored
424 def find(*args)
425 options = extract_options_from_args!(args)
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
426 validate_find_options(options)
427 set_readonly_option!(options)
64fcb75 @jeremy r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
428
abc895b @dhh Added new Base.find API and deprecated find_all, find_first. Added pr…
dhh authored
429 case args.first
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
430 when :first then find_initial(options)
431 when :all then find_every(options)
432 else find_from_ids(args, options)
db045db @dhh Initial
dhh authored
433 end
434 end
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
435
3dfa56c @dhh Updated all references to the old find_first and find_all to use the …
dhh authored
436 # Works like find(:all), but requires a complete SQL string. Examples:
db045db @dhh Initial
dhh authored
437 # Post.find_by_sql "SELECT p.*, c.author FROM posts p, comments c WHERE p.id = c.post_id"
a775cb1 @dhh Added the option for sanitizing find_by_sql and the offset parts in r…
dhh authored
438 # Post.find_by_sql ["SELECT * FROM posts WHERE author = ? AND created > ?", author_id, start_date]
db045db @dhh Initial
dhh authored
439 def find_by_sql(sql)
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
440 connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) }
db045db @dhh Initial
dhh authored
441 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
442
abc895b @dhh Added new Base.find API and deprecated find_all, find_first. Added pr…
dhh authored
443 # Returns true if the given +id+ represents the primary key of a record in the database, false otherwise.
8085cbf @dhh Added support for conditions on Base.exists? (closes #5689) [josh@jos…
dhh authored
444 # You can also pass a set of SQL conditions.
abc895b @dhh Added new Base.find API and deprecated find_all, find_first. Added pr…
dhh authored
445 # Example:
446 # Person.exists?(5)
58ebf30 @jeremy The exists? class method should treat a string argument as an id rath…
jeremy authored
447 # Person.exists?('5')
8085cbf @dhh Added support for conditions on Base.exists? (closes #5689) [josh@jos…
dhh authored
448 # Person.exists?(:name => "David")
58ebf30 @jeremy The exists? class method should treat a string argument as an id rath…
jeremy authored
449 # Person.exists?(['name LIKE ?', "%#{query}%"])
450 def exists?(id_or_conditions)
451 !find(:first, :conditions => expand_id_conditions(id_or_conditions)).nil?
452 rescue ActiveRecord::ActiveRecordError
453 false
db045db @dhh Initial
dhh authored
454 end
abc895b @dhh Added new Base.find API and deprecated find_all, find_first. Added pr…
dhh authored
455
db045db @dhh Initial
dhh authored
456 # 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
457 # fails under validations, the unsaved object is still returned.
db045db @dhh Initial
dhh authored
458 def create(attributes = nil)
efa81da @dhh Added the option of supplying an array of ids and attributes to Base#…
dhh authored
459 if attributes.is_a?(Array)
460 attributes.collect { |attr| create(attr) }
461 else
462 object = new(attributes)
463 object.save
464 object
465 end
db045db @dhh Initial
dhh authored
466 end
467
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
468 # 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
469 # and returns it. If the save fails under validations, the unsaved object is still returned.
5e99422 @dhh Updated docs (closes #3799) [ruby@bobsilva.com]
dhh authored
470 #
471 # The arguments may also be given as arrays in which case the update method is called for each pair of +id+ and
472 # +attributes+ and an array of objects is returned.
473 #
474 # Example of updating one record:
475 # Person.update(15, {:user_name => 'Samuel', :group => 'expert'})
476 #
477 # Example of updating multiple records:
478 # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy"} }
479 # Person.update(people.keys, people.values)
db045db @dhh Initial
dhh authored
480 def update(id, attributes)
efa81da @dhh Added the option of supplying an array of ids and attributes to Base#…
dhh authored
481 if id.is_a?(Array)
482 idx = -1
483 id.collect { |id| idx += 1; update(id, attributes[idx]) }
484 else
485 object = find(id)
486 object.update_attributes(attributes)
487 object
488 end
db045db @dhh Initial
dhh authored
489 end
490
efa81da @dhh Added the option of supplying an array of ids and attributes to Base#…
dhh authored
491 # Deletes the record with the given +id+ without instantiating an object first. If an array of ids is provided, all of them
492 # are deleted.
648b8fd @dhh Added Base.destroy and Base.delete to remove records without holding …
dhh authored
493 def delete(id)
98165fd @jeremy Consistently quote primary key column names. Closes #7763.
jeremy authored
494 delete_all([ "#{connection.quote_column_name(primary_key)} IN (?)", id ])
648b8fd @dhh Added Base.destroy and Base.delete to remove records without holding …
dhh authored
495 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
496
648b8fd @dhh Added Base.destroy and Base.delete to remove records without holding …
dhh authored
497 # Destroys the record with the given +id+ by instantiating the object and calling #destroy (all the callbacks are the triggered).
efa81da @dhh Added the option of supplying an array of ids and attributes to Base#…
dhh authored
498 # If an array of ids is provided, all of them are destroyed.
648b8fd @dhh Added Base.destroy and Base.delete to remove records without holding …
dhh authored
499 def destroy(id)
efa81da @dhh Added the option of supplying an array of ids and attributes to Base#…
dhh authored
500 id.is_a?(Array) ? id.each { |id| destroy(id) } : find(id).destroy
648b8fd @dhh Added Base.destroy and Base.delete to remove records without holding …
dhh authored
501 end
502
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
503 # 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 @dhh Changed the interface on AbstractAdapter to require that adapters ret…
dhh authored
504 # A subset of the records can be selected by specifying +conditions+. Example:
db045db @dhh Initial
dhh authored
505 # Billing.update_all "category = 'authorized', approved = 1", "author = 'David'"
a38f28f @jeremy Base.update_all :order and :limit options. Useful for MySQL updates t…
jeremy authored
506 #
507 # Optional :order and :limit options may be given as the third parameter,
508 # but their behavior is database-specific.
509 def update_all(updates, conditions = nil, options = {})
5acea7f @jeremy update_all can take a Hash argument. sanitize_sql splits into two met…
jeremy authored
510 sql = "UPDATE #{table_name} SET #{sanitize_sql_for_assignment(updates)} "
a38f28f @jeremy Base.update_all :order and :limit options. Useful for MySQL updates t…
jeremy authored
511 scope = scope(:find)
512 add_conditions!(sql, conditions, scope)
513 add_order!(sql, options[:order], scope)
514 add_limit!(sql, options, scope)
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
515 connection.update(sql, "#{name} Update")
db045db @dhh Initial
dhh authored
516 end
0d2db8a @dhh Added Base.update_collection that can update an array of id/attribute…
dhh authored
517
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
518 # Destroys the objects for all the records that match the +condition+ by instantiating each object and calling
db045db @dhh Initial
dhh authored
519 # the destroy method. Example:
520 # Person.destroy_all "last_login < '2004-04-04'"
521 def destroy_all(conditions = nil)
3dfa56c @dhh Updated all references to the old find_first and find_all to use the …
dhh authored
522 find(:all, :conditions => conditions).each { |object| object.destroy }
db045db @dhh Initial
dhh authored
523 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
524
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
525 # Deletes all the records that match the +condition+ without instantiating the objects first (and hence not
db045db @dhh Initial
dhh authored
526 # calling the destroy method). Example:
090bfce @jeremy Correct documentation for Base.delete_all. References #1568.
jeremy authored
527 # Post.delete_all "person_id = 5 AND (category = 'Something' OR category = 'Else')"
db045db @dhh Initial
dhh authored
528 def delete_all(conditions = nil)
529 sql = "DELETE FROM #{table_name} "
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
530 add_conditions!(sql, conditions, scope(:find))
db045db @dhh Initial
dhh authored
531 connection.delete(sql, "#{name} Delete all")
532 end
533
534 # Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
ee614d6 Add documentation caveat about when to use count_by_sql. Closes #8090.…
Marcel Molina authored
535 # The use of this method should be restricted to complicated SQL queries that can't be executed
536 # using the ActiveRecord::Calculations class methods. Look into those before using this.
537 #
538 # ==== Options
539 #
540 # +sql+: An SQL statement which should return a count query from the database, see the example below
541 #
542 # ==== Examples
543 #
e17bf81 @jamis Fix typo in count_by_sql documentation #1969 [Alexey Verkhovsky]
jamis authored
544 # Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
db045db @dhh Initial
dhh authored
545 def count_by_sql(sql)
a775cb1 @dhh Added the option for sanitizing find_by_sql and the offset parts in r…
dhh authored
546 sql = sanitize_conditions(sql)
caaf40d @dhh Added AbstractAdapter#select_value and AbstractAdapter#select_values …
dhh authored
547 connection.select_value(sql, "#{name} Count").to_i
db045db @dhh Initial
dhh authored
548 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
549
8375237 @jamis Made increment_counter/decrement_counter play nicely with optimistic …
jamis authored
550 # A generic "counter updater" implementation, intended primarily to be
551 # used by increment_counter and decrement_counter, but which may also
552 # be useful on its own. It simply does a direct SQL update for the record
553 # with the given ID, altering the given hash of counters by the amount
554 # given by the corresponding value:
555 #
556 # Post.update_counters 5, :comment_count => -1, :action_count => 1
557 # # UPDATE posts
558 # # SET comment_count = comment_count - 1,
559 # # action_count = action_count + 1
560 # # WHERE id = 5
561 def update_counters(id, counters)
562 updates = counters.inject([]) { |list, (counter_name, increment)|
563 sign = increment < 0 ? "-" : "+"
98165fd @jeremy Consistently quote primary key column names. Closes #7763.
jeremy authored
564 list << "#{connection.quote_column_name(counter_name)} = #{connection.quote_column_name(counter_name)} #{sign} #{increment.abs}"
8375237 @jamis Made increment_counter/decrement_counter play nicely with optimistic …
jamis authored
565 }.join(", ")
98165fd @jeremy Consistently quote primary key column names. Closes #7763.
jeremy authored
566 update_all(updates, "#{connection.quote_column_name(primary_key)} = #{quote_value(id)}")
8375237 @jamis Made increment_counter/decrement_counter play nicely with optimistic …
jamis authored
567 end
568
15dc567 Also add documentation enhancements for increment_counter. Closes #8092
Marcel Molina authored
569 # Increment a number field by one, usually representing a count.
570 #
571 # This is used for caching aggregate values, so that they don't need to be computed every time.
572 # For example, a DiscussionBoard may cache post_count and comment_count otherwise every time the board is
573 # shown it would have to run a SQL query to find how many posts and comments there are.
574 #
575 # ==== Options
576 #
577 # +counter_name+ The name of the field that should be incremented
578 # +id+ The id of the object that should be incremented
579 #
580 # ==== Examples
581 #
582 # # Increment the post_count column for the record with an id of 5
583 # DiscussionBoard.increment_counter(:post_count, 5)
db045db @dhh Initial
dhh authored
584 def increment_counter(counter_name, id)
8375237 @jamis Made increment_counter/decrement_counter play nicely with optimistic …
jamis authored
585 update_counters(id, counter_name => 1)
db045db @dhh Initial
dhh authored
586 end
587
5bd3570 Enhance documentation for decrement_counter. Closes #8093. [fearoffish]
Marcel Molina authored
588 # Decrement a number field by one, usually representing a count.
589 #
590 # This works the same as increment_counter but reduces the column value by 1 instead of increasing it.
591 #
592 # ==== Options
593 #
594 # +counter_name+ The name of the field that should be decremented
595 # +id+ The id of the object that should be decremented
596 #
597 # ==== Examples
598 #
599 # # Decrement the post_count column for the record with an id of 5
600 # DiscussionBoard.decrement_counter(:post_count, 5)
db045db @dhh Initial
dhh authored
601 def decrement_counter(counter_name, id)
8375237 @jamis Made increment_counter/decrement_counter play nicely with optimistic …
jamis authored
602 update_counters(id, counter_name => -1)
db045db @dhh Initial
dhh authored
603 end
604
c450a36 @dhh Doc fixes
dhh authored
605
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
606 # Attributes named in this macro are protected from mass-assignment, such as <tt>new(attributes)</tt> and
db045db @dhh Initial
dhh authored
607 # <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
608 # methods to do assignment. This is meant to protect sensitive attributes from being overwritten by URL/form hackers. Example:
db045db @dhh Initial
dhh authored
609 #
610 # class Customer < ActiveRecord::Base
611 # attr_protected :credit_rating
612 # end
613 #
614 # customer = Customer.new("name" => David, "credit_rating" => "Excellent")
615 # customer.credit_rating # => nil
616 # customer.attributes = { "description" => "Jolly fellow", "credit_rating" => "Superb" }
617 # customer.credit_rating # => nil
618 #
619 # customer.credit_rating = "Average"
620 # customer.credit_rating # => "Average"
621 def attr_protected(*attributes)
0e0e774 Protect id attribute from mass assigment even when the primary key is…
Marcel Molina authored
622 write_inheritable_array("attr_protected", attributes - (protected_attributes || []))
db045db @dhh Initial
dhh authored
623 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
624
098fa94 @dhh Fixed documentation snafus #575, #576, #577, #585
dhh authored
625 # Returns an array of all the attributes that have been protected from mass-assignment.
db045db @dhh Initial
dhh authored
626 def protected_attributes # :nodoc:
627 read_inheritable_attribute("attr_protected")
628 end
629
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
630 # If this macro is used, only those attributes named in it will be accessible for mass-assignment, such as
db045db @dhh Initial
dhh authored
631 # <tt>new(attributes)</tt> and <tt>attributes=(attributes)</tt>. This is the more conservative choice for mass-assignment
632 # protection. If you'd rather start from an all-open default and restrict attributes as needed, have a look at
633 # attr_protected.
634 def attr_accessible(*attributes)
0e0e774 Protect id attribute from mass assigment even when the primary key is…
Marcel Molina authored
635 write_inheritable_array("attr_accessible", attributes - (accessible_attributes || []))
db045db @dhh Initial
dhh authored
636 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
637
098fa94 @dhh Fixed documentation snafus #575, #576, #577, #585
dhh authored
638 # Returns an array of all the attributes that have been made accessible to mass-assignment.
db045db @dhh Initial
dhh authored
639 def accessible_attributes # :nodoc:
640 read_inheritable_attribute("attr_accessible")
641 end
642
c450a36 @dhh Doc fixes
dhh authored
643
db045db @dhh Initial
dhh authored
644 # Specifies that the attribute by the name of +attr_name+ should be serialized before saving to the database and unserialized
645 # after loading from the database. The serialization is done through YAML. If +class_name+ is specified, the serialized
098fa94 @dhh Fixed documentation snafus #575, #576, #577, #585
dhh authored
646 # object must be of that class on retrieval or +SerializationTypeMismatch+ will be raised.
db045db @dhh Initial
dhh authored
647 def serialize(attr_name, class_name = Object)
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
648 serialized_attributes[attr_name.to_s] = class_name
db045db @dhh Initial
dhh authored
649 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
650
db045db @dhh Initial
dhh authored
651 # Returns a hash of all the attributes that have been specified for serialization as keys and their class restriction as values.
652 def serialized_attributes
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
653 read_inheritable_attribute("attr_serialized") or write_inheritable_attribute("attr_serialized", {})
db045db @dhh Initial
dhh authored
654 end
655
c450a36 @dhh Doc fixes
dhh authored
656
db045db @dhh Initial
dhh authored
657 # Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending
658 # directly from ActiveRecord. So if the hierarchy looks like: Reply < Message < ActiveRecord, then Message is used
4eab375 @dhh Finished polishing API docs
dhh authored
659 # to guess the table name from even when called on Reply. The rules used to do the guess are handled by the Inflector class
660 # in Active Support, which knows almost all common English inflections (report a bug if your inflection isn't covered).
db045db @dhh Initial
dhh authored
661 #
14101c7 @jeremy Nested classes are given table names prefixed by the singular form of…
jeremy authored
662 # Nested classes are given table names prefixed by the singular form of
663 # the parent's table name. Example:
664 # file class table_name
665 # invoice.rb Invoice invoices
666 # invoice/lineitem.rb Invoice::Lineitem invoice_lineitems
db045db @dhh Initial
dhh authored
667 #
14101c7 @jeremy Nested classes are given table names prefixed by the singular form of…
jeremy authored
668 # Additionally, the class-level table_name_prefix is prepended and the
669 # table_name_suffix is appended. So if you have "myapp_" as a prefix,
670 # the table name guess for an Invoice class becomes "myapp_invoices".
671 # Invoice::Lineitem becomes "myapp_invoice_lineitems".
672 #
673 # You can also overwrite this class method to allow for unguessable
674 # links, such as a Mouse class with a link to a "mice" table. Example:
db045db @dhh Initial
dhh authored
675 #
676 # class Mouse < ActiveRecord::Base
14101c7 @jeremy Nested classes are given table names prefixed by the singular form of…
jeremy authored
677 # set_table_name "mice"
db045db @dhh Initial
dhh authored
678 # end
dcc4868 @dhh Fixed that Base.table_name would expect a parameter when used in has_…
dhh authored
679 def table_name
d736568 Speed up the setting of table_name. Closes #2428.
Marcel Molina authored
680 reset_table_name
681 end
682
fed7d33 @dhh Fixed documentation
dhh authored
683 def reset_table_name #:nodoc:
bcbce90 @jeremy Nested subclasses are not prefixed with the parent class' table_name …
jeremy authored
684 base = base_class
685
686 name =
687 # STI subclasses always use their superclass' table.
688 unless self == base
689 base.table_name
690 else
691 # Nested classes are prefixed with singular parent table name.
692 if parent < ActiveRecord::Base && !parent.abstract_class?
693 contained = parent.table_name
694 contained = contained.singularize if parent.pluralize_table_names
695 contained << '_'
696 end
697 name = "#{table_name_prefix}#{contained}#{undecorated_table_name(base.name)}#{table_name_suffix}"
698 end
699
c450a36 @dhh Doc fixes
dhh authored
700 set_table_name(name)
d736568 Speed up the setting of table_name. Closes #2428.
Marcel Molina authored
701 name
db045db @dhh Initial
dhh authored
702 end
703
098fa94 @dhh Fixed documentation snafus #575, #576, #577, #585
dhh authored
704 # Defines the primary key field -- can be overridden in subclasses. Overwriting will negate any effect of the
db045db @dhh Initial
dhh authored
705 # primary_key_prefix_type setting, though.
706 def primary_key
c0899bc Add convenience predicate methods on Column class. In partial fullfil…
Marcel Molina authored
707 reset_primary_key
708 end
709
fed7d33 @dhh Fixed documentation
dhh authored
710 def reset_primary_key #:nodoc:
c0899bc Add convenience predicate methods on Column class. In partial fullfil…
Marcel Molina authored
711 key = 'id'
db045db @dhh Initial
dhh authored
712 case primary_key_prefix_type
713 when :table_name
def7460 @technoweenie Added Base.abstract_class? that marks which classes are not part of t…
technoweenie authored
714 key = Inflector.foreign_key(base_class.name, false)
db045db @dhh Initial
dhh authored
715 when :table_name_with_underscore
def7460 @technoweenie Added Base.abstract_class? that marks which classes are not part of t…
technoweenie authored
716 key = Inflector.foreign_key(base_class.name)
db045db @dhh Initial
dhh authored
717 end
c0899bc Add convenience predicate methods on Column class. In partial fullfil…
Marcel Molina authored
718 set_primary_key(key)
719 key
db045db @dhh Initial
dhh authored
720 end
721
9d2da04 @jeremy Cache inheritance_column. Closes #6592.
jeremy authored
722 # Defines the column name for use with single table inheritance
723 # -- can be set in subclasses like so: self.inheritance_column = "type_id"
db045db @dhh Initial
dhh authored
724 def inheritance_column
9d2da04 @jeremy Cache inheritance_column. Closes #6592.
jeremy authored
725 @inheritance_column ||= "type".freeze
db045db @dhh Initial
dhh authored
726 end
727
7c8f3ed @jeremy r4325@asus: jeremy | 2005-11-12 03:57:46 -0800
jeremy authored
728 # Lazy-set the sequence name to the connection's default. This method
729 # is only ever called once since set_sequence_name overrides it.
fed7d33 @dhh Fixed documentation
dhh authored
730 def sequence_name #:nodoc:
7c8f3ed @jeremy r4325@asus: jeremy | 2005-11-12 03:57:46 -0800
jeremy authored
731 reset_sequence_name
732 end
733
fed7d33 @dhh Fixed documentation
dhh authored
734 def reset_sequence_name #:nodoc:
7c8f3ed @jeremy r4325@asus: jeremy | 2005-11-12 03:57:46 -0800
jeremy authored
735 default = connection.default_sequence_name(table_name, primary_key)
736 set_sequence_name(default)
737 default
14ea312 @dhh Made Oracle a first-class connection adapter by adhering closer to id…
dhh authored
738 end
739
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindings
dhh authored
740 # Sets the table name to use to the given value, or (if the value
4eab375 @dhh Finished polishing API docs
dhh authored
741 # is nil or false) to the value returned by the given block.
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindings
dhh authored
742 #
743 # Example:
744 #
745 # class Project < ActiveRecord::Base
746 # set_table_name "project"
747 # end
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
748 def set_table_name(value = nil, &block)
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindings
dhh authored
749 define_attr_method :table_name, value, &block
750 end
751 alias :table_name= :set_table_name
752
753 # Sets the name of the primary key column to use to the given value,
754 # or (if the value is nil or false) to the value returned by the given
4eab375 @dhh Finished polishing API docs
dhh authored
755 # block.
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindings
dhh authored
756 #
757 # Example:
758 #
759 # class Project < ActiveRecord::Base
760 # set_primary_key "sysid"
761 # end
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
762 def set_primary_key(value = nil, &block)
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindings
dhh authored
763 define_attr_method :primary_key, value, &block
764 end
765 alias :primary_key= :set_primary_key
766
767 # Sets the name of the inheritance column to use to the given value,
768 # or (if the value # is nil or false) to the value returned by the
4eab375 @dhh Finished polishing API docs
dhh authored
769 # given block.
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindings
dhh authored
770 #
771 # Example:
772 #
773 # class Project < ActiveRecord::Base
774 # set_inheritance_column do
775 # original_inheritance_column + "_id"
776 # end
777 # end
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
778 def set_inheritance_column(value = nil, &block)
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindings
dhh authored
779 define_attr_method :inheritance_column, value, &block
780 end
781 alias :inheritance_column= :set_inheritance_column
782
14ea312 @dhh Made Oracle a first-class connection adapter by adhering closer to id…
dhh authored
783 # Sets the name of the sequence to use when generating ids to the given
784 # value, or (if the value is nil or false) to the value returned by the
7117fdb @jeremy r3616@asus: jeremy | 2005-09-26 23:09:28 -0700
jeremy authored
785 # given block. This is required for Oracle and is useful for any
786 # database which relies on sequences for primary key generation.
14ea312 @dhh Made Oracle a first-class connection adapter by adhering closer to id…
dhh authored
787 #
2076dca @jeremy r3095@asus: jeremy | 2005-11-15 22:40:51 -0800
jeremy authored
788 # If a sequence name is not explicitly set when using Oracle or Firebird,
789 # it will default to the commonly used pattern of: #{table_name}_seq
790 #
791 # If a sequence name is not explicitly set when using PostgreSQL, it
792 # will discover the sequence corresponding to your primary key for you.
14ea312 @dhh Made Oracle a first-class connection adapter by adhering closer to id…
dhh authored
793 #
794 # Example:
795 #
796 # class Project < ActiveRecord::Base
797 # set_sequence_name "projectseq" # default would have been "project_seq"
798 # end
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
799 def set_sequence_name(value = nil, &block)
14ea312 @dhh Made Oracle a first-class connection adapter by adhering closer to id…
dhh authored
800 define_attr_method :sequence_name, value, &block
801 end
802 alias :sequence_name= :set_sequence_name
803
db045db @dhh Initial
dhh authored
804 # Turns the +table_name+ back into a class name following the reverse rules of +table_name+.
805 def class_name(table_name = table_name) # :nodoc:
806 # remove any prefix and/or suffix from the table name
81737fc @jeremy r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
807 class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].camelize
808 class_name = class_name.singularize if pluralize_table_names
809 class_name
db045db @dhh Initial
dhh authored
810 end
811
816f37a @dhh Added migration support to SQL Server adapter (please someone do the …
dhh authored
812 # Indicates whether the table associated with this class exists
813 def table_exists?
814 if connection.respond_to?(:tables)
815 connection.tables.include? table_name
816 else
817 # if the connection adapter hasn't implemented tables, there are two crude tests that can be
818 # used - see if getting column info raises an error, or if the number of columns returned is zero
819 begin
820 reset_column_information
821 columns.size > 0
822 rescue ActiveRecord::StatementInvalid
823 false
824 end
825 end
826 end
827
db045db @dhh Initial
dhh authored
828 # Returns an array of column objects for the table associated with this class.
829 def columns
c0899bc Add convenience predicate methods on Column class. In partial fullfil…
Marcel Molina authored
830 unless @columns
831 @columns = connection.columns(table_name, "#{name} Columns")
832 @columns.each {|column| column.primary = column.name == primary_key}
833 end
834 @columns
db045db @dhh Initial
dhh authored
835 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
836
3b4450b @NZKoz Docs fix for columns_hash [bradediger]
NZKoz authored
837 # Returns a hash of column objects for the table associated with this class.
db045db @dhh Initial
dhh authored
838 def columns_hash
839 @columns_hash ||= columns.inject({}) { |hash, column| hash[column.name] = column; hash }
840 end
d0bd3b5 @jeremy Return PostgreSQL columns in the order they are declared #1374 (perlg…
jeremy authored
841
fed7d33 @dhh Fixed documentation
dhh authored
842 # Returns an array of column names as strings.
49d0f0c @dhh Speeded up eager loading a whole bunch
dhh authored
843 def column_names
d0bd3b5 @jeremy Return PostgreSQL columns in the order they are declared #1374 (perlg…
jeremy authored
844 @column_names ||= columns.map { |column| column.name }
49d0f0c @dhh Speeded up eager loading a whole bunch
dhh authored
845 end
db045db @dhh Initial
dhh authored
846
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
847 # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
848 # and columns used for single table inheritance have been removed.
db045db @dhh Initial
dhh authored
849 def content_columns
c0899bc Add convenience predicate methods on Column class. In partial fullfil…
Marcel Molina authored
850 @content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
db045db @dhh Initial
dhh authored
851 end
852
853 # 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
854 # 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 r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
855 # is available.
fed7d33 @dhh Fixed documentation
dhh authored
856 def column_methods_hash #:nodoc:
d0bd3b5 @jeremy Return PostgreSQL columns in the order they are declared #1374 (perlg…
jeremy authored
857 @dynamic_methods_hash ||= column_names.inject(Hash.new(false)) do |methods, attr|
3ab3a70 @jeremy Clarify semantics of ActiveRecord::Base#respond_to? Closes #2560.
jeremy authored
858 attr_name = attr.to_s
859 methods[attr.to_sym] = attr_name
860 methods["#{attr}=".to_sym] = attr_name
861 methods["#{attr}?".to_sym] = attr_name
862 methods["#{attr}_before_type_cast".to_sym] = attr_name
db045db @dhh Initial
dhh authored
863 methods
864 end
865 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
866
f218771 Add option (true by default) to generate reader methods for each attr…
Marcel Molina authored
867 # Contains the names of the generated reader methods.
fed7d33 @dhh Fixed documentation
dhh authored
868 def read_methods #:nodoc:
aabf909 @jeremy Correct reader method generation for primary key attribute: handle ca…
jeremy authored
869 @read_methods ||= Set.new
f218771 Add option (true by default) to generate reader methods for each attr…
Marcel Molina authored
870 end
aabf909 @jeremy Correct reader method generation for primary key attribute: handle ca…
jeremy authored
871
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
872 # Resets all the cached information about columns, which will cause them to be reloaded on the next request.
1314f48 @dhh Added methods for resetting the cached information on classes that yo…
dhh authored
873 def reset_column_information
aabf909 @jeremy Correct reader method generation for primary key attribute: handle ca…
jeremy authored
874 read_methods.each { |name| undef_method(name) }
9d2da04 @jeremy Cache inheritance_column. Closes #6592.
jeremy authored
875 @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = @read_methods = @inheritance_column = nil
1314f48 @dhh Added methods for resetting the cached information on classes that yo…
dhh authored
876 end
877
4eab375 @dhh Finished polishing API docs
dhh authored
878 def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc:
1314f48 @dhh Added methods for resetting the cached information on classes that yo…
dhh authored
879 subclasses.each { |klass| klass.reset_inheritable_attributes; klass.reset_column_information }
880 end
db045db @dhh Initial
dhh authored
881
882 # Transforms attribute key names into a more humane format, such as "First name" instead of "first_name". Example:
883 # Person.human_attribute_name("first_name") # => "First name"
4eab375 @dhh Finished polishing API docs
dhh authored
884 # Deprecated in favor of just calling "first_name".humanize
885 def human_attribute_name(attribute_key_name) #:nodoc:
1f7e72f @dhh Made human_attribute_name(attribute_key_name) use Inflector.humanize
dhh authored
886 attribute_key_name.humanize
db045db @dhh Initial
dhh authored
887 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
888
06afb8c @jeremy Subclasses of an abstract class work with single-table inheritance. R…
jeremy authored
889 # True if this isn't a concrete subclass needing a STI type condition.
890 def descends_from_active_record?
891 if superclass.abstract_class?
892 superclass.descends_from_active_record?
893 else
894 superclass == Base || !columns_hash.include?(inheritance_column)
895 end
db045db @dhh Initial
dhh authored
896 end
897
52a9e50 @dhh Added ActiveRecord::Base.inspect to return a column-view like #<Post …
dhh authored
898 # Returns a string looking like: #<Post id:integer, title:string, body:text>
899 def inspect
900 "#<#{name} #{columns.collect { |c| "#{c.name}:#{c.type}" }.join(", ")}>"
901 end
902
b445ab9 @NZKoz Rename quote to quote_value so the name can be used in AR models. #3628
NZKoz authored
903
904 def quote_value(value, column = nil) #:nodoc:
b2c0ddf Add support for FrontBase (http://www.frontbase.com/) with a new adap…
Marcel Molina authored
905 connection.quote(value,column)
4940383 @dhh Fixed value quoting in all generated SQL statements, so that integers…
dhh authored
906 end
907
b445ab9 @NZKoz Rename quote to quote_value so the name can be used in AR models. #3628
NZKoz authored
908 def quote(value, column = nil) #:nodoc:
909 connection.quote(value, column)
910 end
e5684a2 @jamis update deprecations to include alternative methods (where available)
jamis authored
911 deprecate :quote => :quote_value
b445ab9 @NZKoz Rename quote to quote_value so the name can be used in AR models. #3628
NZKoz authored
912
4940383 @dhh Fixed value quoting in all generated SQL statements, so that integers…
dhh authored
913 # Used to sanitize objects before they're used in an SELECT SQL-statement. Delegates to <tt>connection.quote</tt>.
4eab375 @dhh Finished polishing API docs
dhh authored
914 def sanitize(object) #:nodoc:
4940383 @dhh Fixed value quoting in all generated SQL statements, so that integers…
dhh authored
915 connection.quote(object)
db045db @dhh Initial
dhh authored
916 end
917
f2a89d7 @dhh Give AR the new benchmark method too
dhh authored
918 # Log and benchmark multiple statements in a single block. Example:
db045db @dhh Initial
dhh authored
919 #
920 # Project.benchmark("Creating project") do
921 # project = Project.create("name" => "stuff")
922 # project.create_manager("name" => "David")
3dfa56c @dhh Updated all references to the old find_first and find_all to use the …
dhh authored
923 # project.milestones << Milestone.find(:all)
db045db @dhh Initial
dhh authored
924 # end
5e8e8d6 @dhh Added use_silence parameter to ActiveRecord::Base.benchmark that can …
dhh authored
925 #
f2a89d7 @dhh Give AR the new benchmark method too
dhh authored
926 # The benchmark is only recorded if the current level of the logger matches the <tt>log_level</tt>, which makes it
927 # easy to include benchmarking statements in production software that will remain inexpensive because the benchmark
928 # will only be conducted if the log level is low enough.
929 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
930 # The logging of the multiple statements is turned off unless <tt>use_silence</tt> is set to false.
f2a89d7 @dhh Give AR the new benchmark method too
dhh authored
931 def benchmark(title, log_level = Logger::DEBUG, use_silence = true)
932 if logger && logger.level == log_level
5e8e8d6 @dhh Added use_silence parameter to ActiveRecord::Base.benchmark that can …
dhh authored
933 result = nil
934 seconds = Benchmark.realtime { result = use_silence ? silence { yield } : yield }
f2a89d7 @dhh Give AR the new benchmark method too
dhh authored
935 logger.add(log_level, "#{title} (#{'%.5f' % seconds})")
5e8e8d6 @dhh Added use_silence parameter to ActiveRecord::Base.benchmark that can …
dhh authored
936 result
937 else
938 yield
939 end
c00bf5f @dhh Fixed the verbosity of using the AR store
dhh authored
940 end
81737fc @jeremy r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
941
c00bf5f @dhh Fixed the verbosity of using the AR store
dhh authored
942 # Silences the logger for the duration of the block.
943 def silence
81737fc @jeremy r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
944 old_logger_level, logger.level = logger.level, Logger::ERROR if logger
945 yield
946 ensure
908e9a1 @dhh Fixed that Base.silence should restore the old logger level when done…
dhh authored
947 logger.level = old_logger_level if logger
db045db @dhh Initial
dhh authored
948 end
390e6d2 @jeremy r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
949
950 # Scope parameters to method calls within the block. Takes a hash of method_name => parameters hash.
1215d54 @dhh Added support for nested scopes (closes #3407) [anna@wota.jp]
dhh authored
951 # method_name may be :find or :create. :find parameters may include the <tt>:conditions</tt>, <tt>:joins</tt>,
445cb5c @NZKoz Add support for :include to with_scope [andrew@redlinesoftware.com]
NZKoz authored
952 # <tt>:include</tt>, <tt>:offset</tt>, <tt>:limit</tt>, and <tt>:readonly</tt> options. :create parameters are an attributes hash.
34f9d30 @dhh Added support for calling constrained class methods on has_many and h…
dhh authored
953 #
390e6d2 @jeremy r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
954 # Article.with_scope(:find => { :conditions => "blog_id = 1" }, :create => { :blog_id => 1 }) do
34f9d30 @dhh Added support for calling constrained class methods on has_many and h…
dhh authored
955 # Article.find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1
390e6d2 @jeremy r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
956 # a = Article.create(1)
1215d54 @dhh Added support for nested scopes (closes #3407) [anna@wota.jp]
dhh authored
957 # a.blog_id # => 1
34f9d30 @dhh Added support for calling constrained class methods on has_many and h…
dhh authored
958 # end
1215d54 @dhh Added support for nested scopes (closes #3407) [anna@wota.jp]
dhh authored
959 #
960 # In nested scopings, all previous parameters are overwritten by inner rule
961 # except :conditions in :find, that are merged as hash.
962 #
963 # Article.with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }, :create => { :blog_id => 1 }) do
964 # Article.with_scope(:find => { :limit => 10})
965 # Article.find(:all) # => SELECT * from articles WHERE blog_id = 1 LIMIT 10
966 # end
967 # Article.with_scope(:find => { :conditions => "author_id = 3" })
968 # Article.find(:all) # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1
969 # end
970 # end
971 #
972 # You can ignore any previous scopings by using <tt>with_exclusive_scope</tt> method.
973 #
974 # Article.with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }) do
975 # Article.with_exclusive_scope(:find => { :limit => 10 })
976 # Article.find(:all) # => SELECT * from articles LIMIT 10
977 # end
978 # end
979 def with_scope(method_scoping = {}, action = :merge, &block)
980 method_scoping = method_scoping.method_scoping if method_scoping.respond_to?(:method_scoping)
981
390e6d2 @jeremy r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
982 # Dup first and second level of hash (method and params).
983 method_scoping = method_scoping.inject({}) do |hash, (method, params)|
1215d54 @dhh Added support for nested scopes (closes #3407) [anna@wota.jp]
dhh authored
984 hash[method] = (params == true) ? params : params.dup
390e6d2 @jeremy r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
985 hash
986 end
987
43f6643 @dhh Fix form_for use of datetime_select and date_select as well as a few …
dhh authored
988 method_scoping.assert_valid_keys([ :find, :create ])
989
390e6d2 @jeremy r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
990 if f = method_scoping[:find]
15aa6e0 @jeremy r4644@asus: jeremy | 2006-06-16 14:57:03 -0700
jeremy authored
991 f.assert_valid_keys([ :conditions, :joins, :select, :include, :from, :offset, :limit, :order, :readonly, :lock ])
5bd116c @NZKoz Make sure with_scope takes both :select and :joins into account when …
NZKoz authored
992 set_readonly_option! f
390e6d2 @jeremy r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
993 end
a5a82d9 @dhh Added extension capabilities to has_many and has_and_belongs_to_many …
dhh authored
994
1215d54 @dhh Added support for nested scopes (closes #3407) [anna@wota.jp]
dhh authored
995 # Merge scopings
996 if action == :merge && current_scoped_methods
997 method_scoping = current_scoped_methods.inject(method_scoping) do |hash, (method, params)|
998 case hash[method]
999 when Hash
445cb5c @NZKoz Add support for :include to with_scope [andrew@redlinesoftware.com]
NZKoz authored
1000 if method == :find
1215d54 @dhh Added support for nested scopes (closes #3407) [anna@wota.jp]
dhh authored
1001 (hash[method].keys + params.keys).uniq.each do |key|
445cb5c @NZKoz Add support for :include to with_scope [andrew@redlinesoftware.com]
NZKoz authored
1002 merge = hash[method][key] && params[key] # merge if both scopes have the same key
1003 if key == :conditions && merge
53aa8da @dhh Fixed that records returned from has_and_belongs_to_many associations…
dhh authored
1004 hash[method][key] = [params[key], hash[method][key]].collect{ |sql| "( %s )" % sanitize_sql(sql) }.join(" AND ")
445cb5c @NZKoz Add support for :include to with_scope [andrew@redlinesoftware.com]
NZKoz authored
1005 elsif key == :include && merge
1006 hash[method][key] = merge_includes(hash[method][key], params[key]).uniq
1215d54 @dhh Added support for nested scopes (closes #3407) [anna@wota.jp]
dhh authored
1007 else
1008 hash[method][key] = hash[method][key] || params[key]
1009 end
1010 end
1011 else
1012 hash[method] = params.merge(hash[method])
1013 end
1014 else
1015 hash[method] = params
1016 end
1017 hash
1018 end
1019 end
1020
1021 self.scoped_methods << method_scoping
a5a82d9 @dhh Added extension capabilities to has_many and has_and_belongs_to_many …
dhh authored
1022
1215d54 @dhh Added support for nested scopes (closes #3407) [anna@wota.jp]
dhh authored
1023 begin
1024 yield
db7fadd @technoweenie Changed those private ActiveRecord methods to take optional third arg…
technoweenie authored
1025 ensure
1215d54 @dhh Added support for nested scopes (closes #3407) [anna@wota.jp]
dhh authored
1026 self.scoped_methods.pop
1027 end
1028 end
1029
ccfcd9f @dhh Doc fixes
dhh authored
1030 # Works like with_scope, but discards any nested properties.
1215d54 @dhh Added support for nested scopes (closes #3407) [anna@wota.jp]
dhh authored
1031 def with_exclusive_scope(method_scoping = {}, &block)
1032 with_scope(method_scoping, :overwrite, &block)
34f9d30 @dhh Added support for calling constrained class methods on has_many and h…
dhh authored
1033 end
db045db @dhh Initial
dhh authored
1034
97849de @dhh Fixed that association proxies would fail === tests like PremiumSubsc…
dhh authored
1035 # Overwrite the default class equality method to provide support for association proxies.
1036 def ===(object)
1037 object.is_a?(self)
34f9d30 @dhh Added support for calling constrained class methods on has_many and h…
dhh authored
1038 end
b840e4e Deprecated ActiveRecord::Base.threaded_connection in favor of ActiveR…
Marcel Molina authored
1039
1040 # Deprecated
ccfcd9f @dhh Doc fixes
dhh authored
1041 def threaded_connections #:nodoc:
b840e4e Deprecated ActiveRecord::Base.threaded_connection in favor of ActiveR…
Marcel Molina authored
1042 allow_concurrency
1043 end
1044
1045 # Deprecated
ccfcd9f @dhh Doc fixes
dhh authored
1046 def threaded_connections=(value) #:nodoc:
b840e4e Deprecated ActiveR