Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100755 2297 lines (2044 sloc) 102.4 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'
db045db @dhh Initial
dhh authored
4
5 module ActiveRecord #:nodoc:
6 class ActiveRecordError < StandardError #:nodoc:
7 end
605bc77 @dhh Added a better exception for when a type column is used in a table wi…
dhh authored
8 class SubclassNotFound < ActiveRecordError #:nodoc:
9 end
db045db @dhh 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
4c7555a @dhh Fixed that Base.save should always return false if the save didn't su…
dhh authored
24 class RecordNotSaved < ActiveRecordError #:nodoc:
25 end
db045db @dhh Initial
dhh authored
26 class StatementInvalid < ActiveRecordError #:nodoc:
27 end
554597d @dhh Added named bind-style variable interpolation #281 [Michael Koziarski]
dhh authored
28 class PreparedStatementInvalid < ActiveRecordError #:nodoc:
29 end
fbf9281 @dhh Added automated optimistic locking if the field lock_version is prese…
dhh authored
30 class StaleObjectError < ActiveRecordError #:nodoc:
31 end
5b2e8b1 @technoweenie Fix that ActiveRecord would create attribute methods and override cus…
technoweenie authored
32 class ConfigurationError < ActiveRecordError #:nodoc:
5b9b904 @dhh Added support for limit and offset with eager loading of has_one and …
dhh authored
33 end
5b2e8b1 @technoweenie Fix that ActiveRecord would create attribute methods and override cus…
technoweenie authored
34 class ReadOnlyRecord < ActiveRecordError #:nodoc:
64fcb75 @jeremy r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
35 end
5b2e8b1 @technoweenie Fix that ActiveRecord would create attribute methods and override cus…
technoweenie authored
36 class Rollback < ActiveRecordError #:nodoc:
37 end
38 class DangerousAttributeError < ActiveRecordError #:nodoc:
ebbe4fb @NZKoz Replace the transaction {|transaction|..} semantics with a new Except…
NZKoz authored
39 end
84a14f2 @jeremy Raise ProtectedAttributeAssignmentError in development and test envir…
jeremy authored
40
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
41 # Raised when you've tried to access a column which wasn't
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
42 # loaded by your finder. Typically this is because :select
43 # has been specified
44 class MissingAttributeError < NoMethodError
45 end
e48b062 @jeremy Sanitize Base#inspect. Closes #8392.
jeremy authored
46
d2fefbe @dhh Added MultiparameterAssignmentErrors and AttributeAssignmentError exc…
dhh authored
47 class AttributeAssignmentError < ActiveRecordError #:nodoc:
48 attr_reader :exception, :attribute
49 def initialize(message, exception, attribute)
50 @exception = exception
51 @attribute = attribute
52 @message = message
53 end
54 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
55
d2fefbe @dhh Added MultiparameterAssignmentErrors and AttributeAssignmentError exc…
dhh authored
56 class MultiparameterAssignmentErrors < ActiveRecordError #:nodoc:
57 attr_reader :errors
58 def initialize(errors)
59 @errors = errors
60 end
61 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
62
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
63 # Active Record objects don't specify their attributes directly, but rather infer them from the table definition with
db045db @dhh Initial
dhh authored
64 # which they're linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change
65 # 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
66 # database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.
67 #
db045db @dhh Initial
dhh authored
68 # 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
69 #
db045db @dhh Initial
dhh authored
70 # == Creation
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
71 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
72 # Active Records accept constructor parameters either in a hash or as a block. The hash method is especially useful when
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
73 # you're receiving the data from somewhere else, like an HTTP request. It works like this:
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
74 #
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
75 # user = User.new(:name => "David", :occupation => "Code Artist")
db045db @dhh Initial
dhh authored
76 # user.name # => "David"
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
77 #
db045db @dhh Initial
dhh authored
78 # You can also use block initialization:
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
79 #
db045db @dhh Initial
dhh authored
80 # user = User.new do |u|
81 # u.name = "David"
82 # u.occupation = "Code Artist"
83 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
84 #
db045db @dhh Initial
dhh authored
85 # 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
86 #
db045db @dhh Initial
dhh authored
87 # user = User.new
88 # user.name = "David"
89 # user.occupation = "Code Artist"
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
90 #
db045db @dhh Initial
dhh authored
91 # == Conditions
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
92 #
c5ec16e @dhh Added simple hash conditions to find that'll just convert hash to an …
dhh authored
93 # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement.
db045db @dhh Initial
dhh authored
94 # 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
95 # 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
96 # only equality and range is possible. Examples:
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
97 #
48052d7 @jeremy to_xml fixes, features, and speedup. Closes #4989.
jeremy authored
98 # class User < ActiveRecord::Base
db045db @dhh Initial
dhh authored
99 # 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
100 # find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'")
db045db @dhh Initial
dhh authored
101 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
102 #
db045db @dhh Initial
dhh authored
103 # 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
104 # find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ])
db045db @dhh Initial
dhh authored
105 # end
c5ec16e @dhh Added simple hash conditions to find that'll just convert hash to an …
dhh authored
106 #
107 # def self.authenticate_safely_simply(user_name, password)
108 # find(:first, :conditions => { :user_name => user_name, :password => password })
109 # end
db045db @dhh Initial
dhh authored
110 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
111 #
2575b3b @dhh Added extra words of caution for guarding against SQL-injection attacks
dhh authored
112 # The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query and is thus susceptible to SQL-injection
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
113 # attacks if the <tt>user_name</tt> and +password+ parameters come directly from an HTTP request. The <tt>authenticate_safely</tt> and
c5ec16e @dhh Added simple hash conditions to find that'll just convert hash to an …
dhh authored
114 # <tt>authenticate_safely_simply</tt> both will sanitize the <tt>user_name</tt> and +password+ before inserting them in the query,
115 # 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
116 #
5cd38ca @dhh Added documentation about named bind variables
dhh authored
117 # 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
118 # 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
119 # the question marks with symbols and supplying a hash with values for the matching symbol keys:
120 #
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
121 # Company.find(:first, [
122 # "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
5cd38ca @dhh Added documentation about named bind variables
dhh authored
123 # { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' }
124 # ])
125 #
c5ec16e @dhh Added simple hash conditions to find that'll just convert hash to an …
dhh authored
126 # Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND
127 # operator. For instance:
128 #
129 # Student.find(:all, :conditions => { :first_name => "Harvey", :status => 1 })
130 # Student.find(:all, :conditions => params[:student])
131 #
2876707 @jeremy Pass a range in :conditions to use the SQL BETWEEN operator. Closes #…
jeremy authored
132 # A range may be used in the hash to use the SQL BETWEEN operator:
133 #
134 # Student.find(:all, :conditions => { :grade => 9..12 })
c5ec16e @dhh Added simple hash conditions to find that'll just convert hash to an …
dhh authored
135 #
db045db @dhh Initial
dhh authored
136 # == Overwriting default accessors
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
137 #
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
138 # All column values are automatically available through basic accessors on the Active Record object, but sometimes you
139 # want to specialize this behavior. This can be done by overwriting the default accessors (using the same
140 # name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things.
db045db @dhh Initial
dhh authored
141 # Example:
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
142 #
db045db @dhh Initial
dhh authored
143 # class Song < ActiveRecord::Base
144 # # 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
145 #
db045db @dhh Initial
dhh authored
146 # def length=(minutes)
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
147 # write_attribute(:length, minutes * 60)
db045db @dhh Initial
dhh authored
148 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
149 #
db045db @dhh Initial
dhh authored
150 # def length
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
151 # read_attribute(:length) / 60
db045db @dhh Initial
dhh authored
152 # end
153 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
154 #
e3b49c0 @dhh Fixed spelling errors (closes #9706) [tarmo/rmm5t]
dhh authored
155 # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
156 # read_attribute(:attribute) as a shorter form.
157 #
e4d845e Document automatically generated predicate methods for attributes. Cl…
Marcel Molina authored
158 # == Attribute query methods
159 #
160 # In addition to the basic accessors, query methods are also automatically available on the Active Record object.
161 # Query methods allow you to test whether an attribute value is present.
162 #
163 # For example, an Active Record User with the <tt>name</tt> attribute has a <tt>name?</tt> method that you can call
164 # to determine whether the user has a name:
165 #
166 # user = User.new(:name => "David")
167 # user.name? # => true
168 #
169 # anonymous = User.new(:name => "")
170 # anonymous.name? # => false
171 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
172 # == Accessing attributes before they have been typecasted
4eab375 @dhh Finished polishing API docs
dhh authored
173 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
174 # 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
175 # 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
176 # 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
177 #
178 # 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
179 # 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
180 # want.
181 #
ac8fd7d @dhh Added dynamic attribute-based finders as a cleaner way of getting obj…
dhh authored
182 # == Dynamic attribute-based finders
183 #
a5a82d9 @dhh Added extension capabilities to has_many and has_and_belongs_to_many …
dhh authored
184 # 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
185 # 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
186 # Person.find_all_by_last_name, Payment.find_by_transaction_id. So instead of writing
187 # <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
188 # 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
189 #
ac8fd7d @dhh Added dynamic attribute-based finders as a cleaner way of getting obj…
dhh authored
190 # It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders like
191 # <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
192 # <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
193 # <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
194 #
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
195 # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount
196 # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is
197 # 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
198 #
a5a82d9 @dhh Added extension capabilities to has_many and has_and_belongs_to_many …
dhh authored
199 # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with
200 # <tt>find_or_create_by_</tt> and will return the object if it already exists and otherwise creates it, then returns it. Example:
201 #
202 # # No 'Summer' tag exists
203 # Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")
204 #
205 # # Now the 'Summer' tag does exist
206 # Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
207 #
d19e464 @sstephenson Added find_or_initialize_by_X which works like find_or_create_by_X bu…
sstephenson authored
208 # Use the <tt>find_or_initialize_by_</tt> finder if you want to return a new record without saving it first. Example:
209 #
210 # # No 'Winter' tag exists
211 # 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
212 # winter.new_record? # true
d19e464 @sstephenson Added find_or_initialize_by_X which works like find_or_create_by_X bu…
sstephenson authored
213 #
14cc8d2 @jeremy find_or_create_by_* takes a hash so you can create with more attribut…
jeremy authored
214 # To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of
215 # a list of parameters. For example:
216 #
217 # Tag.find_or_create_by_name(:name => "rails", :creator => current_user)
218 #
219 # That will either find an existing tag named "rails", or create a new one while setting the user that created it.
220 #
098fa94 @dhh Fixed documentation snafus #575, #576, #577, #585
dhh authored
221 # == 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
222 #
223 # 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
224 # 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
225 #
db045db @dhh Initial
dhh authored
226 # class User < ActiveRecord::Base
227 # serialize :preferences
228 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
229 #
ca2eb16 Fix syntax error in documentation. Closes #4679. [mislav@nippur.irb.hr]
Marcel Molina authored
230 # user = User.create(:preferences => { "background" => "black", "display" => large })
db045db @dhh Initial
dhh authored
231 # User.find(user.id).preferences # => { "background" => "black", "display" => large }
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
232 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
233 # 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
234 # descendent of a class not in the hierarchy. Example:
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
235 #
db045db @dhh Initial
dhh authored
236 # class User < ActiveRecord::Base
66f44e6 @dhh Updated documentation for serialize
dhh authored
237 # serialize :preferences, Hash
db045db @dhh Initial
dhh authored
238 # end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
239 #
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
240 # user = User.create(:preferences => %w( one two three ))
db045db @dhh Initial
dhh authored
241 # User.find(user.id).preferences # raises SerializationTypeMismatch
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
242 #
db045db @dhh Initial
dhh authored
243 # == Single table inheritance
244 #
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
245 # Active Record allows inheritance by storing the name of the class in a column that by default is named "type" (can be changed
db045db @dhh Initial
dhh authored
246 # by overwriting <tt>Base.inheritance_column</tt>). This means that an inheritance looking like this:
247 #
248 # class Company < ActiveRecord::Base; end
249 # class Firm < Company; end
250 # class Client < Company; end
251 # class PriorityClient < Client; end
252 #
0591c53 @dhh Made the dynamic finders use the new find API and updated the example…
dhh authored
253 # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then
254 # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object.
db045db @dhh Initial
dhh authored
255 #
f033833 @dhh Improving documentation...
dhh authored
256 # 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
257 # like normal subclasses with no special magic for differentiating between them or reloading the right type with find.
258 #
db045db @dhh Initial
dhh authored
259 # Note, all the attributes for all the cases are kept in the same table. Read more:
260 # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
261 #
db045db @dhh Initial
dhh authored
262 # == Connection to multiple databases in different models
263 #
264 # 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
265 # All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection.
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
266 # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection
db045db @dhh Initial
dhh authored
267 # and Course *and all its subclasses* will use this connection instead.
268 #
269 # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is
270 # requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool.
271 #
272 # == Exceptions
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
273 #
db045db @dhh Initial
dhh authored
274 # * +ActiveRecordError+ -- generic error class and superclass of all other errors raised by Active Record
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
275 # * +AdapterNotSpecified+ -- the configuration hash used in <tt>establish_connection</tt> didn't include an
db045db @dhh Initial
dhh authored
276 # <tt>:adapter</tt> key.
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
277 # * +AdapterNotFound+ -- the <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified a non-existent adapter
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
278 # (or a bad spelling of an existing one).
279 # * +AssociationTypeMismatch+ -- the object assigned to the association wasn't of the type specified in the association definition.
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
280 # * +SerializationTypeMismatch+ -- the serialized object wasn't of the class specified as the second parameter.
db045db @dhh Initial
dhh authored
281 # * +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
282 # * +RecordNotFound+ -- no record responded to the find* method.
db045db @dhh Initial
dhh authored
283 # Either the row with the given ID doesn't exist or the row didn't meet the additional restrictions.
284 # * +StatementInvalid+ -- the database server rejected the SQL statement. The precise error is added in the message.
285 # 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
286 # * +MultiparameterAssignmentErrors+ -- collection of errors that occurred during a mass assignment using the
287 # +attributes=+ method. The +errors+ property of this exception contains an array of +AttributeAssignmentError+
d2fefbe @dhh Added MultiparameterAssignmentErrors and AttributeAssignmentError exc…
dhh authored
288 # objects that should be inspected to determine which attributes triggered the errors.
289 # * +AttributeAssignmentError+ -- an error occurred while doing a mass assignment through the +attributes=+ method.
290 # 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
291 #
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
292 # *Note*: The attributes listed are class-level attributes (accessible from both the class and instance level).
db045db @dhh Initial
dhh authored
293 # So it's possible to assign a logger to the class through Base.logger= which will then be used by all
294 # instances in the current object space.
295 class Base
296 # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then passed
297 # 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 #7…
technoweenie authored
298 cattr_accessor :logger, :instance_writer => false
e694114 @jeremy Deprecation: removed Reloadable.
jeremy authored
299
db045db @dhh Initial
dhh authored
300 def self.inherited(child) #:nodoc:
301 @@subclasses[self] ||= []
302 @@subclasses[self] << child
303 super
304 end
e694114 @jeremy Deprecation: removed Reloadable.
jeremy authored
305
fed7d33 @dhh Fixed documentation
dhh authored
306 def self.reset_subclasses #:nodoc:
bfbf6bb @jamis Allow ARStore::Session to indicate that it should not be reloaded in …
jamis authored
307 nonreloadables = []
e7f61ea @jamis squash the memleak in dev mode finally (fingers crossed, here)
jamis authored
308 subclasses.each do |klass|
74165eb @seckar New dependencies implementation
seckar authored
309 unless Dependencies.autoloaded? klass
bfbf6bb @jamis Allow ARStore::Session to indicate that it should not be reloaded in …
jamis authored
310 nonreloadables << klass
311 next
312 end
e7f61ea @jamis squash the memleak in dev mode finally (fingers crossed, here)
jamis authored
313 klass.instance_variables.each { |var| klass.send(:remove_instance_variable, var) }
314 klass.instance_methods(false).each { |m| klass.send :undef_method, m }
315 end
bfbf6bb @jamis Allow ARStore::Session to indicate that it should not be reloaded in …
jamis authored
316 @@subclasses = {}
317 nonreloadables.each { |klass| (@@subclasses[klass.superclass] ||= []) << klass }
3c0129a @dhh Fixed memory leak with Active Record classes when Dependencies.mechan…
dhh authored
318 end
319
db045db @dhh Initial
dhh authored
320 @@subclasses = {}
c4a3634 @jeremy Corrected @@configurations typo. #1410 [david@ruppconsulting.com]
jeremy authored
321
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7…
technoweenie authored
322 cattr_accessor :configurations, :instance_writer => false
c4a3634 @jeremy Corrected @@configurations typo. #1410 [david@ruppconsulting.com]
jeremy authored
323 @@configurations = {}
324
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
325 # 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
326 # :table_name_with_underscore. If the first is specified, the Product class will look for "productid" instead of "id" as
327 # 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
328 # that this is a global setting for all Active Records.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7…
technoweenie authored
329 cattr_accessor :primary_key_prefix_type, :instance_writer => false
db045db @dhh Initial
dhh authored
330 @@primary_key_prefix_type = nil
331
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
332 # 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
333 # 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
334 # 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 #7…
technoweenie authored
335 cattr_accessor :table_name_prefix, :instance_writer => false
db045db @dhh Initial
dhh authored
336 @@table_name_prefix = ""
337
338 # Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
339 # "people_basecamp"). By default, the suffix is the empty string.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7…
technoweenie authored
340 cattr_accessor :table_name_suffix, :instance_writer => false
db045db @dhh Initial
dhh authored
341 @@table_name_suffix = ""
342
84a14f2 @jeremy Raise ProtectedAttributeAssignmentError in development and test envir…
jeremy authored
343 # Indicates whether table names should be the pluralized versions of the corresponding class names.
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
344 # 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
345 # 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 #7…
technoweenie authored
346 cattr_accessor :pluralize_table_names, :instance_writer => false
db045db @dhh Initial
dhh authored
347 @@pluralize_table_names = true
348
84a14f2 @jeremy Raise ProtectedAttributeAssignmentError in development and test envir…
jeremy authored
349 # Determines whether 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
350 # 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
351 # 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 #7…
technoweenie authored
352 cattr_accessor :colorize_logging, :instance_writer => false
911614d @dhh Added ActiveRecord::Base.colorize_logging to control whether to use c…
dhh authored
353 @@colorize_logging = true
354
60de8c1 @dhh Added Base.default_timezone accessor that determines whether to use T…
dhh authored
355 # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling dates and times from the database.
356 # This is set to :local by default.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7…
technoweenie authored
357 cattr_accessor :default_timezone, :instance_writer => false
60de8c1 @dhh Added Base.default_timezone accessor that determines whether to use T…
dhh authored
358 @@default_timezone = :local
d8641ca @jeremy CHANGED DEFAULT: set ActiveRecord::Base.allow_concurrency to false. …
jeremy authored
359
84a14f2 @jeremy Raise ProtectedAttributeAssignmentError in development and test envir…
jeremy authored
360 # Determines whether 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. …
jeremy authored
361 # 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 #7…
technoweenie authored
362 cattr_accessor :allow_concurrency, :instance_writer => false
25fb2db @jeremy Dynamically set allow_concurrency. Closes #4044.
jeremy authored
363 @@allow_concurrency = false
d8641ca @jeremy CHANGED DEFAULT: set ActiveRecord::Base.allow_concurrency to false. …
jeremy authored
364
24c3599 @sstephenson Support using different database adapters for development and test wi…
sstephenson authored
365 # Specifies the format to use when dumping the database schema with Rails'
366 # Rakefile. If :sql, the schema is dumped as (potentially database-
367 # specific) SQL statements. If :ruby, the schema is dumped as an
368 # ActiveRecord::Schema file which can be loaded into any database that
369 # supports migrations. Use :ruby if you want to have different database
370 # adapters for, e.g., your development and test environments.
1a11bff @technoweenie Don't create instance writer methods for class attributes. Closes #7…
technoweenie authored
371 cattr_accessor :schema_format , :instance_writer => false
660952e @dhh CHANGED DEFAULT: ActiveRecord::Base.schema_format is now :ruby by def…
dhh authored
372 @@schema_format = :ruby
f218771 Add option (true by default) to generate reader methods for each attr…
Marcel Molina authored
373
db045db @dhh Initial
dhh authored
374 class << self # Class methods
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
375 # Find operates with three different retrieval approaches:
7669011 @dhh Fixes for postgresql testing #1129, #1130, #1131
dhh authored
376 #
377 # * 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]).
378 # If no record can be found for all of the listed ids, then RecordNotFound will be raised.
379 # * Find first: This will return the first record matched by the options used. These options can either be specific
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
380 # conditions or merely an order. If no record can be matched, nil is returned.
7d01005 @dhh Fixed documentation and prepared for release of 0.12
dhh authored
381 # * 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
382 #
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
383 # All approaches accept an options hash as their last parameter. The options are:
7669011 @dhh Fixes for postgresql testing #1129, #1130, #1131
dhh authored
384 #
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
385 # * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
386 # * <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
387 # * <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
388 # * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned.
39c64ff @jeremy Clarify :offset docs. Closes #3733.
jeremy authored
389 # * <tt>:offset</tt>: An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.
37adea6 @dhh Address shortcomings of changeset [8054] [protocool]
dhh authored
390 # * <tt>:joins</tt>: An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (Rarely needed).
391 # Accepts named associations in the form of :include, which will perform an INNER JOIN on the associated table(s).
392 # 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
393 # Pass :readonly => false to override.
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
394 # See adding joins for associations under Associations.
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
395 # * <tt>:include</tt>: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer
396 # to already defined associations. See eager loading under Associations.
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
397 # * <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
6f05696 @dhh Added :select option to find which can specify a different value than…
dhh authored
398 # include the joined columns.
d3cf2a6 Document find's :from option. Closes #5762. [andrew@redlinesoftware.com]
Marcel Molina authored
399 # * <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
400 # of a database view).
64fcb75 @jeremy r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
401 # * <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
402 # * <tt>:lock</tt>: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE".
403 # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE".
7669011 @dhh Fixes for postgresql testing #1129, #1130, #1131
dhh authored
404 #
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
405 # Examples for find by id:
db045db @dhh Initial
dhh authored
406 # Person.find(1) # returns the object for ID = 1
407 # Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
408 # Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
409 # Person.find([1]) # returns an array for the object with ID = 1
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
410 # Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC")
411 #
1e9e198 @jeremy Note that find results may not be in the same order as the id argumen…
jeremy authored
412 # Note that returned records may not be in the same order as the ids you
413 # provide since database rows are unordered. Give an explicit :order
414 # to ensure the results are sorted.
415 #
515886a @dhh Added documentation for new Base.find API and eager association loading
dhh authored
416 # Examples for find first:
7d01005 @dhh Fixed documentation and prepared for release of 0.12
dhh authored
417 # 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
418 # Person.find(:first, :conditions => [ "user_name = ?", user_name])
419 # Person.find(:first, :order => "created_on DESC", :offset => 5)
420 #
421 # Examples for find all:
7d01005 @dhh Fixed documentation and prepared for release of 0.12
dhh authored
422 # 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
423 # Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50)
424 # Person.find(:all, :offset => 10, :limit => 10)
425 # Person.find(:all, :include => [ :account, :friends ])
3309268 @jeremy Add :group option, correspond to GROUP BY, to the find method and to …
jeremy authored
426 # Person.find(:all, :group => "category")
15aa6e0 @jeremy r4644@asus: jeremy | 2006-06-16 14:57:03 -0700
jeremy authored
427 #
428 # Example for find with a lock. Imagine two concurrent transactions:
429 # each will read person.visits == 2, add 1 to it, and save, resulting
430 # in two saves of person.visits = 3. By locking the row, the second
431 # transaction has to wait until the first is finished; we get the
432 # expected person.visits == 4.
433 # Person.transaction do
434 # person = Person.find(1, :lock => true)
435 # person.visits += 1
436 # person.save!
437 # end
6bd672e @dhh Added that Base#find takes an optional options hash, including :condi…
dhh authored
438 def find(*args)
edd68a5 @dhh Refactored in use of extract_options! (closes #9079) [josh]
dhh authored
439 options = args.extract_options!
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
440 # Note: we extract any :joins option with a non-string value from the options, and turn it into
441 # an internal option :ar_joins. This allows code called from here to find the ar_joins, and
442 # it bypasses marking the result as read_only.
443 # A normal string join marks the result as read-only because it contains attributes from joined tables
444 # which are not in the base table and therefore prevent the result from being saved.
445 # In the case of an ar_join, the JoinDependency created to instantiate the results eliminates these
446 # bogus attributes. See JoinDependency#instantiate, and JoinBase#instantiate in associations.rb.
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
447 validate_find_options(options)
448 set_readonly_option!(options)
64fcb75 @jeremy r3618@sedna: jeremy | 2005-10-14 12:06:03 -0700
jeremy authored
449
abc895b @dhh Added new Base.find API and deprecated find_all, find_first. Added pr…
dhh authored
450 case args.first
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
451 when :first then find_initial(options)
452 when :all then find_every(options)
453 else find_from_ids(args, options)
db045db @dhh Initial
dhh authored
454 end
455 end
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
456
3dfa56c @dhh Updated all references to the old find_first and find_all to use the …
dhh authored
457 # Works like find(:all), but requires a complete SQL string. Examples:
db045db @dhh Initial
dhh authored
458 # 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
459 # Post.find_by_sql ["SELECT * FROM posts WHERE author = ? AND created > ?", author_id, start_date]
db045db @dhh Initial
dhh authored
460 def find_by_sql(sql)
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
461 connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) }
db045db @dhh Initial
dhh authored
462 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
463
abc895b @dhh Added new Base.find API and deprecated find_all, find_first. Added pr…
dhh authored
464 # 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
465 # 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
466 # Example:
467 # Person.exists?(5)
58ebf30 @jeremy The exists? class method should treat a string argument as an id rath…
jeremy authored
468 # Person.exists?('5')
8085cbf @dhh Added support for conditions on Base.exists? (closes #5689) [josh@jos…
dhh authored
469 # Person.exists?(:name => "David")
58ebf30 @jeremy The exists? class method should treat a string argument as an id rath…
jeremy authored
470 # Person.exists?(['name LIKE ?', "%#{query}%"])
471 def exists?(id_or_conditions)
c4c6662 @NZKoz Performance enhancement for Base.exists?. CLoses #8769. [hasmanyjosh]
NZKoz authored
472 !find(:first, :select => "#{table_name}.#{primary_key}", :conditions => expand_id_conditions(id_or_conditions)).nil?
58ebf30 @jeremy The exists? class method should treat a string argument as an id rath…
jeremy authored
473 rescue ActiveRecord::ActiveRecordError
474 false
db045db @dhh Initial
dhh authored
475 end
abc895b @dhh Added new Base.find API and deprecated find_all, find_first. Added pr…
dhh authored
476
db045db @dhh Initial
dhh authored
477 # 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
478 # fails under validations, the unsaved object is still returned.
db045db @dhh Initial
dhh authored
479 def create(attributes = nil)
efa81da @dhh Added the option of supplying an array of ids and attributes to Base#…
dhh authored
480 if attributes.is_a?(Array)
481 attributes.collect { |attr| create(attr) }
482 else
483 object = new(attributes)
484 object.save
485 object
486 end
db045db @dhh Initial
dhh authored
487 end
488
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
489 # 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
490 # 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
491 #
492 # The arguments may also be given as arrays in which case the update method is called for each pair of +id+ and
493 # +attributes+ and an array of objects is returned.
494 #
495 # Example of updating one record:
496 # Person.update(15, {:user_name => 'Samuel', :group => 'expert'})
497 #
498 # Example of updating multiple records:
499 # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy"} }
500 # Person.update(people.keys, people.values)
db045db @dhh Initial
dhh authored
501 def update(id, attributes)
efa81da @dhh Added the option of supplying an array of ids and attributes to Base#…
dhh authored
502 if id.is_a?(Array)
503 idx = -1
504 id.collect { |id| idx += 1; update(id, attributes[idx]) }
505 else
506 object = find(id)
507 object.update_attributes(attributes)
508 object
509 end
db045db @dhh Initial
dhh authored
510 end
511
efa81da @dhh Added the option of supplying an array of ids and attributes to Base#…
dhh authored
512 # Deletes the record with the given +id+ without instantiating an object first. If an array of ids is provided, all of them
513 # are deleted.
648b8fd @dhh Added Base.destroy and Base.delete to remove records without holding …
dhh authored
514 def delete(id)
98165fd @jeremy Consistently quote primary key column names. Closes #7763.
jeremy authored
515 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
516 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
517
648b8fd @dhh Added Base.destroy and Base.delete to remove records without holding …
dhh authored
518 # 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
519 # 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
520 def destroy(id)
efa81da @dhh Added the option of supplying an array of ids and attributes to Base#…
dhh authored
521 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
522 end
523
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
524 # 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
525 # A subset of the records can be selected by specifying +conditions+. Example:
db045db @dhh Initial
dhh authored
526 # 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
527 #
528 # Optional :order and :limit options may be given as the third parameter,
529 # but their behavior is database-specific.
530 def update_all(updates, conditions = nil, options = {})
5acea7f @jeremy update_all can take a Hash argument. sanitize_sql splits into two met…
jeremy authored
531 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
532 scope = scope(:find)
533 add_conditions!(sql, conditions, scope)
534 add_order!(sql, options[:order], scope)
535 add_limit!(sql, options, scope)
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
536 connection.update(sql, "#{name} Update")
db045db @dhh Initial
dhh authored
537 end
0d2db8a @dhh Added Base.update_collection that can update an array of id/attribute…
dhh authored
538
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
539 # Destroys the objects for all the records that match the +conditions+ by instantiating each object and calling
db045db @dhh Initial
dhh authored
540 # the destroy method. Example:
541 # Person.destroy_all "last_login < '2004-04-04'"
542 def destroy_all(conditions = nil)
3dfa56c @dhh Updated all references to the old find_first and find_all to use the …
dhh authored
543 find(:all, :conditions => conditions).each { |object| object.destroy }
db045db @dhh Initial
dhh authored
544 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
545
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
546 # Deletes all the records that match the +conditions+ without instantiating the objects first (and hence not
db045db @dhh Initial
dhh authored
547 # calling the destroy method). Example:
090bfce @jeremy Correct documentation for Base.delete_all. References #1568.
jeremy authored
548 # Post.delete_all "person_id = 5 AND (category = 'Something' OR category = 'Else')"
db045db @dhh Initial
dhh authored
549 def delete_all(conditions = nil)
9b6207c @jeremy Quote table names. Defaults to column quoting. Closes #4593.
jeremy authored
550 sql = "DELETE FROM #{quoted_table_name} "
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
551 add_conditions!(sql, conditions, scope(:find))
db045db @dhh Initial
dhh authored
552 connection.delete(sql, "#{name} Delete all")
553 end
554
555 # 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
556 # The use of this method should be restricted to complicated SQL queries that can't be executed
557 # using the ActiveRecord::Calculations class methods. Look into those before using this.
558 #
559 # ==== Options
560 #
561 # +sql+: An SQL statement which should return a count query from the database, see the example below
562 #
563 # ==== Examples
564 #
e17bf81 @jamis Fix typo in count_by_sql documentation #1969 [Alexey Verkhovsky]
jamis authored
565 # Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
db045db @dhh Initial
dhh authored
566 def count_by_sql(sql)
a775cb1 @dhh Added the option for sanitizing find_by_sql and the offset parts in r…
dhh authored
567 sql = sanitize_conditions(sql)
caaf40d @dhh Added AbstractAdapter#select_value and AbstractAdapter#select_values …
dhh authored
568 connection.select_value(sql, "#{name} Count").to_i
db045db @dhh Initial
dhh authored
569 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
570
8375237 @jamis Made increment_counter/decrement_counter play nicely with optimistic …
jamis authored
571 # A generic "counter updater" implementation, intended primarily to be
572 # used by increment_counter and decrement_counter, but which may also
573 # be useful on its own. It simply does a direct SQL update for the record
574 # with the given ID, altering the given hash of counters by the amount
575 # given by the corresponding value:
576 #
577 # Post.update_counters 5, :comment_count => -1, :action_count => 1
578 # # UPDATE posts
579 # # SET comment_count = comment_count - 1,
580 # # action_count = action_count + 1
581 # # WHERE id = 5
582 def update_counters(id, counters)
583 updates = counters.inject([]) { |list, (counter_name, increment)|
584 sign = increment < 0 ? "-" : "+"
98165fd @jeremy Consistently quote primary key column names. Closes #7763.
jeremy authored
585 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
586 }.join(", ")
98165fd @jeremy Consistently quote primary key column names. Closes #7763.
jeremy authored
587 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
588 end
589
15dc567 Also add documentation enhancements for increment_counter. Closes #80…
Marcel Molina authored
590 # Increment a number field by one, usually representing a count.
591 #
592 # This is used for caching aggregate values, so that they don't need to be computed every time.
593 # For example, a DiscussionBoard may cache post_count and comment_count otherwise every time the board is
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
594 # shown it would have to run an SQL query to find how many posts and comments there are.
15dc567 Also add documentation enhancements for increment_counter. Closes #80…
Marcel Molina authored
595 #
596 # ==== Options
597 #
598 # +counter_name+ The name of the field that should be incremented
599 # +id+ The id of the object that should be incremented
600 #
601 # ==== Examples
602 #
603 # # Increment the post_count column for the record with an id of 5
604 # DiscussionBoard.increment_counter(:post_count, 5)
db045db @dhh Initial
dhh authored
605 def increment_counter(counter_name, id)
8375237 @jamis Made increment_counter/decrement_counter play nicely with optimistic …
jamis authored
606 update_counters(id, counter_name => 1)
db045db @dhh Initial
dhh authored
607 end
608
5bd3570 Enhance documentation for decrement_counter. Closes #8093. [fearoffish]
Marcel Molina authored
609 # Decrement a number field by one, usually representing a count.
610 #
611 # This works the same as increment_counter but reduces the column value by 1 instead of increasing it.
612 #
613 # ==== Options
614 #
615 # +counter_name+ The name of the field that should be decremented
616 # +id+ The id of the object that should be decremented
617 #
618 # ==== Examples
619 #
620 # # Decrement the post_count column for the record with an id of 5
621 # DiscussionBoard.decrement_counter(:post_count, 5)
db045db @dhh Initial
dhh authored
622 def decrement_counter(counter_name, id)
8375237 @jamis Made increment_counter/decrement_counter play nicely with optimistic …
jamis authored
623 update_counters(id, counter_name => -1)
db045db @dhh Initial
dhh authored
624 end
625
c450a36 @dhh Doc fixes
dhh authored
626
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
627 # Attributes named in this macro are protected from mass-assignment, such as <tt>new(attributes)</tt> and
db045db @dhh Initial
dhh authored
628 # <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
629 # methods to do assignment. This is meant to protect sensitive attributes from being overwritten by URL/form hackers. Example:
db045db @dhh Initial
dhh authored
630 #
631 # class Customer < ActiveRecord::Base
632 # attr_protected :credit_rating
633 # end
634 #
635 # customer = Customer.new("name" => David, "credit_rating" => "Excellent")
636 # customer.credit_rating # => nil
637 # customer.attributes = { "description" => "Jolly fellow", "credit_rating" => "Superb" }
638 # customer.credit_rating # => nil
639 #
640 # customer.credit_rating = "Average"
641 # customer.credit_rating # => "Average"
d761ac4 Add docs explaining how to protect all attributes using attr_accessib…
Marcel Molina authored
642 #
643 # To start from an all-closed default and enable attributes as needed, have a look at attr_accessible.
db045db @dhh Initial
dhh authored
644 def attr_protected(*attributes)
3a3e7ef @jeremy attr_protected and _accessible use sets of strings instead of arrays …
jeremy authored
645 write_inheritable_attribute("attr_protected", Set.new(attributes.map(&:to_s)) + (protected_attributes || []))
db045db @dhh Initial
dhh authored
646 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
647
098fa94 @dhh Fixed documentation snafus #575, #576, #577, #585
dhh authored
648 # Returns an array of all the attributes that have been protected from mass-assignment.
db045db @dhh Initial
dhh authored
649 def protected_attributes # :nodoc:
650 read_inheritable_attribute("attr_protected")
651 end
652
f770b82 Enhance explanation with more examples for attr_accessible macro. Clo…
Marcel Molina authored
653 # Similar to the attr_protected macro, this protects attributes of your model from mass-assignment,
654 # such as <tt>new(attributes)</tt> and <tt>attributes=(attributes)</tt>
655 # however, it does it in the opposite way. This locks all attributes and only allows access to the
656 # attributes specified. Assignment to attributes not in this list will be ignored and need to be set
657 # using the direct writer methods instead. This is meant to protect sensitive attributes from being
658 # overwritten by URL/form hackers. If you'd rather start from an all-open default and restrict
659 # attributes as needed, have a look at attr_protected.
660 #
661 # ==== Options
d761ac4 Add docs explaining how to protect all attributes using attr_accessib…
Marcel Molina authored
662 #
f770b82 Enhance explanation with more examples for attr_accessible macro. Clo…
Marcel Molina authored
663 # <tt>*attributes</tt> A comma separated list of symbols that represent columns _not_ to be protected
664 #
665 # ==== Examples
d761ac4 Add docs explaining how to protect all attributes using attr_accessib…
Marcel Molina authored
666 #
667 # class Customer < ActiveRecord::Base
f770b82 Enhance explanation with more examples for attr_accessible macro. Clo…
Marcel Molina authored
668 # attr_accessible :name, :nickname
d761ac4 Add docs explaining how to protect all attributes using attr_accessib…
Marcel Molina authored
669 # end
670 #
f770b82 Enhance explanation with more examples for attr_accessible macro. Clo…
Marcel Molina authored
671 # customer = Customer.new(:name => "David", :nickname => "Dave", :credit_rating => "Excellent")
672 # customer.credit_rating # => nil
673 # customer.attributes = { :name => "Jolly fellow", :credit_rating => "Superb" }
674 # customer.credit_rating # => nil
d761ac4 Add docs explaining how to protect all attributes using attr_accessib…
Marcel Molina authored
675 #
f770b82 Enhance explanation with more examples for attr_accessible macro. Clo…
Marcel Molina authored
676 # customer.credit_rating = "Average"
677 # customer.credit_rating # => "Average"
db045db @dhh Initial
dhh authored
678 def attr_accessible(*attributes)
3a3e7ef @jeremy attr_protected and _accessible use sets of strings instead of arrays …
jeremy authored
679 write_inheritable_attribute("attr_accessible", Set.new(attributes.map(&:to_s)) + (accessible_attributes || []))
db045db @dhh Initial
dhh authored
680 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
681
098fa94 @dhh Fixed documentation snafus #575, #576, #577, #585
dhh authored
682 # Returns an array of all the attributes that have been made accessible to mass-assignment.
db045db @dhh Initial
dhh authored
683 def accessible_attributes # :nodoc:
684 read_inheritable_attribute("attr_accessible")
685 end
686
66d05f5 @technoweenie Add attr_readonly to specify columns that are skipped during a normal…
technoweenie authored
687 # Attributes listed as readonly can be set for a new record, but will be ignored in database updates afterwards.
688 def attr_readonly(*attributes)
a33007d @jeremy attr_readonly uses a set of strings instead of an array of symbols in…
jeremy authored
689 write_inheritable_attribute("attr_readonly", Set.new(attributes.map(&:to_s)) + (readonly_attributes || []))
66d05f5 @technoweenie Add attr_readonly to specify columns that are skipped during a normal…
technoweenie authored
690 end
691
692 # Returns an array of all the attributes that have been specified as readonly.
693 def readonly_attributes
694 read_inheritable_attribute("attr_readonly")
695 end
c450a36 @dhh Doc fixes
dhh authored
696
1a0cdf7 @dhh Docfix (closes #8096)
dhh authored
697 # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object,
698 # then specify the name of that attribute using this method and it will be handled automatically.
699 # The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that
700 # class on retrieval or +SerializationTypeMismatch+ will be raised.
701 #
702 # ==== Options
703 #
704 # +attr_name+ The field name that should be serialized
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
705 # +class_name+ Optional, class name that the object type should be equal to
1a0cdf7 @dhh Docfix (closes #8096)
dhh authored
706 #
707 # ==== Example
708 # # Serialize a preferences attribute
709 # class User
710 # serialize :preferences
711 # end
db045db @dhh Initial
dhh authored
712 def serialize(attr_name, class_name = Object)
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
713 serialized_attributes[attr_name.to_s] = class_name
db045db @dhh Initial
dhh authored
714 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
715
db045db @dhh Initial
dhh authored
716 # Returns a hash of all the attributes that have been specified for serialization as keys and their class restriction as values.
717 def serialized_attributes
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
718 read_inheritable_attribute("attr_serialized") or write_inheritable_attribute("attr_serialized", {})
db045db @dhh Initial
dhh authored
719 end
720
c450a36 @dhh Doc fixes
dhh authored
721
db045db @dhh Initial
dhh authored
722 # Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending
723 # directly from ActiveRecord. So if the hierarchy looks like: Reply < Message < ActiveRecord, then Message is used
d64832c Give examples for what tables should be called for models inside a mo…
Marcel Molina authored
724 # to guess the table name even when called on Reply. The rules used to do the guess are handled by the Inflector class
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
725 # in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb.
db045db @dhh Initial
dhh authored
726 #
14101c7 @jeremy Nested classes are given table names prefixed by the singular form of…
jeremy authored
727 # Nested classes are given table names prefixed by the singular form of
d64832c Give examples for what tables should be called for models inside a mo…
Marcel Molina authored
728 # the parent's table name. Enclosing modules are not considered. Examples:
729 #
730 # class Invoice < ActiveRecord::Base; end;
14101c7 @jeremy Nested classes are given table names prefixed by the singular form of…
jeremy authored
731 # file class table_name
732 # invoice.rb Invoice invoices
d64832c Give examples for what tables should be called for models inside a mo…
Marcel Molina authored
733 #
734 # class Invoice < ActiveRecord::Base; class Lineitem < ActiveRecord::Base; end; end;
735 # file class table_name
736 # invoice.rb Invoice::Lineitem invoice_lineitems
737 #
738 # module Invoice; class Lineitem < ActiveRecord::Base; end; end;
739 # file class table_name
740 # invoice/lineitem.rb Invoice::Lineitem lineitems
db045db @dhh Initial
dhh authored
741 #
14101c7 @jeremy Nested classes are given table names prefixed by the singular form of…
jeremy authored
742 # Additionally, the class-level table_name_prefix is prepended and the
743 # table_name_suffix is appended. So if you have "myapp_" as a prefix,
744 # the table name guess for an Invoice class becomes "myapp_invoices".
745 # Invoice::Lineitem becomes "myapp_invoice_lineitems".
746 #
747 # You can also overwrite this class method to allow for unguessable
748 # links, such as a Mouse class with a link to a "mice" table. Example:
db045db @dhh Initial
dhh authored
749 #
750 # class Mouse < ActiveRecord::Base
14101c7 @jeremy Nested classes are given table names prefixed by the singular form of…
jeremy authored
751 # set_table_name "mice"
db045db @dhh Initial
dhh authored
752 # end
dcc4868 @dhh Fixed that Base.table_name would expect a parameter when used in has_…
dhh authored
753 def table_name
d736568 Speed up the setting of table_name. Closes #2428.
Marcel Molina authored
754 reset_table_name
755 end
756
fed7d33 @dhh Fixed documentation
dhh authored
757 def reset_table_name #:nodoc:
bcbce90 @jeremy Nested subclasses are not prefixed with the parent class' table_name …
jeremy authored
758 base = base_class
759
760 name =
761 # STI subclasses always use their superclass' table.
762 unless self == base
763 base.table_name
764 else
765 # Nested classes are prefixed with singular parent table name.
766 if parent < ActiveRecord::Base && !parent.abstract_class?
767 contained = parent.table_name
768 contained = contained.singularize if parent.pluralize_table_names
769 contained << '_'
770 end
771 name = "#{table_name_prefix}#{contained}#{undecorated_table_name(base.name)}#{table_name_suffix}"
772 end
773
c450a36 @dhh Doc fixes
dhh authored
774 set_table_name(name)
d736568 Speed up the setting of table_name. Closes #2428.
Marcel Molina authored
775 name
db045db @dhh Initial
dhh authored
776 end
777
098fa94 @dhh Fixed documentation snafus #575, #576, #577, #585
dhh authored
778 # Defines the primary key field -- can be overridden in subclasses. Overwriting will negate any effect of the
db045db @dhh Initial
dhh authored
779 # primary_key_prefix_type setting, though.
780 def primary_key
c0899bc Add convenience predicate methods on Column class. In partial fullfil…
Marcel Molina authored
781 reset_primary_key
782 end
783
fed7d33 @dhh Fixed documentation
dhh authored
784 def reset_primary_key #:nodoc:
c0899bc Add convenience predicate methods on Column class. In partial fullfil…
Marcel Molina authored
785 key = 'id'
db045db @dhh Initial
dhh authored
786 case primary_key_prefix_type
787 when :table_name
def7460 @technoweenie Added Base.abstract_class? that marks which classes are not part of t…
technoweenie authored
788 key = Inflector.foreign_key(base_class.name, false)
db045db @dhh Initial
dhh authored
789 when :table_name_with_underscore
def7460 @technoweenie Added Base.abstract_class? that marks which classes are not part of t…
technoweenie authored
790 key = Inflector.foreign_key(base_class.name)
db045db @dhh Initial
dhh authored
791 end
c0899bc Add convenience predicate methods on Column class. In partial fullfil…
Marcel Molina authored
792 set_primary_key(key)
793 key
db045db @dhh Initial
dhh authored
794 end
795
9d2da04 @jeremy Cache inheritance_column. Closes #6592.
jeremy authored
796 # Defines the column name for use with single table inheritance
797 # -- can be set in subclasses like so: self.inheritance_column = "type_id"
db045db @dhh Initial
dhh authored
798 def inheritance_column
9d2da04 @jeremy Cache inheritance_column. Closes #6592.
jeremy authored
799 @inheritance_column ||= "type".freeze
db045db @dhh Initial
dhh authored
800 end
801
7c8f3ed @jeremy r4325@asus: jeremy | 2005-11-12 03:57:46 -0800
jeremy authored
802 # Lazy-set the sequence name to the connection's default. This method
803 # is only ever called once since set_sequence_name overrides it.
fed7d33 @dhh Fixed documentation
dhh authored
804 def sequence_name #:nodoc:
7c8f3ed @jeremy r4325@asus: jeremy | 2005-11-12 03:57:46 -0800
jeremy authored
805 reset_sequence_name
806 end
807
fed7d33 @dhh Fixed documentation
dhh authored
808 def reset_sequence_name #:nodoc:
7c8f3ed @jeremy r4325@asus: jeremy | 2005-11-12 03:57:46 -0800
jeremy authored
809 default = connection.default_sequence_name(table_name, primary_key)
810 set_sequence_name(default)
811 default
14ea312 @dhh Made Oracle a first-class connection adapter by adhering closer to id…
dhh authored
812 end
813
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindin…
dhh authored
814 # Sets the table name to use to the given value, or (if the value
4eab375 @dhh Finished polishing API docs
dhh authored
815 # is nil or false) to the value returned by the given block.
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindin…
dhh authored
816 #
817 # Example:
818 #
819 # class Project < ActiveRecord::Base
820 # set_table_name "project"
821 # end
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
822 def set_table_name(value = nil, &block)
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindin…
dhh authored
823 define_attr_method :table_name, value, &block
824 end
825 alias :table_name= :set_table_name
826
827 # Sets the name of the primary key column to use to the given value,
828 # or (if the value is nil or false) to the value returned by the given
4eab375 @dhh Finished polishing API docs
dhh authored
829 # block.
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindin…
dhh authored
830 #
831 # Example:
832 #
833 # class Project < ActiveRecord::Base
834 # set_primary_key "sysid"
835 # end
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
836 def set_primary_key(value = nil, &block)
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindin…
dhh authored
837 define_attr_method :primary_key, value, &block
838 end
839 alias :primary_key= :set_primary_key
840
841 # Sets the name of the inheritance column to use to the given value,
842 # or (if the value # is nil or false) to the value returned by the
4eab375 @dhh Finished polishing API docs
dhh authored
843 # given block.
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindin…
dhh authored
844 #
845 # Example:
846 #
847 # class Project < ActiveRecord::Base
848 # set_inheritance_column do
849 # original_inheritance_column + "_id"
850 # end
851 # end
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
852 def set_inheritance_column(value = nil, &block)
1aa82b3 @dhh Added keyword-style approach to defining the custom relational bindin…
dhh authored
853 define_attr_method :inheritance_column, value, &block
854 end
855 alias :inheritance_column= :set_inheritance_column
856
14ea312 @dhh Made Oracle a first-class connection adapter by adhering closer to id…
dhh authored
857 # Sets the name of the sequence to use when generating ids to the given
858 # 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
859 # given block. This is required for Oracle and is useful for any
860 # 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
861 #
2076dca @jeremy r3095@asus: jeremy | 2005-11-15 22:40:51 -0800
jeremy authored
862 # If a sequence name is not explicitly set when using Oracle or Firebird,
863 # it will default to the commonly used pattern of: #{table_name}_seq
864 #
865 # If a sequence name is not explicitly set when using PostgreSQL, it
866 # 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
867 #
868 # Example:
869 #
870 # class Project < ActiveRecord::Base
871 # set_sequence_name "projectseq" # default would have been "project_seq"
872 # end
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
873 def set_sequence_name(value = nil, &block)
14ea312 @dhh Made Oracle a first-class connection adapter by adhering closer to id…
dhh authored
874 define_attr_method :sequence_name, value, &block
875 end
876 alias :sequence_name= :set_sequence_name
877
db045db @dhh Initial
dhh authored
878 # Turns the +table_name+ back into a class name following the reverse rules of +table_name+.
879 def class_name(table_name = table_name) # :nodoc:
880 # remove any prefix and/or suffix from the table name
81737fc @jeremy r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
881 class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].camelize
882 class_name = class_name.singularize if pluralize_table_names
883 class_name
db045db @dhh Initial
dhh authored
884 end
885
816f37a @dhh Added migration support to SQL Server adapter (please someone do the …
dhh authored
886 # Indicates whether the table associated with this class exists
887 def table_exists?
888 if connection.respond_to?(:tables)
889 connection.tables.include? table_name
890 else
891 # if the connection adapter hasn't implemented tables, there are two crude tests that can be
892 # used - see if getting column info raises an error, or if the number of columns returned is zero
893 begin
894 reset_column_information
895 columns.size > 0
896 rescue ActiveRecord::StatementInvalid
897 false
898 end
899 end
900 end
901
db045db @dhh Initial
dhh authored
902 # Returns an array of column objects for the table associated with this class.
903 def columns
c0899bc Add convenience predicate methods on Column class. In partial fullfil…
Marcel Molina authored
904 unless @columns
905 @columns = connection.columns(table_name, "#{name} Columns")
906 @columns.each {|column| column.primary = column.name == primary_key}
907 end
908 @columns
db045db @dhh Initial
dhh authored
909 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
910
3b4450b @NZKoz Docs fix for columns_hash [bradediger]
NZKoz authored
911 # Returns a hash of column objects for the table associated with this class.
db045db @dhh Initial
dhh authored
912 def columns_hash
913 @columns_hash ||= columns.inject({}) { |hash, column| hash[column.name] = column; hash }
914 end
d0bd3b5 @jeremy Return PostgreSQL columns in the order they are declared #1374 (perlg…
jeremy authored
915
fed7d33 @dhh Fixed documentation
dhh authored
916 # Returns an array of column names as strings.
49d0f0c @dhh Speeded up eager loading a whole bunch
dhh authored
917 def column_names
d0bd3b5 @jeremy Return PostgreSQL columns in the order they are declared #1374 (perlg…
jeremy authored
918 @column_names ||= columns.map { |column| column.name }
49d0f0c @dhh Speeded up eager loading a whole bunch
dhh authored
919 end
db045db @dhh Initial
dhh authored
920
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
921 # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
922 # and columns used for single table inheritance have been removed.
db045db @dhh Initial
dhh authored
923 def content_columns
c0899bc Add convenience predicate methods on Column class. In partial fullfil…
Marcel Molina authored
924 @content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
db045db @dhh Initial
dhh authored
925 end
926
927 # 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
928 # 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
929 # is available.
fed7d33 @dhh Fixed documentation
dhh authored
930 def column_methods_hash #:nodoc:
d0bd3b5 @jeremy Return PostgreSQL columns in the order they are declared #1374 (perlg…
jeremy authored
931 @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
932 attr_name = attr.to_s
933 methods[attr.to_sym] = attr_name
934 methods["#{attr}=".to_sym] = attr_name
935 methods["#{attr}?".to_sym] = attr_name
936 methods["#{attr}_before_type_cast".to_sym] = attr_name
db045db @dhh Initial
dhh authored
937 methods
938 end
939 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
940
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
941 # 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
942 def reset_column_information
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
943 generated_methods.each { |name| undef_method(name) }
944 @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = @generated_methods = @inheritance_column = nil
1314f48 @dhh Added methods for resetting the cached information on classes that yo…
dhh authored
945 end
946
4eab375 @dhh Finished polishing API docs
dhh authored
947 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
948 subclasses.each { |klass| klass.reset_inheritable_attributes; klass.reset_column_information }
949 end
db045db @dhh Initial
dhh authored
950
951 # Transforms attribute key names into a more humane format, such as "First name" instead of "first_name". Example:
952 # Person.human_attribute_name("first_name") # => "First name"
4eab375 @dhh Finished polishing API docs
dhh authored
953 # Deprecated in favor of just calling "first_name".humanize
954 def human_attribute_name(attribute_key_name) #:nodoc:
1f7e72f @dhh Made human_attribute_name(attribute_key_name) use Inflector.humanize
dhh authored
955 attribute_key_name.humanize
db045db @dhh Initial
dhh authored
956 end
6e39c9e @jeremy r1614@asus: jeremy | 2005-07-03 08:01:08 -0700
jeremy authored
957
06afb8c @jeremy Subclasses of an abstract class work with single-table inheritance. R…
jeremy authored
958 # True if this isn't a concrete subclass needing a STI type condition.
959 def descends_from_active_record?
960 if superclass.abstract_class?
961 superclass.descends_from_active_record?
962 else
963 superclass == Base || !columns_hash.include?(inheritance_column)
964 end
db045db @dhh Initial
dhh authored
965 end
966
b4ec990 @NZKoz Cache the descends_from_activerecord? call to speed up query generati…
NZKoz authored
967 def finder_needs_type_condition? #:nodoc:
968 # This is like this because benchmarking justifies the strange :false stuff
969 :true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true)
970 end
971
d0360a4 @jeremy Base.inspect handles Base itself and abstract_class? Don't use #<Foo…
jeremy authored
972 # Returns a string like 'Post id:integer, title:string, body:text'
52a9e50 @dhh Added ActiveRecord::Base.inspect to return a column-view like #<Post …
dhh authored
973 def inspect
d0360a4 @jeremy Base.inspect handles Base itself and abstract_class? Don't use #<Foo…
jeremy authored
974 if self == Base
975 super
976 elsif abstract_class?
977 "#{super}(abstract)"
bb94ce9 @NZKoz Let inspect on AR classes work when the table doesn't exist. Closes #…
NZKoz authored
978 elsif table_exists?
d0360a4 @jeremy Base.inspect handles Base itself and abstract_class? Don't use #<Foo…
jeremy authored
979 attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
980 "#{super}(#{attr_list})"
bb94ce9 @NZKoz Let inspect on AR classes work when the table doesn't exist. Closes #…
NZKoz authored
981 else
982 "#{super}(Table doesn't exist)"
d0360a4 @jeremy Base.inspect handles Base itself and abstract_class? Don't use #<Foo…
jeremy authored
983 end
52a9e50 @dhh Added ActiveRecord::Base.inspect to return a column-view like #<Post …
dhh authored
984 end
985
b445ab9 @NZKoz Rename quote to quote_value so the name can be used in AR models. #36…
NZKoz authored
986
987 def quote_value(value, column = nil) #:nodoc:
b2c0ddf Add support for FrontBase (http://www.frontbase.com/) with a new adap…
Marcel Molina authored
988 connection.quote(value,column)
4940383 @dhh Fixed value quoting in all generated SQL statements, so that integers…
dhh authored
989 end
990
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
991 # Used to sanitize objects before they're used in an SQL SELECT statement. Delegates to <tt>connection.quote</tt>.
4eab375 @dhh Finished polishing API docs
dhh authored
992 def sanitize(object) #:nodoc:
4940383 @dhh Fixed value quoting in all generated SQL statements, so that integers…
dhh authored
993 connection.quote(object)
db045db @dhh Initial
dhh authored
994 end
995
f2a89d7 @dhh Give AR the new benchmark method too
dhh authored
996 # Log and benchmark multiple statements in a single block. Example:
db045db @dhh Initial
dhh authored
997 #
998 # Project.benchmark("Creating project") do
999 # project = Project.create("name" => "stuff")
1000 # project.create_manager("name" => "David")
3dfa56c @dhh Updated all references to the old find_first and find_all to use the …
dhh authored
1001 # project.milestones << Milestone.find(:all)
db045db @dhh Initial
dhh authored
1002 # end
5e8e8d6 @dhh Added use_silence parameter to ActiveRecord::Base.benchmark that can …
dhh authored
1003 #
f2a89d7 @dhh Give AR the new benchmark method too
dhh authored
1004 # The benchmark is only recorded if the current level of the logger matches the <tt>log_level</tt>, which makes it
1005 # easy to include benchmarking statements in production software that will remain inexpensive because the benchmark
1006 # will only be conducted if the log level is low enough.
1007 #
2948910 Misc doc fixes (typos/grammar/etc.). Closes #2430.
Marcel Molina authored
1008 # 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
1009 def benchmark(title, log_level = Logger::DEBUG, use_silence = true)
1010 if logger && logger.level == log_level
5e8e8d6 @dhh Added use_silence parameter to ActiveRecord::Base.benchmark that can …
dhh authored
1011 result = nil
1012 seconds = Benchmark.realtime { result = use_silence ? silence { yield } : yield }
f2a89d7 @dhh Give AR the new benchmark method too
dhh authored
1013 logger.add(log_level, "#{title} (#{'%.5f' % seconds})")
5e8e8d6 @dhh Added use_silence parameter to ActiveRecord::Base.benchmark that can …
dhh authored
1014 result
1015 else
1016 yield
1017 end
c00bf5f @dhh Fixed the verbosity of using the AR store
dhh authored
1018 end
81737fc @jeremy r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
1019
c00bf5f @dhh Fixed the verbosity of using the AR store
dhh authored
1020 # Silences the logger for the duration of the block.
1021 def silence
81737fc @jeremy r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
1022 old_logger_level, logger.level = logger.level, Logger::ERROR if logger
1023 yield
1024 ensure
908e9a1 @dhh Fixed that Base.silence should restore the old logger level when done…
dhh authored
1025 logger.level = old_logger_level if logger
db045db @dhh Initial
dhh authored
1026 end
390e6d2 @jeremy r2915@asus: jeremy | 2005-11-06 05:02:53 -0800
jeremy authored
1027
97849de @dhh Fixed that association proxies would fail === tests like PremiumSubsc…
dhh authored
1028 # Overwrite the default class equality method to provide support for association proxies.
1029 def ===(object)
1030 object.is_a?(self)
34f9d30 @dhh Added support for calling constrained class methods on has_many and h…
dhh authored
1031 end
b840e4e Deprecated ActiveRecord::Base.threaded_connection in favor of ActiveR…
Marcel Molina authored
1032
d2f4750 @jamis Add AR::Base.base_class for querying the ancestor AR::Base subclass […
jamis authored
1033 # Returns the base AR subclass that this class descends from. If A
1034 # extends AR::Base, A.base_class will return A. If B descends from A
1035 # through some arbitrarily deep hierarchy, B.base_class will return A.
1036 def base_class
1037 class_of_active_record_descendant(self)
1038 end
1039
def7460 @technoweenie Added Base.abstract_class? that marks which classes are not part of t…
technoweenie authored
1040 # Set this to true if this is an abstract class (see #abstract_class?).
1041 attr_accessor :abstract_class
1042
1043 # Returns whether this class is a base AR class. If A is a base class and
1044 # B descends from A, then B.base_class will return B.
1045 def abstract_class?
1046 abstract_class == true
1047 end
1048
db045db @dhh Initial
dhh authored
1049 private
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1050 def find_initial(options)
1051 options.update(:limit => 1) unless options[:include]
1052 find_every(options).first
1053 end
2fbe0ae @jeremy Support nil and Array in :conditions => { attr => value } hashes. Clo…
jeremy authored
1054
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1055 def find_every(options)
37adea6 @dhh Address shortcomings of changeset [8054] [protocool]
dhh authored
1056 records = scoped?(:find, :include) || options[:include] ?
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1057 find_with_associations(options) :
1058 find_by_sql(construct_finder_sql(options))
1059
1060 records.each { |record| record.readonly! } if options[:readonly]
1061
1062 records
1063 end
2fbe0ae @jeremy Support nil and Array in :conditions => { attr => value } hashes. Clo…
jeremy authored
1064
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1065 def find_from_ids(ids, options)
2fbe0ae @jeremy Support nil and Array in :conditions => { attr => value } hashes. Clo…
jeremy authored
1066 expects_array = ids.first.kind_of?(Array)
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1067 return ids.first if expects_array && ids.first.empty?
2fbe0ae @jeremy Support nil and Array in :conditions => { attr => value } hashes. Clo…
jeremy authored
1068
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1069 ids = ids.flatten.compact.uniq
1070
1071 case ids.size
1072 when 0
1073 raise RecordNotFound, "Couldn't find #{name} without an ID"
1074 when 1
1075 result = find_one(ids.first, options)
1076 expects_array ? [ result ] : result
1077 else
1078 find_some(ids, options)
1079 end
1080 end
1081
1082 def find_one(id, options)
1083 conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
9b6207c @jeremy Quote table names. Defaults to column quoting. Closes #4593.
jeremy authored
1084 options.update :conditions => "#{quoted_table_name}.#{connection.quote_column_name(primary_key)} = #{quote_value(id,columns_hash[primary_key])}#{conditions}"
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1085
230c5a0 @jeremy find_one uses find_every.first instead of find_initial since its prim…
jeremy authored
1086 # Use find_every(options).first since the primary key condition
1087 # already ensures we have a single record. Using find_initial adds
1088 # a superfluous :limit => 1.
1089 if result = find_every(options).first
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1090 result
1091 else
1092 raise RecordNotFound, "Couldn't find #{name} with ID=#{id}#{conditions}"
1093 end
1094 end
1095
1096 def find_some(ids, options)
1097 conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
b445ab9 @NZKoz Rename quote to quote_value so the name can be used in AR models. #36…
NZKoz authored
1098 ids_list = ids.map { |id| quote_value(id,columns_hash[primary_key]) }.join(',')
9b6207c @jeremy Quote table names. Defaults to column quoting. Closes #4593.
jeremy authored
1099 options.update :conditions => "#{quoted_table_name}.#{connection.quote_column_name(primary_key)} IN (#{ids_list})#{conditions}"
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1100
1101 result = find_every(options)
1102
8158455 @jeremy Fix an edge case with find with a list of ids, limit, and offset. Clo…
jeremy authored
1103 # Determine expected size from limit and offset, not just ids.size.
109926c @jeremy Find with a list of ids supports limit/offset. Closes #8437.
jeremy authored
1104 expected_size =
1105 if options[:limit] && ids.size > options[:limit]
1106 options[:limit]
1107 else
1108 ids.size
1109 end
8158455 @jeremy Fix an edge case with find with a list of ids, limit, and offset. Clo…
jeremy authored
1110
1111 # 11 ids with limit 3, offset 9 should give 2 results.
1112 if options[:offset] && (ids.size - options[:offset] < expected_size)
1113 expected_size = ids.size - options[:offset]
1114 end
109926c @jeremy Find with a list of ids supports limit/offset. Closes #8437.
jeremy authored
1115
1116 if result.size == expected_size
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1117 result
1118 else
109926c @jeremy Find with a list of ids supports limit/offset. Closes #8437.
jeremy authored
1119 raise RecordNotFound, "Couldn't find all #{name.pluralize} with IDs (#{ids_list})#{conditions} (found #{result.size} results, but was looking for #{expected_size})"
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1120 end
1121 end
1122
4b4dd54 @jeremy Clashing type columns due to a sloppy join shouldn't wreck single-tab…
jeremy authored
1123 # Finder methods must instantiate through this method to work with the
1124 # single-table inheritance model that makes it possible to create
1125 # objects of different types from the same table.
db045db @dhh Initial
dhh authored
1126 def instantiate(record)
4b4dd54 @jeremy Clashing type columns due to a sloppy join shouldn't wreck single-tab…
jeremy authored
1127 object =
eb2fbf0 Optimize instantiation of STI subclass records. In partial fullfilmen…
Marcel Molina authored
1128 if subclass_name = record[inheritance_column]
4b4dd54 @jeremy Clashing type columns due to a sloppy join shouldn't wreck single-tab…
jeremy authored
1129 # No type given.
eb2fbf0 Optimize instantiation of STI subclass records. In partial fullfilmen…
Marcel Molina authored
1130 if subclass_name.empty?
1131 allocate
4b4dd54 @jeremy Clashing type columns due to a sloppy join shouldn't wreck single-tab…
jeremy authored
1132
eb2fbf0 Optimize instantiation of STI subclass records. In partial fullfilmen…
Marcel Molina authored
1133 else
4b4dd54 @jeremy Clashing type columns due to a sloppy join shouldn't wreck single-tab…
jeremy authored
1134 # Ignore type if no column is present since it was probably
1135 # pulled in from a sloppy join.
9d2da04 @jeremy Cache inheritance_column. Closes #6592.
jeremy authored
1136 unless columns_hash.include?(inheritance_column)
4b4dd54 @jeremy Clashing type columns due to a sloppy join shouldn't wreck single-tab…
jeremy authored
1137 allocate
1138
1139 else
1140 begin
1141 compute_type(subclass_name).allocate
1142 rescue NameError
1143 raise SubclassNotFound,
1144 "The single-table inheritance mechanism failed to locate the subclass: '#{record[inheritance_column]}'. " +
1145 "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
1146 "Please rename this column if you didn't intend it to be used for storing the inheritance class " +
1147 "or overwrite #{self.to_s}.inheritance_column to use another column for that information."
1148 end
eb2fbf0 Optimize instantiation of STI subclass records. In partial fullfilmen…
Marcel Molina authored
1149 end
1150 end
1151 else
1152 allocate
81737fc @jeremy r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
1153 end
605bc77 @dhh Added a better exception for when a type column is used in a table wi…
dhh authored
1154
db045db @dhh Initial
dhh authored
1155 object.instance_variable_set("@attributes", record)
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
1156 object.instance_variable_set("@attributes_cache", Hash.new)
55efae2 @jeremy Performance: absorb instantiate and initialize_with_callbacks into th…
jeremy authored
1157
1158 if object.respond_to_without_attributes?(:after_find)
1159 object.send(:callback, :after_find)
1160 end
1161
1162 if object.respond_to_without_attributes?(:after_initialize)
1163 object.send(:callback, :after_initialize)
1164 end
1165
81737fc @jeremy r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
1166 object
db045db @dhh Initial
dhh authored
1167 end
81737fc @jeremy r1613@asus: jeremy | 2005-07-03 07:04:53 -0700
jeremy authored
1168
c7d6d68 @jeremy Reflections don't attempt to resolve module nesting of association cl…
jeremy authored
1169 # Nest the type name in the same module as this class.
1170 # Bar is "MyApp::Business::Bar" relative to MyApp::Business::Foo
db045db @dhh Initial
dhh authored
1171 def type_name_with_module(type_name)
6400367 @seckar Fix type_name_with_module to handle type names that begin with '::'. …
seckar authored
1172 (/^::/ =~ type_name) ? type_name : "#{parent.name}::#{type_name}"
db045db @dhh Initial
dhh authored
1173 end
1174
abc895b @dhh Added new Base.find API and deprecated find_all, find_first. Added pr…
dhh authored
1175 def construct_finder_sql(options)
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1176 scope = scope(:find)
9b6207c @jeremy Quote table names. Defaults to column quoting. Closes #4593.
jeremy authored
1177 sql = "SELECT #{(scope && scope[:select]) || options[:select] || (options[:joins] && quoted_table_name + '.*') || '*'} "
1178 sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
6abda69 @dhh Added preliminary support for join models [DHH] Added preliminary sup…
dhh authored
1179
c9c1852 @dhh Making ActiveRecord faster [skaes]
dhh authored
1180 add_joins!(sql, options, scope)
1181 add_conditions!(sql, options[:conditions], scope)
6abda69 @dhh Added preliminary support for join models [DHH] Added preliminary sup…
dhh authored
1182
3566be4 @dhh Fixed that eager loading queries and with_scope should respect the :g…
dhh authored
1183 add_group!(sql, options[:group], scope)
57a3e44 @jamis make add_order a tad faster (Closes #6567)
jamis authored
1184 add_order!(sql, options[:order], scope)
c9c1852