PageRenderTime 74ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/vendor/rails/activerecord/lib/active_record/base.rb

https://github.com/brownjohnf/instiki
Ruby | 3220 lines | 1575 code | 280 blank | 1365 comment | 163 complexity | 07303c415857b83811136e83861e582c MD5 | raw file
Possible License(s): ISC, LGPL-2.1
  1. require 'yaml'
  2. require 'set'
  3. require 'active_support/core_ext/class/attribute'
  4. module ActiveRecord #:nodoc:
  5. # Generic Active Record exception class.
  6. class ActiveRecordError < StandardError
  7. end
  8. # Raised when the single-table inheritance mechanism fails to locate the subclass
  9. # (for example due to improper usage of column that +inheritance_column+ points to).
  10. class SubclassNotFound < ActiveRecordError #:nodoc:
  11. end
  12. # Raised when an object assigned to an association has an incorrect type.
  13. #
  14. # class Ticket < ActiveRecord::Base
  15. # has_many :patches
  16. # end
  17. #
  18. # class Patch < ActiveRecord::Base
  19. # belongs_to :ticket
  20. # end
  21. #
  22. # # Comments are not patches, this assignment raises AssociationTypeMismatch.
  23. # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.")
  24. class AssociationTypeMismatch < ActiveRecordError
  25. end
  26. # Raised when unserialized object's type mismatches one specified for serializable field.
  27. class SerializationTypeMismatch < ActiveRecordError
  28. end
  29. # Raised when adapter not specified on connection (or configuration file <tt>config/database.yml</tt> misses adapter field).
  30. class AdapterNotSpecified < ActiveRecordError
  31. end
  32. # Raised when Active Record cannot find database adapter specified in <tt>config/database.yml</tt> or programmatically.
  33. class AdapterNotFound < ActiveRecordError
  34. end
  35. # Raised when connection to the database could not been established (for example when <tt>connection=</tt> is given a nil object).
  36. class ConnectionNotEstablished < ActiveRecordError
  37. end
  38. # Raised when Active Record cannot find record by given id or set of ids.
  39. class RecordNotFound < ActiveRecordError
  40. end
  41. # Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be
  42. # saved because record is invalid.
  43. class RecordNotSaved < ActiveRecordError
  44. end
  45. # Raised when SQL statement cannot be executed by the database (for example, it's often the case for MySQL when Ruby driver used is too old).
  46. class StatementInvalid < ActiveRecordError
  47. end
  48. # Raised when number of bind variables in statement given to <tt>:condition</tt> key (for example, when using +find+ method)
  49. # does not match number of expected variables.
  50. #
  51. # For example, in
  52. #
  53. # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362]
  54. #
  55. # two placeholders are given but only one variable to fill them.
  56. class PreparedStatementInvalid < ActiveRecordError
  57. end
  58. # Raised on attempt to save stale record. Record is stale when it's being saved in another query after
  59. # instantiation, for example, when two users edit the same wiki page and one starts editing and saves
  60. # the page before the other.
  61. #
  62. # Read more about optimistic locking in ActiveRecord::Locking module RDoc.
  63. class StaleObjectError < ActiveRecordError
  64. end
  65. # Raised when association is being configured improperly or
  66. # user tries to use offset and limit together with has_many or has_and_belongs_to_many associations.
  67. class ConfigurationError < ActiveRecordError
  68. end
  69. # Raised on attempt to update record that is instantiated as read only.
  70. class ReadOnlyRecord < ActiveRecordError
  71. end
  72. # ActiveRecord::Transactions::ClassMethods.transaction uses this exception
  73. # to distinguish a deliberate rollback from other exceptional situations.
  74. # Normally, raising an exception will cause the +transaction+ method to rollback
  75. # the database transaction *and* pass on the exception. But if you raise an
  76. # ActiveRecord::Rollback exception, then the database transaction will be rolled back,
  77. # without passing on the exception.
  78. #
  79. # For example, you could do this in your controller to rollback a transaction:
  80. #
  81. # class BooksController < ActionController::Base
  82. # def create
  83. # Book.transaction do
  84. # book = Book.new(params[:book])
  85. # book.save!
  86. # if today_is_friday?
  87. # # The system must fail on Friday so that our support department
  88. # # won't be out of job. We silently rollback this transaction
  89. # # without telling the user.
  90. # raise ActiveRecord::Rollback, "Call tech support!"
  91. # end
  92. # end
  93. # # ActiveRecord::Rollback is the only exception that won't be passed on
  94. # # by ActiveRecord::Base.transaction, so this line will still be reached
  95. # # even on Friday.
  96. # redirect_to root_url
  97. # end
  98. # end
  99. class Rollback < ActiveRecordError
  100. end
  101. # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods).
  102. class DangerousAttributeError < ActiveRecordError
  103. end
  104. # Raised when you've tried to access a column which wasn't loaded by your finder.
  105. # Typically this is because <tt>:select</tt> has been specified.
  106. class MissingAttributeError < NoMethodError
  107. end
  108. # Raised when unknown attributes are supplied via mass assignment.
  109. class UnknownAttributeError < NoMethodError
  110. end
  111. # Raised when an error occurred while doing a mass assignment to an attribute through the
  112. # <tt>attributes=</tt> method. The exception has an +attribute+ property that is the name of the
  113. # offending attribute.
  114. class AttributeAssignmentError < ActiveRecordError
  115. attr_reader :exception, :attribute
  116. def initialize(message, exception, attribute)
  117. @exception = exception
  118. @attribute = attribute
  119. @message = message
  120. end
  121. end
  122. # Raised when there are multiple errors while doing a mass assignment through the +attributes+
  123. # method. The exception has an +errors+ property that contains an array of AttributeAssignmentError
  124. # objects, each corresponding to the error while assigning to an attribute.
  125. class MultiparameterAssignmentErrors < ActiveRecordError
  126. attr_reader :errors
  127. def initialize(errors)
  128. @errors = errors
  129. end
  130. end
  131. # Active Record objects don't specify their attributes directly, but rather infer them from the table definition with
  132. # which they're linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change
  133. # is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain
  134. # database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.
  135. #
  136. # See the mapping rules in table_name and the full example in link:files/README.html for more insight.
  137. #
  138. # == Creation
  139. #
  140. # Active Records accept constructor parameters either in a hash or as a block. The hash method is especially useful when
  141. # you're receiving the data from somewhere else, like an HTTP request. It works like this:
  142. #
  143. # user = User.new(:name => "David", :occupation => "Code Artist")
  144. # user.name # => "David"
  145. #
  146. # You can also use block initialization:
  147. #
  148. # user = User.new do |u|
  149. # u.name = "David"
  150. # u.occupation = "Code Artist"
  151. # end
  152. #
  153. # And of course you can just create a bare object and specify the attributes after the fact:
  154. #
  155. # user = User.new
  156. # user.name = "David"
  157. # user.occupation = "Code Artist"
  158. #
  159. # == Conditions
  160. #
  161. # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement.
  162. # The array form is to be used when the condition input is tainted and requires sanitization. The string form can
  163. # be used for statements that don't involve tainted data. The hash form works much like the array form, except
  164. # only equality and range is possible. Examples:
  165. #
  166. # class User < ActiveRecord::Base
  167. # def self.authenticate_unsafely(user_name, password)
  168. # find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'")
  169. # end
  170. #
  171. # def self.authenticate_safely(user_name, password)
  172. # find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ])
  173. # end
  174. #
  175. # def self.authenticate_safely_simply(user_name, password)
  176. # find(:first, :conditions => { :user_name => user_name, :password => password })
  177. # end
  178. # end
  179. #
  180. # The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query and is thus susceptible to SQL-injection
  181. # attacks if the <tt>user_name</tt> and +password+ parameters come directly from an HTTP request. The <tt>authenticate_safely</tt> and
  182. # <tt>authenticate_safely_simply</tt> both will sanitize the <tt>user_name</tt> and +password+ before inserting them in the query,
  183. # which will ensure that an attacker can't escape the query and fake the login (or worse).
  184. #
  185. # When using multiple parameters in the conditions, it can easily become hard to read exactly what the fourth or fifth
  186. # question mark is supposed to represent. In those cases, you can resort to named bind variables instead. That's done by replacing
  187. # the question marks with symbols and supplying a hash with values for the matching symbol keys:
  188. #
  189. # Company.find(:first, :conditions => [
  190. # "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
  191. # { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' }
  192. # ])
  193. #
  194. # Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND
  195. # operator. For instance:
  196. #
  197. # Student.find(:all, :conditions => { :first_name => "Harvey", :status => 1 })
  198. # Student.find(:all, :conditions => params[:student])
  199. #
  200. # A range may be used in the hash to use the SQL BETWEEN operator:
  201. #
  202. # Student.find(:all, :conditions => { :grade => 9..12 })
  203. #
  204. # An array may be used in the hash to use the SQL IN operator:
  205. #
  206. # Student.find(:all, :conditions => { :grade => [9,11,12] })
  207. #
  208. # == Overwriting default accessors
  209. #
  210. # All column values are automatically available through basic accessors on the Active Record object, but sometimes you
  211. # want to specialize this behavior. This can be done by overwriting the default accessors (using the same
  212. # name as the attribute) and calling <tt>read_attribute(attr_name)</tt> and <tt>write_attribute(attr_name, value)</tt> to actually change things.
  213. # Example:
  214. #
  215. # class Song < ActiveRecord::Base
  216. # # Uses an integer of seconds to hold the length of the song
  217. #
  218. # def length=(minutes)
  219. # write_attribute(:length, minutes.to_i * 60)
  220. # end
  221. #
  222. # def length
  223. # read_attribute(:length) / 60
  224. # end
  225. # end
  226. #
  227. # You can alternatively use <tt>self[:attribute]=(value)</tt> and <tt>self[:attribute]</tt> instead of <tt>write_attribute(:attribute, value)</tt> and
  228. # <tt>read_attribute(:attribute)</tt> as a shorter form.
  229. #
  230. # == Attribute query methods
  231. #
  232. # In addition to the basic accessors, query methods are also automatically available on the Active Record object.
  233. # Query methods allow you to test whether an attribute value is present.
  234. #
  235. # For example, an Active Record User with the <tt>name</tt> attribute has a <tt>name?</tt> method that you can call
  236. # to determine whether the user has a name:
  237. #
  238. # user = User.new(:name => "David")
  239. # user.name? # => true
  240. #
  241. # anonymous = User.new(:name => "")
  242. # anonymous.name? # => false
  243. #
  244. # == Accessing attributes before they have been typecasted
  245. #
  246. # Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first.
  247. # That can be done by using the <tt><attribute>_before_type_cast</tt> accessors that all attributes have. For example, if your Account model
  248. # has a <tt>balance</tt> attribute, you can call <tt>account.balance_before_type_cast</tt> or <tt>account.id_before_type_cast</tt>.
  249. #
  250. # This is especially useful in validation situations where the user might supply a string for an integer field and you want to display
  251. # the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you
  252. # want.
  253. #
  254. # == Dynamic attribute-based finders
  255. #
  256. # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by
  257. # appending the name of an attribute to <tt>find_by_</tt>, <tt>find_last_by_</tt>, or <tt>find_all_by_</tt>, so you get finders like <tt>Person.find_by_user_name</tt>,
  258. # <tt>Person.find_all_by_last_name</tt>, and <tt>Payment.find_by_transaction_id</tt>. So instead of writing
  259. # <tt>Person.find(:first, :conditions => ["user_name = ?", user_name])</tt>, you just do <tt>Person.find_by_user_name(user_name)</tt>.
  260. # And instead of writing <tt>Person.find(:all, :conditions => ["last_name = ?", last_name])</tt>, you just do <tt>Person.find_all_by_last_name(last_name)</tt>.
  261. #
  262. # It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders like
  263. # <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
  264. # <tt>Person.find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password])</tt>, you just do
  265. # <tt>Person.find_by_user_name_and_password(user_name, password)</tt>.
  266. #
  267. # It's even possible to use all the additional parameters to find. For example, the full interface for <tt>Payment.find_all_by_amount</tt>
  268. # is actually <tt>Payment.find_all_by_amount(amount, options)</tt>. And the full interface to <tt>Person.find_by_user_name</tt> is
  269. # actually <tt>Person.find_by_user_name(user_name, options)</tt>. So you could call <tt>Payment.find_all_by_amount(50, :order => "created_on")</tt>.
  270. # Also you may call <tt>Payment.find_last_by_amount(amount, options)</tt> returning the last record matching that amount and options.
  271. #
  272. # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with
  273. # <tt>find_or_create_by_</tt> and will return the object if it already exists and otherwise creates it, then returns it. Protected attributes won't be set unless they are given in a block. For example:
  274. #
  275. # # No 'Summer' tag exists
  276. # Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")
  277. #
  278. # # Now the 'Summer' tag does exist
  279. # Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
  280. #
  281. # # Now 'Bob' exist and is an 'admin'
  282. # User.find_or_create_by_name('Bob', :age => 40) { |u| u.admin = true }
  283. #
  284. # Use the <tt>find_or_initialize_by_</tt> finder if you want to return a new record without saving it first. Protected attributes won't be set unless they are given in a block. For example:
  285. #
  286. # # No 'Winter' tag exists
  287. # winter = Tag.find_or_initialize_by_name("Winter")
  288. # winter.new_record? # true
  289. #
  290. # To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of
  291. # a list of parameters. For example:
  292. #
  293. # Tag.find_or_create_by_name(:name => "rails", :creator => current_user)
  294. #
  295. # That will either find an existing tag named "rails", or create a new one while setting the user that created it.
  296. #
  297. # == Saving arrays, hashes, and other non-mappable objects in text columns
  298. #
  299. # 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+.
  300. # This makes it possible to store arrays, hashes, and other non-mappable objects without doing any additional work. Example:
  301. #
  302. # class User < ActiveRecord::Base
  303. # serialize :preferences
  304. # end
  305. #
  306. # user = User.create(:preferences => { "background" => "black", "display" => large })
  307. # User.find(user.id).preferences # => { "background" => "black", "display" => large }
  308. #
  309. # You can also specify a class option as the second parameter that'll raise an exception if a serialized object is retrieved as a
  310. # descendant of a class not in the hierarchy. Example:
  311. #
  312. # class User < ActiveRecord::Base
  313. # serialize :preferences, Hash
  314. # end
  315. #
  316. # user = User.create(:preferences => %w( one two three ))
  317. # User.find(user.id).preferences # raises SerializationTypeMismatch
  318. #
  319. # == Single table inheritance
  320. #
  321. # Active Record allows inheritance by storing the name of the class in a column that by default is named "type" (can be changed
  322. # by overwriting <tt>Base.inheritance_column</tt>). This means that an inheritance looking like this:
  323. #
  324. # class Company < ActiveRecord::Base; end
  325. # class Firm < Company; end
  326. # class Client < Company; end
  327. # class PriorityClient < Client; end
  328. #
  329. # When you do <tt>Firm.create(:name => "37signals")</tt>, this record will be saved in the companies table with type = "Firm". You can then
  330. # fetch this row again using <tt>Company.find(:first, "name = '37signals'")</tt> and it will return a Firm object.
  331. #
  332. # 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
  333. # like normal subclasses with no special magic for differentiating between them or reloading the right type with find.
  334. #
  335. # Note, all the attributes for all the cases are kept in the same table. Read more:
  336. # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
  337. #
  338. # == Connection to multiple databases in different models
  339. #
  340. # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection.
  341. # All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection.
  342. # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say <tt>Course.establish_connection</tt>
  343. # and Course and all of its subclasses will use this connection instead.
  344. #
  345. # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is
  346. # requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool.
  347. #
  348. # == Exceptions
  349. #
  350. # * ActiveRecordError - Generic error class and superclass of all other errors raised by Active Record.
  351. # * AdapterNotSpecified - The configuration hash used in <tt>establish_connection</tt> didn't include an
  352. # <tt>:adapter</tt> key.
  353. # * AdapterNotFound - The <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified a non-existent adapter
  354. # (or a bad spelling of an existing one).
  355. # * AssociationTypeMismatch - The object assigned to the association wasn't of the type specified in the association definition.
  356. # * SerializationTypeMismatch - The serialized object wasn't of the class specified as the second parameter.
  357. # * ConnectionNotEstablished+ - No connection has been established. Use <tt>establish_connection</tt> before querying.
  358. # * RecordNotFound - No record responded to the +find+ method. Either the row with the given ID doesn't exist
  359. # or the row didn't meet the additional restrictions. Some +find+ calls do not raise this exception to signal
  360. # nothing was found, please check its documentation for further details.
  361. # * StatementInvalid - The database server rejected the SQL statement. The precise error is added in the message.
  362. # * MultiparameterAssignmentErrors - Collection of errors that occurred during a mass assignment using the
  363. # <tt>attributes=</tt> method. The +errors+ property of this exception contains an array of AttributeAssignmentError
  364. # objects that should be inspected to determine which attributes triggered the errors.
  365. # * AttributeAssignmentError - An error occurred while doing a mass assignment through the <tt>attributes=</tt> method.
  366. # You can inspect the +attribute+ property of the exception object to determine which attribute triggered the error.
  367. #
  368. # *Note*: The attributes listed are class-level attributes (accessible from both the class and instance level).
  369. # So it's possible to assign a logger to the class through <tt>Base.logger=</tt> which will then be used by all
  370. # instances in the current object space.
  371. class Base
  372. ##
  373. # :singleton-method:
  374. # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then passed
  375. # on to any new database connections made and which can be retrieved on both a class and instance level by calling +logger+.
  376. cattr_accessor :logger, :instance_writer => false
  377. def self.inherited(child) #:nodoc:
  378. @@subclasses[self] ||= []
  379. @@subclasses[self] << child
  380. super
  381. end
  382. def self.reset_subclasses #:nodoc:
  383. nonreloadables = []
  384. subclasses.each do |klass|
  385. unless ActiveSupport::Dependencies.autoloaded? klass
  386. nonreloadables << klass
  387. next
  388. end
  389. klass.instance_variables.each { |var| klass.send(:remove_instance_variable, var) }
  390. klass.instance_methods(false).each { |m| klass.send :undef_method, m }
  391. end
  392. @@subclasses = {}
  393. nonreloadables.each { |klass| (@@subclasses[klass.superclass] ||= []) << klass }
  394. end
  395. @@subclasses = {}
  396. ##
  397. # :singleton-method:
  398. # Contains the database configuration - as is typically stored in config/database.yml -
  399. # as a Hash.
  400. #
  401. # For example, the following database.yml...
  402. #
  403. # development:
  404. # adapter: sqlite3
  405. # database: db/development.sqlite3
  406. #
  407. # production:
  408. # adapter: sqlite3
  409. # database: db/production.sqlite3
  410. #
  411. # ...would result in ActiveRecord::Base.configurations to look like this:
  412. #
  413. # {
  414. # 'development' => {
  415. # 'adapter' => 'sqlite3',
  416. # 'database' => 'db/development.sqlite3'
  417. # },
  418. # 'production' => {
  419. # 'adapter' => 'sqlite3',
  420. # 'database' => 'db/production.sqlite3'
  421. # }
  422. # }
  423. cattr_accessor :configurations, :instance_writer => false
  424. @@configurations = {}
  425. ##
  426. # :singleton-method:
  427. # Accessor for the prefix type that will be prepended to every primary key column name. The options are :table_name and
  428. # :table_name_with_underscore. If the first is specified, the Product class will look for "productid" instead of "id" as
  429. # the primary column. If the latter is specified, the Product class will look for "product_id" instead of "id". Remember
  430. # that this is a global setting for all Active Records.
  431. cattr_accessor :primary_key_prefix_type, :instance_writer => false
  432. @@primary_key_prefix_type = nil
  433. ##
  434. # :singleton-method:
  435. # Accessor for the name of the prefix string to prepend to every table name. So if set to "basecamp_", all
  436. # table names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient way of creating a namespace
  437. # for tables in a shared database. By default, the prefix is the empty string.
  438. #
  439. # If you are organising your models within modules you can add a prefix to the models within a namespace by defining
  440. # a singleton method in the parent module called table_name_prefix which returns your chosen prefix.
  441. cattr_accessor :table_name_prefix, :instance_writer => false
  442. @@table_name_prefix = ""
  443. ##
  444. # :singleton-method:
  445. # Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
  446. # "people_basecamp"). By default, the suffix is the empty string.
  447. cattr_accessor :table_name_suffix, :instance_writer => false
  448. @@table_name_suffix = ""
  449. ##
  450. # :singleton-method:
  451. # Indicates whether table names should be the pluralized versions of the corresponding class names.
  452. # If true, the default table name for a Product class will be +products+. If false, it would just be +product+.
  453. # See table_name for the full rules on table/class naming. This is true, by default.
  454. cattr_accessor :pluralize_table_names, :instance_writer => false
  455. @@pluralize_table_names = true
  456. ##
  457. # :singleton-method:
  458. # Determines whether to use ANSI codes to colorize the logging statements committed by the connection adapter. These colors
  459. # make it much easier to overview things during debugging (when used through a reader like +tail+ and on a black background), but
  460. # may complicate matters if you use software like syslog. This is true, by default.
  461. cattr_accessor :colorize_logging, :instance_writer => false
  462. @@colorize_logging = true
  463. ##
  464. # :singleton-method:
  465. # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling dates and times from the database.
  466. # This is set to :local by default.
  467. cattr_accessor :default_timezone, :instance_writer => false
  468. @@default_timezone = :local
  469. ##
  470. # :singleton-method:
  471. # Specifies the format to use when dumping the database schema with Rails'
  472. # Rakefile. If :sql, the schema is dumped as (potentially database-
  473. # specific) SQL statements. If :ruby, the schema is dumped as an
  474. # ActiveRecord::Schema file which can be loaded into any database that
  475. # supports migrations. Use :ruby if you want to have different database
  476. # adapters for, e.g., your development and test environments.
  477. cattr_accessor :schema_format , :instance_writer => false
  478. @@schema_format = :ruby
  479. ##
  480. # :singleton-method:
  481. # Specify whether or not to use timestamps for migration numbers
  482. cattr_accessor :timestamped_migrations , :instance_writer => false
  483. @@timestamped_migrations = true
  484. # Determine whether to store the full constant name including namespace when using STI
  485. class_attribute :store_full_sti_class
  486. self.store_full_sti_class = false
  487. # Stores the default scope for the class
  488. class_inheritable_accessor :default_scoping, :instance_writer => false
  489. self.default_scoping = []
  490. class << self # Class methods
  491. # Find operates with four different retrieval approaches:
  492. #
  493. # * 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]).
  494. # If no record can be found for all of the listed ids, then RecordNotFound will be raised.
  495. # * Find first - This will return the first record matched by the options used. These options can either be specific
  496. # conditions or merely an order. If no record can be matched, +nil+ is returned. Use
  497. # <tt>Model.find(:first, *args)</tt> or its shortcut <tt>Model.first(*args)</tt>.
  498. # * Find last - This will return the last record matched by the options used. These options can either be specific
  499. # conditions or merely an order. If no record can be matched, +nil+ is returned. Use
  500. # <tt>Model.find(:last, *args)</tt> or its shortcut <tt>Model.last(*args)</tt>.
  501. # * Find all - This will return all the records matched by the options used.
  502. # If no records are found, an empty array is returned. Use
  503. # <tt>Model.find(:all, *args)</tt> or its shortcut <tt>Model.all(*args)</tt>.
  504. #
  505. # All approaches accept an options hash as their last parameter.
  506. #
  507. # ==== Parameters
  508. #
  509. # * <tt>:conditions</tt> - An SQL fragment like "administrator = 1", <tt>[ "user_name = ?", username ]</tt>, or <tt>["user_name = :user_name", { :user_name => user_name }]</tt>. See conditions in the intro.
  510. # * <tt>:order</tt> - An SQL fragment like "created_at DESC, name".
  511. # * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
  512. # * <tt>:having</tt> - Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt> returns. Uses the <tt>HAVING</tt> SQL-clause.
  513. # * <tt>:limit</tt> - An integer determining the limit on the number of rows that should be returned.
  514. # * <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.
  515. # * <tt>:joins</tt> - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed),
  516. # named associations in the same form used for the <tt>:include</tt> option, which will perform an <tt>INNER JOIN</tt> on the associated table(s),
  517. # or an array containing a mixture of both strings and named associations.
  518. # If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns.
  519. # Pass <tt>:readonly => false</tt> to override.
  520. # * <tt>:include</tt> - Names associations that should be loaded alongside. The symbols named refer
  521. # to already defined associations. See eager loading under Associations.
  522. # * <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
  523. # include the joined columns. Takes a string with the SELECT SQL fragment (e.g. "id, name").
  524. # * <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
  525. # of a database view).
  526. # * <tt>:readonly</tt> - Mark the returned records read-only so they cannot be saved or updated.
  527. # * <tt>:lock</tt> - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE".
  528. # <tt>:lock => true</tt> gives connection's default exclusive lock, usually "FOR UPDATE".
  529. #
  530. # ==== Examples
  531. #
  532. # # find by id
  533. # Person.find(1) # returns the object for ID = 1
  534. # Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
  535. # Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
  536. # Person.find([1]) # returns an array for the object with ID = 1
  537. # Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC")
  538. #
  539. # Note that returned records may not be in the same order as the ids you
  540. # provide since database rows are unordered. Give an explicit <tt>:order</tt>
  541. # to ensure the results are sorted.
  542. #
  543. # ==== Examples
  544. #
  545. # # find first
  546. # Person.find(:first) # returns the first object fetched by SELECT * FROM people
  547. # Person.find(:first, :conditions => [ "user_name = ?", user_name])
  548. # Person.find(:first, :conditions => [ "user_name = :u", { :u => user_name }])
  549. # Person.find(:first, :order => "created_on DESC", :offset => 5)
  550. #
  551. # # find last
  552. # Person.find(:last) # returns the last object fetched by SELECT * FROM people
  553. # Person.find(:last, :conditions => [ "user_name = ?", user_name])
  554. # Person.find(:last, :order => "created_on DESC", :offset => 5)
  555. #
  556. # # find all
  557. # Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people
  558. # Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50)
  559. # Person.find(:all, :conditions => { :friends => ["Bob", "Steve", "Fred"] }
  560. # Person.find(:all, :offset => 10, :limit => 10)
  561. # Person.find(:all, :include => [ :account, :friends ])
  562. # Person.find(:all, :group => "category")
  563. #
  564. # Example for find with a lock: Imagine two concurrent transactions:
  565. # each will read <tt>person.visits == 2</tt>, add 1 to it, and save, resulting
  566. # in two saves of <tt>person.visits = 3</tt>. By locking the row, the second
  567. # transaction has to wait until the first is finished; we get the
  568. # expected <tt>person.visits == 4</tt>.
  569. #
  570. # Person.transaction do
  571. # person = Person.find(1, :lock => true)
  572. # person.visits += 1
  573. # person.save!
  574. # end
  575. def find(*args)
  576. options = args.extract_options!
  577. validate_find_options(options)
  578. set_readonly_option!(options)
  579. case args.first
  580. when :first then find_initial(options)
  581. when :last then find_last(options)
  582. when :all then find_every(options)
  583. else find_from_ids(args, options)
  584. end
  585. end
  586. # A convenience wrapper for <tt>find(:first, *args)</tt>. You can pass in all the
  587. # same arguments to this method as you can to <tt>find(:first)</tt>.
  588. def first(*args)
  589. find(:first, *args)
  590. end
  591. # A convenience wrapper for <tt>find(:last, *args)</tt>. You can pass in all the
  592. # same arguments to this method as you can to <tt>find(:last)</tt>.
  593. def last(*args)
  594. find(:last, *args)
  595. end
  596. # This is an alias for find(:all). You can pass in all the same arguments to this method as you can
  597. # to find(:all)
  598. def all(*args)
  599. find(:all, *args)
  600. end
  601. # Executes a custom SQL query against your database and returns all the results. The results will
  602. # be returned as an array with columns requested encapsulated as attributes of the model you call
  603. # this method from. If you call <tt>Product.find_by_sql</tt> then the results will be returned in
  604. # a Product object with the attributes you specified in the SQL query.
  605. #
  606. # If you call a complicated SQL query which spans multiple tables the columns specified by the
  607. # SELECT will be attributes of the model, whether or not they are columns of the corresponding
  608. # table.
  609. #
  610. # The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be
  611. # no database agnostic conversions performed. This should be a last resort because using, for example,
  612. # MySQL specific terms will lock you to using that particular database engine or require you to
  613. # change your call if you switch engines.
  614. #
  615. # ==== Examples
  616. # # A simple SQL query spanning multiple tables
  617. # Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
  618. # > [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
  619. #
  620. # # You can use the same string replacement techniques as you can with ActiveRecord#find
  621. # Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
  622. # > [#<Post:0x36bff9c @attributes={"first_name"=>"The Cheap Man Buys Twice"}>, ...]
  623. def find_by_sql(sql)
  624. connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) }
  625. end
  626. # Returns true if a record exists in the table that matches the +id+ or
  627. # conditions given, or false otherwise. The argument can take five forms:
  628. #
  629. # * Integer - Finds the record with this primary key.
  630. # * String - Finds the record with a primary key corresponding to this
  631. # string (such as <tt>'5'</tt>).
  632. # * Array - Finds the record that matches these +find+-style conditions
  633. # (such as <tt>['color = ?', 'red']</tt>).
  634. # * Hash - Finds the record that matches these +find+-style conditions
  635. # (such as <tt>{:color => 'red'}</tt>).
  636. # * No args - Returns false if the table is empty, true otherwise.
  637. #
  638. # For more information about specifying conditions as a Hash or Array,
  639. # see the Conditions section in the introduction to ActiveRecord::Base.
  640. #
  641. # Note: You can't pass in a condition as a string (like <tt>name =
  642. # 'Jamie'</tt>), since it would be sanitized and then queried against
  643. # the primary key column, like <tt>id = 'name = \'Jamie\''</tt>.
  644. #
  645. # ==== Examples
  646. # Person.exists?(5)
  647. # Person.exists?('5')
  648. # Person.exists?(:name => "David")
  649. # Person.exists?(['name LIKE ?', "%#{query}%"])
  650. # Person.exists?
  651. def exists?(id_or_conditions = {})
  652. find_initial(
  653. :select => "#{quoted_table_name}.#{primary_key}",
  654. :conditions => expand_id_conditions(id_or_conditions)) ? true : false
  655. end
  656. # Creates an object (or multiple objects) and saves it to the database, if validations pass.
  657. # The resulting object is returned whether the object was saved successfully to the database or not.
  658. #
  659. # The +attributes+ parameter can be either be a Hash or an Array of Hashes. These Hashes describe the
  660. # attributes on the objects that are to be created.
  661. #
  662. # ==== Examples
  663. # # Create a single new object
  664. # User.create(:first_name => 'Jamie')
  665. #
  666. # # Create an Array of new objects
  667. # User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }])
  668. #
  669. # # Create a single object and pass it into a block to set other attributes.
  670. # User.create(:first_name => 'Jamie') do |u|
  671. # u.is_admin = false
  672. # end
  673. #
  674. # # Creating an Array of new objects using a block, where the block is executed for each object:
  675. # User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u|
  676. # u.is_admin = false
  677. # end
  678. def create(attributes = nil, &block)
  679. if attributes.is_a?(Array)
  680. attributes.collect { |attr| create(attr, &block) }
  681. else
  682. object = new(attributes)
  683. yield(object) if block_given?
  684. object.save
  685. object
  686. end
  687. end
  688. # Updates an object (or multiple objects) and saves it to the database, if validations pass.
  689. # The resulting object is returned whether the object was saved successfully to the database or not.
  690. #
  691. # ==== Parameters
  692. #
  693. # * +id+ - This should be the id or an array of ids to be updated.
  694. # * +attributes+ - This should be a hash of attributes to be set on the object, or an array of hashes.
  695. #
  696. # ==== Examples
  697. #
  698. # # Updating one record:
  699. # Person.update(15, :user_name => 'Samuel', :group => 'expert')
  700. #
  701. # # Updating multiple records:
  702. # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
  703. # Person.update(people.keys, people.values)
  704. def update(id, attributes)
  705. if id.is_a?(Array)
  706. idx = -1
  707. id.collect { |one_id| idx += 1; update(one_id, attributes[idx]) }
  708. else
  709. object = find(id)
  710. object.update_attributes(attributes)
  711. object
  712. end
  713. end
  714. # Deletes the row with a primary key matching the +id+ argument, using a
  715. # SQL +DELETE+ statement, and returns the number of rows deleted. Active
  716. # Record objects are not instantiated, so the object's callbacks are not
  717. # executed, including any <tt>:dependent</tt> association options or
  718. # Observer methods.
  719. #
  720. # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
  721. #
  722. # Note: Although it is often much faster than the alternative,
  723. # <tt>#destroy</tt>, skipping callbacks might bypass business logic in
  724. # your application that ensures referential integrity or performs other
  725. # essential jobs.
  726. #
  727. # ==== Examples
  728. #
  729. # # Delete a single row
  730. # Todo.delete(1)
  731. #
  732. # # Delete multiple rows
  733. # Todo.delete([2,3,4])
  734. def delete(id)
  735. delete_all([ "#{connection.quote_column_name(primary_key)} IN (?)", id ])
  736. end
  737. # Destroy an object (or multiple objects) that has the given id, the object is instantiated first,
  738. # therefore all callbacks and filters are fired off before the object is deleted. This method is
  739. # less efficient than ActiveRecord#delete but allows cleanup methods and other actions to be run.
  740. #
  741. # This essentially finds the object (or multiple objects) with the given id, creates a new object
  742. # from the attributes, and then calls destroy on it.
  743. #
  744. # ==== Parameters
  745. #
  746. # * +id+ - Can be either an Integer or an Array of Integers.
  747. #
  748. # ==== Examples
  749. #
  750. # # Destroy a single object
  751. # Todo.destroy(1)
  752. #
  753. # # Destroy multiple objects
  754. # todos = [1,2,3]
  755. # Todo.destroy(todos)
  756. def destroy(id)
  757. if id.is_a?(Array)
  758. id.map { |one_id| destroy(one_id) }
  759. else
  760. find(id).destroy
  761. end
  762. end
  763. # Updates all records with details given if they match a set of conditions supplied, limits and order can
  764. # also be supplied. This method constructs a single SQL UPDATE statement and sends it straight to the
  765. # database. It does not instantiate the involved models and it does not trigger Active Record callbacks.
  766. #
  767. # ==== Parameters
  768. #
  769. # * +updates+ - A string of column and value pairs that will be set on any records that match conditions. This creates the SET clause of the generated SQL.
  770. # * +conditions+ - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro for more info.
  771. # * +options+ - Additional options are <tt>:limit</tt> and <tt>:order</tt>, see the examples for usage.
  772. #
  773. # ==== Examples
  774. #
  775. # # Update all billing objects with the 3 different attributes given
  776. # Billing.update_all( "category = 'authorized', approved = 1, author = 'David'" )
  777. #
  778. # # Update records that match our conditions
  779. # Billing.update_all( "author = 'David'", "title LIKE '%Rails%'" )
  780. #
  781. # # Update records that match our conditions but limit it to 5 ordered by date
  782. # Billing.update_all( "author = 'David'", "title LIKE '%Rails%'",
  783. # :order => 'created_at', :limit => 5 )
  784. def update_all(updates, conditions = nil, options = {})
  785. sql = "UPDATE #{quoted_table_name} SET #{sanitize_sql_for_assignment(updates)} "
  786. scope = scope(:find)
  787. select_sql = ""
  788. add_conditions!(select_sql, conditions, scope)
  789. if options.has_key?(:limit) || (scope && scope[:limit])
  790. # Only take order from scope if limit is also provided by scope, this
  791. # is useful for updating a has_many association with a limit.
  792. add_order!(select_sql, options[:order], scope)
  793. add_limit!(select_sql, options, scope)
  794. sql.concat(connection.limited_update_conditions(select_sql, quoted_table_name, connection.quote_column_name(primary_key)))
  795. else
  796. add_order!(select_sql, options[:order], nil)
  797. sql.concat(select_sql)
  798. end
  799. connection.update(sql, "#{name} Update")
  800. end
  801. # Destroys the records matching +conditions+ by instantiating each
  802. # record and calling its +destroy+ method. Each object's callbacks are
  803. # executed (including <tt>:dependent</tt> association options and
  804. # +before_destroy+/+after_destroy+ Observer methods). Returns the
  805. # collection of objects that were destroyed; each will be frozen, to
  806. # reflect that no changes should be made (since they can't be
  807. # persisted).
  808. #
  809. # Note: Instantiation, callback execution, and deletion of each
  810. # record can be time consuming when you're removing many records at
  811. # once. It generates at least one SQL +DELETE+ query per record (or
  812. # possibly more, to enforce your callbacks). If you want to delete many
  813. # rows quickly, without concern for their associations or callbacks, use
  814. # +delete_all+ instead.
  815. #
  816. # ==== Parameters
  817. #
  818. # * +conditions+ - A string, array, or hash that specifies which records
  819. # to destroy. If omitted, all records are destroyed. See the
  820. # Conditions section in the introduction to ActiveRecord::Base for
  821. # more information.
  822. #
  823. # ==== Examples
  824. #
  825. # Person.destroy_all("last_login < '2004-04-04'")
  826. # Person.destroy_all(:status => "inactive")
  827. def destroy_all(conditions = nil)
  828. find(:all, :conditions => conditions).each { |object| object.destroy }
  829. end
  830. # Deletes the records matching +conditions+ without instantiating the records first, and hence not
  831. # calling the +destroy+ method nor invoking callbacks. This is a single SQL DELETE statement that
  832. # goes straight to the database, much more efficient than +destroy_all+. Be careful with relations
  833. # though, in particular <tt>:dependent</tt> rules defined on associations are not honored. Returns
  834. # the number of rows affected.
  835. #
  836. # ==== Parameters
  837. #
  838. # * +conditions+ - Conditions are specified the same way as with +find+ method.
  839. #
  840. # ==== Example
  841. #
  842. # Post.delete_all("person_id = 5 AND (category = 'Something' OR category = 'Else')")
  843. # Post.delete_all(["person_id = ? AND (category = ? OR category = ?)", 5, 'Something', 'Else'])
  844. #
  845. # Both calls delete the affected posts all at once with a single DELETE statement. If you need to destroy dependent
  846. # associations or call your <tt>before_*</tt> or +after_destroy+ callbacks, use the +destroy_all+ method instead.
  847. def delete_all(conditions = nil)
  848. sql = "DELETE FROM #{quoted_table_name} "
  849. add_conditions!(sql, conditions, scope(:find))
  850. connection.delete(sql, "#{name} Delete all")
  851. end
  852. # Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
  853. # The use of this method should be restricted to complicated SQL queries that can't be executed
  854. # using the ActiveRecord::Calculations class methods. Look into those before using this.
  855. #
  856. # ==== Parameters
  857. #
  858. # * +sql+ - An SQL statement which should return a count query from the database, see the example below.
  859. #
  860. # ==== Examples
  861. #
  862. # Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
  863. def count_by_sql(sql)
  864. sql = sanitize_conditions(sql)
  865. connection.select_value(sql, "#{name} Count").to_i
  866. end
  867. # Resets one or more counter caches to their correct value using an SQL
  868. # count query. This is useful when adding new counter caches, or if the
  869. # counter has been corrupted or modified directly by SQL.
  870. #
  871. # ==== Parameters
  872. #
  873. # * +id+ - The id of the object you wish to reset a counter on.
  874. # * +counters+ - One or more counter names to reset
  875. #
  876. # ==== Examples
  877. #
  878. # # For Post with id #1 records reset the comments_count
  879. # Post.reset_counters(1, :comments)
  880. def reset_counters(id, *counters)
  881. object = find(id)
  882. counters.each do |association|
  883. child_class = reflect_on_association(association.to_sym).klass
  884. belongs_name = self.name.demodulize.underscore.to_sym
  885. counter_name = child_class.reflect_on_association(belongs_name).counter_cache_column
  886. value = object.send(association).count
  887. connection.update(<<-CMD, "#{name} UPDATE")
  888. UPDATE #{quoted_table_name}
  889. SET #{connection.quote_column_name(counter_name)} = #{value}
  890. WHERE #{connection.quote_column_name(primary_key)} = #{quote_value(object.id)}
  891. CMD
  892. end
  893. return true
  894. end
  895. # A generic "counter updater" implementation, intended primarily to be
  896. # used by increment_counter and decrement_counter, but which may also
  897. # be useful on its own. It simply does a direct SQL update for the record
  898. # with the given ID, altering the given hash of counters by the amount
  899. # given by the corresponding value:
  900. #
  901. # ==== Parameters
  902. #
  903. # * +id+ - The id of the object you wish to update a counter on or an Array of ids.
  904. # * +counters+ - An Array of Hashes containing the names of the fields
  905. # to update as keys and the amount to update the field by as values.
  906. #
  907. # ==== Examples
  908. #
  909. # # For the Post with id of 5, decrement the comment_count by 1, and
  910. # # increment the action_count by 1
  911. # Post.update_counters 5, :comment_count => -1, :action_count => 1
  912. # # Executes the following SQL:
  913. # # UPDATE posts
  914. # # SET comment_count = comment_count - 1,
  915. # # action_count = action_count + 1
  916. # # WHERE id = 5
  917. #
  918. # # For the Posts with id of 10 and 15, increment the comment_count by 1
  919. # Post.update_counters [10, 15], :comment_count => 1
  920. # # Executes the following SQL:
  921. # # UPDATE posts
  922. # # SET comment_count = comment_count + 1,
  923. # # WHERE id IN (10, 15)
  924. def update_counters(id, counters)
  925. updates = counters.map do |counter_name, value|
  926. operator = value < 0 ? '-' : '+'
  927. quoted_column = connection.quote_column_name(counter_name)
  928. "#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
  929. end
  930. update_all(updates.join(', '), primary_key => id )
  931. end
  932. # Increment a number field by one, usually representing a count.
  933. #
  934. # This is used for caching aggregate values, so that they don't need to be computed every time.
  935. # For example, a DiscussionBoard may cache post_count and comment_count otherwise every time the board is
  936. # shown it would have to run an SQL query to find how many posts and comments there are.
  937. #
  938. # ==== Parameters
  939. #
  940. # * +counter_name+ - The name of the field that should be incremented.
  941. # * +id+ - The id of the object that should be incremented.
  942. #
  943. # ==== Examples
  944. #
  945. # # Increment the post_count column for the record with an id of 5
  946. # DiscussionBoard.increment_counter(:post_count, 5)
  947. def increment_counter(counter_name, id)
  948. update_counters(id, counter_name => 1)
  949. end
  950. # Decrement a number field by one, usually representing a count.
  951. #
  952. # This works the same as increment_counter but reduces the column value by 1 instead of increasing it.
  953. #
  954. # ==== Parameters
  955. #
  956. # * +counter_name+ - The name of the field that should be decremented.
  957. # * +id+ - The id of the object that should be decremented.
  958. #
  959. # ==== Examples
  960. #
  961. # # Decrement the post_count column for the record with an id of 5
  962. # DiscussionBoard.decrement_counter(:post_count, 5)
  963. def decrement_counter(counter_name, id)
  964. update_counters(id, counter_name => -1)
  965. end
  966. # Attributes named in this macro are protected from mass-assignment,
  967. # such as <tt>new(attributes)</tt>,
  968. # <tt>update_attributes(attributes)</tt>, or
  969. # <tt>attributes=(attributes)</tt>.
  970. #
  971. # Mass-assignment to these attributes will simply be ignored, to assign
  972. # to them you can use direct writer methods. This is meant to protect
  973. # sensitive attributes from being overwritten by malicious users
  974. # tampering with URLs or forms.
  975. #
  976. # class Customer < ActiveRecord::Base
  977. # attr_protected :credit_rating
  978. # end
  979. #
  980. # customer = Customer.new("name" => David, "credit_rating" => "Excellent")
  981. # customer.credit_rating # => nil
  982. # customer.attributes = { "description" => "Jolly fellow", "credit_rating" => "Superb" }
  983. # customer.credit_rating # => nil
  984. #
  985. # customer.credit_rating = "Average"
  986. # customer.credit_rating # => "Average"
  987. #
  988. # To start from an all-closed default and enable attributes as needed,
  989. # have a look at +attr_accessible+.
  990. def attr_protected(*attributes)
  991. write_inheritable_attribute(:attr_protected, Set.new(attributes.map(&:to_s)) + (protected_attributes || []))
  992. end
  993. # Returns an array of all the attributes that have been protected from mass-assignment.
  994. def protected_attributes # :nodoc:
  995. read_inheritable_attribute(:attr_protected)
  996. end
  997. # Specifies a white list of model attributes that can be set via
  998. # mass-assignment, such as <tt>new(attributes)</tt>,
  999. # <tt>update_attributes(attributes)</tt>, or
  1000. # <tt>attributes=(attributes)</tt>
  1001. #
  1002. # This is the opposite of the +attr_protected+ macro: Mass-assignment
  1003. # will only set attributes in this list, to assign to the rest of
  1004. # attributes you can use direct writer methods. This is meant to protect
  1005. # sensitive attributes from being overwritten by malicious users
  1006. # tampering with URLs or forms. If you'd rather start from an all-open
  1007. # default and restrict attributes as needed, have a look at
  1008. # +attr_protected+.
  1009. #
  1010. # class Customer < ActiveRecord::Base
  1011. # attr_accessible :name, :nickname
  1012. # end
  1013. #
  1014. # customer = Customer.new(:name => "David", :nickname => "Dave", :credit_rating => "Excellent")
  1015. # customer.credit_rating # => nil
  1016. # customer.attributes = { :name => "Jolly fellow", :credit_rating => "Superb" }
  1017. # customer.credit_rating # => nil
  1018. #
  1019. # customer.credit_rating = "Average"
  1020. # customer.credit_rating # => "Average"
  1021. def attr_accessible(*attributes)
  1022. write_inheritable_attribute(:attr_accessible, Set.new(attributes.map(&:to_s)) + (accessible_attributes || []))
  1023. end
  1024. # Returns an array of all the attributes that have been made accessible to mass-assignment.
  1025. def accessible_attributes # :nodoc:
  1026. read_inheritable_attribute(:attr_accessible)
  1027. end
  1028. # Attributes listed as readonly can be set for a new record, but will be ignored in database updates afterwards.
  1029. def attr_readonly(*attributes)
  1030. write_inheritable_attribute(:attr_readonly, Set.new(attributes.map(&:to_s)) + (readonly_attributes || []))
  1031. end
  1032. # Returns an array of all the attributes that have been specified as readonly.
  1033. def readonly_attributes
  1034. read_inheritable_attribute(:attr_readonly)
  1035. end
  1036. # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object,
  1037. # then specify the name of that attribute using this method and it will be handled automatically.
  1038. # The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that
  1039. # class on retrieval or SerializationTypeMismatch will be raised.
  1040. #
  1041. # ==== Parameters
  1042. #
  1043. # * +attr_name+ - The field name that should be serialized.
  1044. # * +class_name+ - Optional, class name that the object type should be equal to.
  1045. #
  1046. # ==== Example
  1047. # # Serialize a preferences attribute
  1048. # class User
  1049. # serialize :preferences
  1050. # end
  1051. def serialize(attr_name, class_name = Object)
  1052. serialized_attributes[attr_name.to_s] = class_name
  1053. end
  1054. # Returns a hash of all the attributes that have been specified for serialization as keys and their class restriction as values.
  1055. def serialized_attributes
  1056. read_inheritable_attribute(:attr_serialized) or write_inheritable_attribute(:attr_serialized, {})
  1057. end
  1058. # Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending
  1059. # directly from ActiveRecord::Base. So if the hierarchy looks like: Reply < Message < ActiveRecord::Base, then Message is used
  1060. # to guess the table name even when called on Reply. The rules used to do the guess are handled by the Inflector class
  1061. # in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb.
  1062. #
  1063. # Nested classes are given table names prefixed by the singular form of
  1064. # the parent's table name. Enclosing modules are not considered.
  1065. #
  1066. # ==== Examples
  1067. #
  1068. # class Invoice < ActiveRecord::Base; end;
  1069. # file class table_name
  1070. # invoice.rb Invoice invoices
  1071. #
  1072. # class Invoice < ActiveRecord::Base; class Lineitem < ActiveRecord::Base; end; end;
  1073. # file class table_name
  1074. # invoice.rb Invoice::Lineitem invoice_lineitems
  1075. #
  1076. # module Invoice; class Lineitem < ActiveRecord::Base; end; end;
  1077. # file class table_name
  1078. # invoice/lineitem.rb Invoice::Lineitem lineitems
  1079. #
  1080. # Additionally, the class-level +table_name_prefix+ is prepended and the
  1081. # +table_name_suffix+ is appended. So if you have "myapp_" as a prefix,
  1082. # the table name guess for an Invoice class becomes "myapp_invoices".
  1083. # Invoice::Lineitem becomes "myapp_invoice_lineitems".
  1084. #
  1085. # You can also overwrite this class method to allow for unguessable
  1086. # links, such as a Mouse class with a link to a "mice" table. Example:
  1087. #
  1088. # class Mouse < ActiveRecord::Base
  1089. # set_table_name "mice"
  1090. # end
  1091. def table_name
  1092. reset_table_name
  1093. end
  1094. def reset_table_name #:nodoc:
  1095. base = base_class
  1096. name =
  1097. # STI subclasses always use their superclass' table.
  1098. unless self == base
  1099. base.table_name
  1100. else
  1101. # Nested classes are prefixed with singular parent table name.
  1102. if parent < ActiveRecord::Base && !parent.abstract_class?
  1103. contained = parent.table_name
  1104. contained = contained.singularize if parent.pluralize_table_names
  1105. contained << '_'
  1106. end
  1107. name = "#{full_table_name_prefix}#{contained}#{undecorated_table_name(base.name)}#{table_name_suffix}"
  1108. end
  1109. set_table_name(name)
  1110. name
  1111. end
  1112. # Defines the primary key field -- can be overridden in subclasses. Overwriting will negate any effect of the
  1113. # primary_key_prefix_type setting, though.
  1114. def primary_key
  1115. reset_primary_key
  1116. end
  1117. def reset_primary_key #:nodoc:
  1118. key = get_primary_key(base_class.name)
  1119. set_primary_key(key)
  1120. key
  1121. end
  1122. def get_primary_key(base_name) #:nodoc:
  1123. key = 'id'
  1124. case primary_key_prefix_type
  1125. when :table_name
  1126. key = base_name.to_s.foreign_key(false)
  1127. when :table_name_with_underscore
  1128. key = base_name.to_s.foreign_key
  1129. end
  1130. key
  1131. end
  1132. def full_table_name_prefix #:nodoc:
  1133. (parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
  1134. end
  1135. # Defines the column name for use with single table inheritance
  1136. # -- can be set in subclasses like so: self.inheritance_column = "type_id"
  1137. def inheritance_column
  1138. @inheritance_column ||= "type".freeze
  1139. end
  1140. # Lazy-set the sequence name to the connection's default. This method
  1141. # is only ever called once since set_sequence_name overrides it.
  1142. def sequence_name #:nodoc:
  1143. reset_sequence_name
  1144. end
  1145. def reset_sequence_name #:nodoc:
  1146. default = connection.default_sequence_name(table_name, primary_key)
  1147. set_sequence_name(default)
  1148. default
  1149. end
  1150. # Sets the table name to use to the given value, or (if the value
  1151. # is nil or false) to the value returned by the given block.
  1152. #
  1153. # class Project < ActiveRecord::Base
  1154. # set_table_name "project"
  1155. # end
  1156. def set_table_name(value = nil, &block)
  1157. define_attr_method :table_name, value, &block
  1158. end
  1159. alias :table_name= :set_table_name
  1160. # Sets the name of the primary key column to use to the given value,
  1161. # or (if the value is nil or false) to the value returned by the given
  1162. # block.
  1163. #
  1164. # class Project < ActiveRecord::Base
  1165. # set_primary_key "sysid"
  1166. # end
  1167. def set_primary_key(value = nil, &block)
  1168. define_attr_method :primary_key, value, &block
  1169. end
  1170. alias :primary_key= :set_primary_key
  1171. # Sets the name of the inheritance column to use to the given value,
  1172. # or (if the value # is nil or false) to the value returned by the
  1173. # given block.
  1174. #
  1175. # class Project < ActiveRecord::Base
  1176. # set_inheritance_column do
  1177. # original_inheritance_column + "_id"
  1178. # end
  1179. # end
  1180. def set_inheritance_column(value = nil, &block)
  1181. define_attr_method :inheritance_column, value, &block
  1182. end
  1183. alias :inheritance_column= :set_inheritance_column
  1184. # Sets the name of the sequence to use when generating ids to the given
  1185. # value, or (if the value is nil or false) to the value returned by the
  1186. # given block. This is required for Oracle and is useful for any
  1187. # database which relies on sequences for primary key generation.
  1188. #
  1189. # If a sequence name is not explicitly set when using Oracle or Firebird,
  1190. # it will default to the commonly used pattern of: #{table_name}_seq
  1191. #
  1192. # If a sequence name is not explicitly set when using PostgreSQL, it
  1193. # will discover the sequence corresponding to your primary key for you.
  1194. #
  1195. # class Project < ActiveRecord::Base
  1196. # set_sequence_name "projectseq" # default would have been "project_seq"
  1197. # end
  1198. def set_sequence_name(value = nil, &block)
  1199. define_attr_method :sequence_name, value, &block
  1200. end
  1201. alias :sequence_name= :set_sequence_name
  1202. # Turns the +table_name+ back into a class name following the reverse rules of +table_name+.
  1203. def class_name(table_name = table_name) # :nodoc:
  1204. ActiveSupport::Deprecation.warn("ActiveRecord::Base#class_name is deprecated and will be removed in Rails 3.", caller)
  1205. # remove any prefix and/or suffix from the table name
  1206. class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].camelize
  1207. class_name = class_name.singularize if pluralize_table_names
  1208. class_name
  1209. end
  1210. # Indicates whether the table associated with this class exists
  1211. def table_exists?
  1212. connection.table_exists?(table_name)
  1213. end
  1214. # Returns an array of column objects for the table associated with this class.
  1215. def columns
  1216. unless defined?(@columns) && @columns
  1217. @columns = connection.columns(table_name, "#{name} Columns")
  1218. @columns.each { |column| column.primary = column.name == primary_key }
  1219. end
  1220. @columns
  1221. end
  1222. # Returns a hash of column objects for the table associated with this class.
  1223. def columns_hash
  1224. @columns_hash ||= columns.inject({}) { |hash, column| hash[column.name] = column; hash }
  1225. end
  1226. # Returns an array of column names as strings.
  1227. def column_names
  1228. @column_names ||= columns.map { |column| column.name }
  1229. end
  1230. # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
  1231. # and columns used for single table inheritance have been removed.
  1232. def content_columns
  1233. @content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
  1234. end
  1235. # 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
  1236. # 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
  1237. # is available.
  1238. def column_methods_hash #:nodoc:
  1239. @dynamic_methods_hash ||= column_names.inject(Hash.new(false)) do |methods, attr|
  1240. attr_name = attr.to_s
  1241. methods[attr.to_sym] = attr_name
  1242. methods["#{attr}=".to_sym] = attr_name
  1243. methods["#{attr}?".to_sym] = attr_name
  1244. methods["#{attr}_before_type_cast".to_sym] = attr_name
  1245. methods
  1246. end
  1247. end
  1248. # Resets all the cached information about columns, which will cause them
  1249. # to be reloaded on the next request.
  1250. #
  1251. # The most common usage pattern for this method is probably in a migration,
  1252. # when just after creating a table you want to populate it with some default
  1253. # values, eg:
  1254. #
  1255. # class CreateJobLevels < ActiveRecord::Migration
  1256. # def self.up
  1257. # create_table :job_levels do |t|
  1258. # t.integer :id
  1259. # t.string :name
  1260. #
  1261. # t.timestamps
  1262. # end
  1263. #
  1264. # JobLevel.reset_column_information
  1265. # %w{assistant executive manager director}.each do |type|
  1266. # JobLevel.create(:name => type)
  1267. # end
  1268. # end
  1269. #
  1270. # def self.down
  1271. # drop_table :job_levels
  1272. # end
  1273. # end
  1274. def reset_column_information
  1275. generated_methods.each { |name| undef_method(name) }
  1276. @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = @generated_methods = @inheritance_column = nil
  1277. end
  1278. def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc:
  1279. subclasses.each { |klass| klass.reset_inheritable_attributes; klass.reset_column_information }
  1280. end
  1281. def self_and_descendants_from_active_record#nodoc:
  1282. klass = self
  1283. classes = [klass]
  1284. while klass != klass.base_class
  1285. classes << klass = klass.superclass
  1286. end
  1287. classes
  1288. rescue
  1289. # OPTIMIZE this rescue is to fix this test: ./test/cases/reflection_test.rb:56:in `test_human_name_for_column'
  1290. # Appearantly the method base_class causes some trouble.
  1291. # It now works for sure.
  1292. [self]
  1293. end
  1294. # Transforms attribute key names into a more humane format, such as "First name" instead of "first_name". Example:
  1295. # Person.human_attribute_name("first_name") # => "First name"
  1296. # This used to be depricated in favor of humanize, but is now preferred, because it automatically uses the I18n
  1297. # module now.
  1298. # Specify +options+ with additional translating options.
  1299. def human_attribute_name(attribute_key_name, options = {})
  1300. defaults = self_and_descendants_from_active_record.map do |klass|
  1301. :"#{klass.name.underscore}.#{attribute_key_name}"
  1302. end
  1303. defaults << options[:default] if options[:default]
  1304. defaults.flatten!
  1305. defaults << attribute_key_name.to_s.humanize
  1306. options[:count] ||= 1
  1307. I18n.translate(defaults.shift, options.merge(:default => defaults, :scope => [:activerecord, :attributes]))
  1308. end
  1309. # Transform the modelname into a more humane format, using I18n.
  1310. # Defaults to the basic humanize method.
  1311. # Default scope of the translation is activerecord.models
  1312. # Specify +options+ with additional translating options.
  1313. def human_name(options = {})
  1314. defaults = self_and_descendants_from_active_record.map do |klass|
  1315. :"#{klass.name.underscore}"
  1316. end
  1317. defaults << self.name.humanize
  1318. I18n.translate(defaults.shift, {:scope => [:activerecord, :models], :count => 1, :default => defaults}.merge(options))
  1319. end
  1320. # True if this isn't a concrete subclass needing a STI type condition.
  1321. def descends_from_active_record?
  1322. if superclass.abstract_class?
  1323. superclass.descends_from_active_record?
  1324. else
  1325. superclass == Base || !columns_hash.include?(inheritance_column)
  1326. end
  1327. end
  1328. def finder_needs_type_condition? #:nodoc:
  1329. # This is like this because benchmarking justifies the strange :false stuff
  1330. :true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true)
  1331. end
  1332. # Returns a string like 'Post id:integer, title:string, body:text'
  1333. def inspect
  1334. if self == Base
  1335. super
  1336. elsif abstract_class?
  1337. "#{super}(abstract)"
  1338. elsif table_exists?
  1339. attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
  1340. "#{super}(#{attr_list})"
  1341. else
  1342. "#{super}(Table doesn't exist)"
  1343. end
  1344. end
  1345. def quote_value(value, column = nil) #:nodoc:
  1346. connection.quote(value,column)
  1347. end
  1348. # Used to sanitize objects before they're used in an SQL SELECT statement. Delegates to <tt>connection.quote</tt>.
  1349. def sanitize(object) #:nodoc:
  1350. connection.quote(object)
  1351. end
  1352. # Log and benchmark multiple statements in a single block. Example:
  1353. #
  1354. # Project.benchmark("Creating project") do
  1355. # project = Project.create("name" => "stuff")
  1356. # project.create_manager("name" => "David")
  1357. # project.milestones << Milestone.find(:all)
  1358. # end
  1359. #
  1360. # The benchmark is only recorded if the current level of the logger is less than or equal to the <tt>log_level</tt>,
  1361. # which makes it easy to include benchmarking statements in production software that will remain inexpensive because
  1362. # the benchmark will only be conducted if the log level is low enough.
  1363. #
  1364. # The logging of the multiple statements is turned off unless <tt>use_silence</tt> is set to false.
  1365. def benchmark(title, log_level = Logger::DEBUG, use_silence = true)
  1366. if logger && logger.level <= log_level
  1367. result = nil
  1368. ms = Benchmark.ms { result = use_silence ? silence { yield } : yield }
  1369. logger.add(log_level, '%s (%.1fms)' % [title, ms])
  1370. result
  1371. else
  1372. yield
  1373. end
  1374. end
  1375. # Silences the logger for the duration of the block.
  1376. def silence
  1377. old_logger_level, logger.level = logger.level, Logger::ERROR if logger
  1378. yield
  1379. ensure
  1380. logger.level = old_logger_level if logger
  1381. end
  1382. # Overwrite the default class equality method to provide support for association proxies.
  1383. def ===(object)
  1384. object.is_a?(self)
  1385. end
  1386. # Returns the base AR subclass that this class descends from. If A
  1387. # extends AR::Base, A.base_class will return A. If B descends from A
  1388. # through some arbitrarily deep hierarchy, B.base_class will return A.
  1389. def base_class
  1390. class_of_active_record_descendant(self)
  1391. end
  1392. # Set this to true if this is an abstract class (see <tt>abstract_class?</tt>).
  1393. attr_accessor :abstract_class
  1394. # Returns whether this class is a base AR class. If A is a base class and
  1395. # B descends from A, then B.base_class will return B.
  1396. def abstract_class?
  1397. defined?(@abstract_class) && @abstract_class == true
  1398. end
  1399. def respond_to?(method_id, include_private = false)
  1400. if match = DynamicFinderMatch.match(method_id)
  1401. return true if all_attributes_exists?(match.attribute_names)
  1402. elsif match = DynamicScopeMatch.match(method_id)
  1403. return true if all_attributes_exists?(match.attribute_names)
  1404. end
  1405. super
  1406. end
  1407. def sti_name
  1408. store_full_sti_class ? name : name.demodulize
  1409. end
  1410. # Merges conditions so that the result is a valid +condition+
  1411. def merge_conditions(*conditions)
  1412. segments = []
  1413. conditions.each do |condition|
  1414. unless condition.blank?
  1415. sql = sanitize_sql(condition)
  1416. segments << sql unless sql.blank?
  1417. end
  1418. end
  1419. "(#{segments.join(') AND (')})" unless segments.empty?
  1420. end
  1421. private
  1422. def find_initial(options)
  1423. options.update(:limit => 1)
  1424. find_every(options).first
  1425. end
  1426. def find_last(options)
  1427. order = options[:order]
  1428. if order
  1429. order = reverse_sql_order(order)
  1430. elsif !scoped?(:find, :order)
  1431. order = "#{table_name}.#{primary_key} DESC"
  1432. end
  1433. if scoped?(:find, :order)
  1434. scope = scope(:find)
  1435. original_scoped_order = scope[:order]
  1436. scope[:order] = reverse_sql_order(original_scoped_order)
  1437. end
  1438. begin
  1439. find_initial(options.merge({ :order => order }))
  1440. ensure
  1441. scope[:order] = original_scoped_order if original_scoped_order
  1442. end
  1443. end
  1444. def reverse_sql_order(order_query)
  1445. reversed_query = order_query.to_s.split(/,/).each { |s|
  1446. if s.match(/\s(asc|ASC)$/)
  1447. s.gsub!(/\s(asc|ASC)$/, ' DESC')
  1448. elsif s.match(/\s(desc|DESC)$/)
  1449. s.gsub!(/\s(desc|DESC)$/, ' ASC')
  1450. elsif !s.match(/\s(asc|ASC|desc|DESC)$/)
  1451. s.concat(' DESC')
  1452. end
  1453. }.join(',')
  1454. end
  1455. def find_every(options)
  1456. include_associations = merge_includes(scope(:find, :include), options[:include])
  1457. if include_associations.any? && references_eager_loaded_tables?(options)
  1458. records = find_with_associations(options)
  1459. else
  1460. records = find_by_sql(construct_finder_sql(options))
  1461. if include_associations.any?
  1462. preload_associations(records, include_associations)
  1463. end
  1464. end
  1465. records.each { |record| record.readonly! } if options[:readonly]
  1466. records
  1467. end
  1468. def find_from_ids(ids, options)
  1469. expects_array = ids.first.kind_of?(Array)
  1470. return ids.first if expects_array && ids.first.empty?
  1471. ids = ids.flatten.compact.uniq
  1472. case ids.size
  1473. when 0
  1474. raise RecordNotFound, "Couldn't find #{name} without an ID"
  1475. when 1
  1476. result = find_one(ids.first, options)
  1477. expects_array ? [ result ] : result
  1478. else
  1479. find_some(ids, options)
  1480. end
  1481. end
  1482. def find_one(id, options)
  1483. conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
  1484. options.update :conditions => "#{quoted_table_name}.#{connection.quote_column_name(primary_key)} = #{quote_value(id,columns_hash[primary_key])}#{conditions}"
  1485. # Use find_every(options).first since the primary key condition
  1486. # already ensures we have a single record. Using find_initial adds
  1487. # a superfluous :limit => 1.
  1488. if result = find_every(options).first
  1489. result
  1490. else
  1491. raise RecordNotFound, "Couldn't find #{name} with ID=#{id}#{conditions}"
  1492. end
  1493. end
  1494. def find_some(ids, options)
  1495. conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
  1496. ids_list = ids.map { |id| quote_value(id,columns_hash[primary_key]) }.join(',')
  1497. options.update :conditions => "#{quoted_table_name}.#{connection.quote_column_name(primary_key)} IN (#{ids_list})#{conditions}"
  1498. result = find_every(options)
  1499. # Determine expected size from limit and offset, not just ids.size.
  1500. expected_size =
  1501. if options[:limit] && ids.size > options[:limit]
  1502. options[:limit]
  1503. else
  1504. ids.size
  1505. end
  1506. # 11 ids with limit 3, offset 9 should give 2 results.
  1507. if options[:offset] && (ids.size - options[:offset] < expected_size)
  1508. expected_size = ids.size - options[:offset]
  1509. end
  1510. if result.size == expected_size
  1511. result
  1512. else
  1513. raise RecordNotFound, "Couldn't find all #{name.pluralize} with IDs (#{ids_list})#{conditions} (found #{result.size} results, but was looking for #{expected_size})"
  1514. end
  1515. end
  1516. # Finder methods must instantiate through this method to work with the
  1517. # single-table inheritance model that makes it possible to create
  1518. # objects of different types from the same table.
  1519. def instantiate(record)
  1520. object =
  1521. if subclass_name = record[inheritance_column]
  1522. # No type given.
  1523. if subclass_name.empty?
  1524. allocate
  1525. else
  1526. # Ignore type if no column is present since it was probably
  1527. # pulled in from a sloppy join.
  1528. unless columns_hash.include?(inheritance_column)
  1529. allocate
  1530. else
  1531. begin
  1532. compute_type(subclass_name).allocate
  1533. rescue NameError
  1534. raise SubclassNotFound,
  1535. "The single-table inheritance mechanism failed to locate the subclass: '#{record[inheritance_column]}'. " +
  1536. "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
  1537. "Please rename this column if you didn't intend it to be used for storing the inheritance class " +
  1538. "or overwrite #{self.to_s}.inheritance_column to use another column for that information."
  1539. end
  1540. end
  1541. end
  1542. else
  1543. allocate
  1544. end
  1545. object.instance_variable_set("@attributes", record)
  1546. object.instance_variable_set("@attributes_cache", Hash.new)
  1547. if object.respond_to_without_attributes?(:after_find)
  1548. object.send(:callback, :after_find)
  1549. end
  1550. if object.respond_to_without_attributes?(:after_initialize)
  1551. object.send(:callback, :after_initialize)
  1552. end
  1553. object
  1554. end
  1555. # Nest the type name in the same module as this class.
  1556. # Bar is "MyApp::Business::Bar" relative to MyApp::Business::Foo
  1557. def type_name_with_module(type_name)
  1558. if store_full_sti_class
  1559. type_name
  1560. else
  1561. (/^::/ =~ type_name) ? type_name : "#{parent.name}::#{type_name}"
  1562. end
  1563. end
  1564. def default_select(qualified)
  1565. if qualified
  1566. quoted_table_name + '.*'
  1567. else
  1568. '*'
  1569. end
  1570. end
  1571. def construct_finder_sql(options)
  1572. scope = scope(:find)
  1573. sql = "SELECT #{options[:select] || (scope && scope[:select]) || default_select(options[:joins] || (scope && scope[:joins]))} "
  1574. sql << "FROM #{options[:from] || (scope && scope[:from]) || quoted_table_name} "
  1575. add_joins!(sql, options[:joins], scope)
  1576. add_conditions!(sql, options[:conditions], scope)
  1577. add_group!(sql, options[:group], options[:having], scope)
  1578. add_order!(sql, options[:order], scope)
  1579. add_limit!(sql, options, scope)
  1580. add_lock!(sql, options, scope)
  1581. sql
  1582. end
  1583. # Merges includes so that the result is a valid +include+
  1584. def merge_includes(first, second)
  1585. (safe_to_array(first) + safe_to_array(second)).uniq
  1586. end
  1587. def merge_joins(*joins)
  1588. if joins.any?{|j| j.is_a?(String) || array_of_strings?(j) }
  1589. joins = joins.collect do |join|
  1590. join = [join] if join.is_a?(String)
  1591. unless array_of_strings?(join)
  1592. join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, join, nil)
  1593. join = join_dependency.join_associations.collect { |assoc| assoc.association_join }
  1594. end
  1595. join
  1596. end
  1597. joins.flatten.map{|j| j.strip}.uniq
  1598. else
  1599. joins.collect{|j| safe_to_array(j)}.flatten.uniq
  1600. end
  1601. end
  1602. # Object#to_a is deprecated, though it does have the desired behavior
  1603. def safe_to_array(o)
  1604. case o
  1605. when NilClass
  1606. []
  1607. when Array
  1608. o
  1609. else
  1610. [o]
  1611. end
  1612. end
  1613. def array_of_strings?(o)
  1614. o.is_a?(Array) && o.all?{|obj| obj.is_a?(String)}
  1615. end
  1616. def add_order!(sql, order, scope = :auto)
  1617. scope = scope(:find) if :auto == scope
  1618. scoped_order = scope[:order] if scope
  1619. if order
  1620. sql << " ORDER BY #{order}"
  1621. if scoped_order && scoped_order != order
  1622. sql << ", #{scoped_order}"
  1623. end
  1624. else
  1625. sql << " ORDER BY #{scoped_order}" if scoped_order
  1626. end
  1627. end
  1628. def add_group!(sql, group, having, scope = :auto)
  1629. if group
  1630. sql << " GROUP BY #{group}"
  1631. sql << " HAVING #{sanitize_sql_for_conditions(having)}" if having
  1632. else
  1633. scope = scope(:find) if :auto == scope
  1634. if scope && (scoped_group = scope[:group])
  1635. sql << " GROUP BY #{scoped_group}"
  1636. sql << " HAVING #{sanitize_sql_for_conditions(scope[:having])}" if scope[:having]
  1637. end
  1638. end
  1639. end
  1640. # The optional scope argument is for the current <tt>:find</tt> scope.
  1641. def add_limit!(sql, options, scope = :auto)
  1642. scope = scope(:find) if :auto == scope
  1643. if scope
  1644. options[:limit] ||= scope[:limit]
  1645. options[:offset] ||= scope[:offset]
  1646. end
  1647. connection.add_limit_offset!(sql, options)
  1648. end
  1649. # The optional scope argument is for the current <tt>:find</tt> scope.
  1650. # The <tt>:lock</tt> option has precedence over a scoped <tt>:lock</tt>.
  1651. def add_lock!(sql, options, scope = :auto)
  1652. scope = scope(:find) if :auto == scope
  1653. options = options.reverse_merge(:lock => scope[:lock]) if scope
  1654. connection.add_lock!(sql, options)
  1655. end
  1656. # The optional scope argument is for the current <tt>:find</tt> scope.
  1657. def add_joins!(sql, joins, scope = :auto)
  1658. scope = scope(:find) if :auto == scope
  1659. merged_joins = scope && scope[:joins] && joins ? merge_joins(scope[:joins], joins) : (joins || scope && scope[:joins])
  1660. case merged_joins
  1661. when Symbol, Hash, Array
  1662. if array_of_strings?(merged_joins)
  1663. sql << merged_joins.join(' ') + " "
  1664. else
  1665. join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, merged_joins, nil)
  1666. sql << " #{join_dependency.join_associations.collect { |assoc| assoc.association_join }.join} "
  1667. end
  1668. when String
  1669. sql << " #{merged_joins} "
  1670. end
  1671. end
  1672. # Adds a sanitized version of +conditions+ to the +sql+ string. Note that the passed-in +sql+ string is changed.
  1673. # The optional scope argument is for the current <tt>:find</tt> scope.
  1674. def add_conditions!(sql, conditions, scope = :auto)
  1675. scope = scope(:find) if :auto == scope
  1676. conditions = [conditions]
  1677. conditions << scope[:conditions] if scope
  1678. conditions << type_condition if finder_needs_type_condition?
  1679. merged_conditions = merge_conditions(*conditions)
  1680. sql << "WHERE #{merged_conditions} " unless merged_conditions.blank?
  1681. end
  1682. def type_condition(table_alias=nil)
  1683. quoted_table_alias = self.connection.quote_table_name(table_alias || table_name)
  1684. quoted_inheritance_column = connection.quote_column_name(inheritance_column)
  1685. type_condition = subclasses.inject("#{quoted_table_alias}.#{quoted_inheritance_column} = '#{sti_name}' ") do |condition, subclass|
  1686. condition << "OR #{quoted_table_alias}.#{quoted_inheritance_column} = '#{subclass.sti_name}' "
  1687. end
  1688. " (#{type_condition}) "
  1689. end
  1690. # Guesses the table name, but does not decorate it with prefix and suffix information.
  1691. def undecorated_table_name(class_name = base_class.name)
  1692. table_name = class_name.to_s.demodulize.underscore
  1693. table_name = table_name.pluralize if pluralize_table_names
  1694. table_name
  1695. end
  1696. # Enables dynamic finders like <tt>find_by_user_name(user_name)</tt> and <tt>find_by_user_name_and_password(user_name, password)</tt>
  1697. # that are turned into <tt>find(:first, :conditions => ["user_name = ?", user_name])</tt> and
  1698. # <tt>find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password])</tt> respectively. Also works for
  1699. # <tt>find(:all)</tt> by using <tt>find_all_by_amount(50)</tt> that is turned into <tt>find(:all, :conditions => ["amount = ?", 50])</tt>.
  1700. #
  1701. # It's even possible to use all the additional parameters to +find+. For example, the full interface for +find_all_by_amount+
  1702. # is actually <tt>find_all_by_amount(amount, options)</tt>.
  1703. #
  1704. # Also enables dynamic scopes like scoped_by_user_name(user_name) and scoped_by_user_name_and_password(user_name, password) that
  1705. # are turned into scoped(:conditions => ["user_name = ?", user_name]) and scoped(:conditions => ["user_name = ? AND password = ?", user_name, password])
  1706. # respectively.
  1707. #
  1708. # Each dynamic finder, scope or initializer/creator is also defined in the class after it is first invoked, so that future
  1709. # attempts to use it do not run through method_missing.
  1710. def method_missing(method_id, *arguments, &block)
  1711. if match = DynamicFinderMatch.match(method_id)
  1712. attribute_names = match.attribute_names
  1713. super unless all_attributes_exists?(attribute_names)
  1714. if match.finder?
  1715. finder = match.finder
  1716. bang = match.bang?
  1717. # def self.find_by_login_and_activated(*args)
  1718. # options = args.extract_options!
  1719. # attributes = construct_attributes_from_arguments(
  1720. # [:login,:activated],
  1721. # args
  1722. # )
  1723. # finder_options = { :conditions => attributes }
  1724. # validate_find_options(options)
  1725. # set_readonly_option!(options)
  1726. #
  1727. # if options[:conditions]
  1728. # with_scope(:find => finder_options) do
  1729. # find(:first, options)
  1730. # end
  1731. # else
  1732. # find(:first, options.merge(finder_options))
  1733. # end
  1734. # end
  1735. self.class_eval <<-EOS, __FILE__, __LINE__ + 1
  1736. def self.#{method_id}(*args)
  1737. options = args.extract_options!
  1738. attributes = construct_attributes_from_arguments(
  1739. [:#{attribute_names.join(',:')}],
  1740. args
  1741. )
  1742. finder_options = { :conditions => attributes }
  1743. validate_find_options(options)
  1744. set_readonly_option!(options)
  1745. #{'result = ' if bang}if options[:conditions]
  1746. with_scope(:find => finder_options) do
  1747. find(:#{finder}, options)
  1748. end
  1749. else
  1750. find(:#{finder}, options.merge(finder_options))
  1751. end
  1752. #{'result || raise(RecordNotFound, "Couldn\'t find #{name} with #{attributes.to_a.collect {|pair| "#{pair.first} = #{pair.second}"}.join(\', \')}")' if bang}
  1753. end
  1754. EOS
  1755. send(method_id, *arguments)
  1756. elsif match.instantiator?
  1757. instantiator = match.instantiator
  1758. # def self.find_or_create_by_user_id(*args)
  1759. # guard_protected_attributes = false
  1760. #
  1761. # if args[0].is_a?(Hash)
  1762. # guard_protected_attributes = true
  1763. # attributes = args[0].with_indifferent_access
  1764. # find_attributes = attributes.slice(*[:user_id])
  1765. # else
  1766. # find_attributes = attributes = construct_attributes_from_arguments([:user_id], args)
  1767. # end
  1768. #
  1769. # options = { :conditions => find_attributes }
  1770. # set_readonly_option!(options)
  1771. #
  1772. # record = find(:first, options)
  1773. #
  1774. # if record.nil?
  1775. # record = self.new { |r| r.send(:attributes=, attributes, guard_protected_attributes) }
  1776. # yield(record) if block_given?
  1777. # record.save
  1778. # record
  1779. # else
  1780. # record
  1781. # end
  1782. # end
  1783. self.class_eval <<-EOS, __FILE__, __LINE__ + 1
  1784. def self.#{method_id}(*args)
  1785. attributes = [:#{attribute_names.join(',:')}]
  1786. protected_attributes_for_create, unprotected_attributes_for_create = {}, {}
  1787. args.each_with_index do |arg, i|
  1788. if arg.is_a?(Hash)
  1789. protected_attributes_for_create = args[i].with_indifferent_access
  1790. else
  1791. unprotected_attributes_for_create[attributes[i]] = args[i]
  1792. end
  1793. end
  1794. find_attributes = (protected_attributes_for_create.merge(unprotected_attributes_for_create)).slice(*attributes)
  1795. options = { :conditions => find_attributes }
  1796. set_readonly_option!(options)
  1797. record = find(:first, options)
  1798. if record.nil?
  1799. record = self.new do |r|
  1800. r.send(:attributes=, protected_attributes_for_create, true) unless protected_attributes_for_create.empty?
  1801. r.send(:attributes=, unprotected_attributes_for_create, false) unless unprotected_attributes_for_create.empty?
  1802. end
  1803. #{'yield(record) if block_given?'}
  1804. #{'record.save' if instantiator == :create}
  1805. record
  1806. else
  1807. record
  1808. end
  1809. end
  1810. EOS
  1811. send(method_id, *arguments, &block)
  1812. end
  1813. elsif match = DynamicScopeMatch.match(method_id)
  1814. attribute_names = match.attribute_names
  1815. super unless all_attributes_exists?(attribute_names)
  1816. if match.scope?
  1817. self.class_eval <<-EOS, __FILE__, __LINE__ + 1
  1818. def self.#{method_id}(*args) # def self.scoped_by_user_name_and_password(*args)
  1819. options = args.extract_options! # options = args.extract_options!
  1820. attributes = construct_attributes_from_arguments( # attributes = construct_attributes_from_arguments(
  1821. [:#{attribute_names.join(',:')}], args # [:user_name, :password], args
  1822. ) # )
  1823. #
  1824. scoped(:conditions => attributes) # scoped(:conditions => attributes)
  1825. end # end
  1826. EOS
  1827. send(method_id, *arguments)
  1828. end
  1829. else
  1830. super
  1831. end
  1832. end
  1833. def construct_attributes_from_arguments(attribute_names, arguments)
  1834. attributes = {}
  1835. attribute_names.each_with_index { |name, idx| attributes[name] = arguments[idx] }
  1836. attributes
  1837. end
  1838. # Similar in purpose to +expand_hash_conditions_for_aggregates+.
  1839. def expand_attribute_names_for_aggregates(attribute_names)
  1840. expanded_attribute_names = []
  1841. attribute_names.each do |attribute_name|
  1842. unless (aggregation = reflect_on_aggregation(attribute_name.to_sym)).nil?
  1843. aggregate_mapping(aggregation).each do |field_attr, aggregate_attr|
  1844. expanded_attribute_names << field_attr
  1845. end
  1846. else
  1847. expanded_attribute_names << attribute_name
  1848. end
  1849. end
  1850. expanded_attribute_names
  1851. end
  1852. def all_attributes_exists?(attribute_names)
  1853. attribute_names = expand_attribute_names_for_aggregates(attribute_names)
  1854. attribute_names.all? { |name| column_methods_hash.include?(name.to_sym) }
  1855. end
  1856. def attribute_condition(quoted_column_name, argument)
  1857. case argument
  1858. when nil then "#{quoted_column_name} IS ?"
  1859. when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope then "#{quoted_column_name} IN (?)"
  1860. when Range then if argument.exclude_end?
  1861. "#{quoted_column_name} >= ? AND #{quoted_column_name} < ?"
  1862. else
  1863. "#{quoted_column_name} BETWEEN ? AND ?"
  1864. end
  1865. else "#{quoted_column_name} = ?"
  1866. end
  1867. end
  1868. # Interpret Array and Hash as conditions and anything else as an id.
  1869. def expand_id_conditions(id_or_conditions)
  1870. case id_or_conditions
  1871. when Array, Hash then id_or_conditions
  1872. else sanitize_sql(primary_key => id_or_conditions)
  1873. end
  1874. end
  1875. # Defines an "attribute" method (like +inheritance_column+ or
  1876. # +table_name+). A new (class) method will be created with the
  1877. # given name. If a value is specified, the new method will
  1878. # return that value (as a string). Otherwise, the given block
  1879. # will be used to compute the value of the method.
  1880. #
  1881. # The original method will be aliased, with the new name being
  1882. # prefixed with "original_". This allows the new method to
  1883. # access the original value.
  1884. #
  1885. # Example:
  1886. #
  1887. # class A < ActiveRecord::Base
  1888. # define_attr_method :primary_key, "sysid"
  1889. # define_attr_method( :inheritance_column ) do
  1890. # original_inheritance_column + "_id"
  1891. # end
  1892. # end
  1893. def define_attr_method(name, value=nil, &block)
  1894. sing = class << self; self; end
  1895. sing.send :alias_method, "original_#{name}", name
  1896. if block_given?
  1897. sing.send :define_method, name, &block
  1898. else
  1899. # use eval instead of a block to work around a memory leak in dev
  1900. # mode in fcgi
  1901. sing.class_eval "def #{name}; #{value.to_s.inspect}; end"
  1902. end
  1903. end
  1904. protected
  1905. # Scope parameters to method calls within the block. Takes a hash of method_name => parameters hash.
  1906. # method_name may be <tt>:find</tt> or <tt>:create</tt>. <tt>:find</tt> parameters may include the <tt>:conditions</tt>, <tt>:joins</tt>,
  1907. # <tt>:include</tt>, <tt>:offset</tt>, <tt>:limit</tt>, and <tt>:readonly</tt> options. <tt>:create</tt> parameters are an attributes hash.
  1908. #
  1909. # class Article < ActiveRecord::Base
  1910. # def self.create_with_scope
  1911. # with_scope(:find => { :conditions => "blog_id = 1" }, :create => { :blog_id => 1 }) do
  1912. # find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1
  1913. # a = create(1)
  1914. # a.blog_id # => 1
  1915. # end
  1916. # end
  1917. # end
  1918. #
  1919. # In nested scopings, all previous parameters are overwritten by the innermost rule, with the exception of
  1920. # <tt>:conditions</tt>, <tt>:include</tt>, and <tt>:joins</tt> options in <tt>:find</tt>, which are merged.
  1921. #
  1922. # <tt>:joins</tt> options are uniqued so multiple scopes can join in the same table without table aliasing
  1923. # problems. If you need to join multiple tables, but still want one of the tables to be uniqued, use the
  1924. # array of strings format for your joins.
  1925. #
  1926. # class Article < ActiveRecord::Base
  1927. # def self.find_with_scope
  1928. # with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }, :create => { :blog_id => 1 }) do
  1929. # with_scope(:find => { :limit => 10 })
  1930. # find(:all) # => SELECT * from articles WHERE blog_id = 1 LIMIT 10
  1931. # end
  1932. # with_scope(:find => { :conditions => "author_id = 3" })
  1933. # find(:all) # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1
  1934. # end
  1935. # end
  1936. # end
  1937. # end
  1938. #
  1939. # You can ignore any previous scopings by using the <tt>with_exclusive_scope</tt> method.
  1940. #
  1941. # class Article < ActiveRecord::Base
  1942. # def self.find_with_exclusive_scope
  1943. # with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }) do
  1944. # with_exclusive_scope(:find => { :limit => 10 })
  1945. # find(:all) # => SELECT * from articles LIMIT 10
  1946. # end
  1947. # end
  1948. # end
  1949. # end
  1950. #
  1951. # *Note*: the +:find+ scope also has effect on update and deletion methods,
  1952. # like +update_all+ and +delete_all+.
  1953. def with_scope(method_scoping = {}, action = :merge, &block)
  1954. method_scoping = method_scoping.method_scoping if method_scoping.respond_to?(:method_scoping)
  1955. # Dup first and second level of hash (method and params).
  1956. method_scoping = method_scoping.inject({}) do |hash, (method, params)|
  1957. hash[method] = (params == true) ? params : params.dup
  1958. hash
  1959. end
  1960. method_scoping.assert_valid_keys([ :find, :create ])
  1961. if f = method_scoping[:find]
  1962. f.assert_valid_keys(VALID_FIND_OPTIONS)
  1963. set_readonly_option! f
  1964. end
  1965. # Merge scopings
  1966. if [:merge, :reverse_merge].include?(action) && current_scoped_methods
  1967. method_scoping = current_scoped_methods.inject(method_scoping) do |hash, (method, params)|
  1968. case hash[method]
  1969. when Hash
  1970. if method == :find
  1971. (hash[method].keys + params.keys).uniq.each do |key|
  1972. merge = hash[method][key] && params[key] # merge if both scopes have the same key
  1973. if key == :conditions && merge
  1974. if params[key].is_a?(Hash) && hash[method][key].is_a?(Hash)
  1975. hash[method][key] = merge_conditions(hash[method][key].deep_merge(params[key]))
  1976. else
  1977. hash[method][key] = merge_conditions(params[key], hash[method][key])
  1978. end
  1979. elsif key == :include && merge
  1980. hash[method][key] = merge_includes(hash[method][key], params[key]).uniq
  1981. elsif key == :joins && merge
  1982. hash[method][key] = merge_joins(params[key], hash[method][key])
  1983. else
  1984. hash[method][key] = hash[method][key] || params[key]
  1985. end
  1986. end
  1987. else
  1988. if action == :reverse_merge
  1989. hash[method] = hash[method].merge(params)
  1990. else
  1991. hash[method] = params.merge(hash[method])
  1992. end
  1993. end
  1994. else
  1995. hash[method] = params
  1996. end
  1997. hash
  1998. end
  1999. end
  2000. self.scoped_methods << method_scoping
  2001. begin
  2002. yield
  2003. ensure
  2004. self.scoped_methods.pop
  2005. end
  2006. end
  2007. # Works like with_scope, but discards any nested properties.
  2008. def with_exclusive_scope(method_scoping = {}, &block)
  2009. with_scope(method_scoping, :overwrite, &block)
  2010. end
  2011. def subclasses #:nodoc:
  2012. @@subclasses[self] ||= []
  2013. @@subclasses[self] + extra = @@subclasses[self].inject([]) {|list, subclass| list + subclass.subclasses }
  2014. end
  2015. # Sets the default options for the model. The format of the
  2016. # <tt>options</tt> argument is the same as in find.
  2017. #
  2018. # class Person < ActiveRecord::Base
  2019. # default_scope :order => 'last_name, first_name'
  2020. # end
  2021. def default_scope(options = {})
  2022. self.default_scoping << { :find => options, :create => options[:conditions].is_a?(Hash) ? options[:conditions] : {} }
  2023. end
  2024. # Test whether the given method and optional key are scoped.
  2025. def scoped?(method, key = nil) #:nodoc:
  2026. if current_scoped_methods && (scope = current_scoped_methods[method])
  2027. !key || !scope[key].nil?
  2028. end
  2029. end
  2030. # Retrieve the scope for the given method and optional key.
  2031. def scope(method, key = nil) #:nodoc:
  2032. if current_scoped_methods && (scope = current_scoped_methods[method])
  2033. key ? scope[key] : scope
  2034. end
  2035. end
  2036. def scoped_methods #:nodoc:
  2037. Thread.current[:"#{self}_scoped_methods"] ||= self.default_scoping.dup
  2038. end
  2039. def current_scoped_methods #:nodoc:
  2040. scoped_methods.last
  2041. end
  2042. # Returns the class type of the record using the current module as a prefix. So descendants of
  2043. # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
  2044. def compute_type(type_name)
  2045. modularized_name = type_name_with_module(type_name)
  2046. silence_warnings do
  2047. begin
  2048. class_eval(modularized_name, __FILE__)
  2049. rescue NameError
  2050. class_eval(type_name, __FILE__)
  2051. end
  2052. end
  2053. end
  2054. # Returns the class descending directly from ActiveRecord::Base or an
  2055. # abstract class, if any, in the inheritance hierarchy.
  2056. def class_of_active_record_descendant(klass)
  2057. if klass.superclass == Base || klass.superclass.abstract_class?
  2058. klass
  2059. elsif klass.superclass.nil?
  2060. raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
  2061. else
  2062. class_of_active_record_descendant(klass.superclass)
  2063. end
  2064. end
  2065. # Returns the name of the class descending directly from Active Record in the inheritance hierarchy.
  2066. def class_name_of_active_record_descendant(klass) #:nodoc:
  2067. klass.base_class.name
  2068. end
  2069. # Accepts an array, hash, or string of SQL conditions and sanitizes
  2070. # them into a valid SQL fragment for a WHERE clause.
  2071. # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
  2072. # { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'"
  2073. # "name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'"
  2074. def sanitize_sql_for_conditions(condition, table_name = quoted_table_name)
  2075. return nil if condition.blank?
  2076. case condition
  2077. when Array; sanitize_sql_array(condition)
  2078. when Hash; sanitize_sql_hash_for_conditions(condition, table_name)
  2079. else condition
  2080. end
  2081. end
  2082. alias_method :sanitize_sql, :sanitize_sql_for_conditions
  2083. # Accepts an array, hash, or string of SQL conditions and sanitizes
  2084. # them into a valid SQL fragment for a SET clause.
  2085. # { :name => nil, :group_id => 4 } returns "name = NULL , group_id='4'"
  2086. def sanitize_sql_for_assignment(assignments)
  2087. case assignments
  2088. when Array; sanitize_sql_array(assignments)
  2089. when Hash; sanitize_sql_hash_for_assignment(assignments)
  2090. else assignments
  2091. end
  2092. end
  2093. def aggregate_mapping(reflection)
  2094. mapping = reflection.options[:mapping] || [reflection.name, reflection.name]
  2095. mapping.first.is_a?(Array) ? mapping : [mapping]
  2096. end
  2097. # Accepts a hash of SQL conditions and replaces those attributes
  2098. # that correspond to a +composed_of+ relationship with their expanded
  2099. # aggregate attribute values.
  2100. # Given:
  2101. # class Person < ActiveRecord::Base
  2102. # composed_of :address, :class_name => "Address",
  2103. # :mapping => [%w(address_street street), %w(address_city city)]
  2104. # end
  2105. # Then:
  2106. # { :address => Address.new("813 abc st.", "chicago") }
  2107. # # => { :address_street => "813 abc st.", :address_city => "chicago" }
  2108. def expand_hash_conditions_for_aggregates(attrs)
  2109. expanded_attrs = {}
  2110. attrs.each do |attr, value|
  2111. unless (aggregation = reflect_on_aggregation(attr.to_sym)).nil?
  2112. mapping = aggregate_mapping(aggregation)
  2113. mapping.each do |field_attr, aggregate_attr|
  2114. if mapping.size == 1 && !value.respond_to?(aggregate_attr)
  2115. expanded_attrs[field_attr] = value
  2116. else
  2117. expanded_attrs[field_attr] = value.send(aggregate_attr)
  2118. end
  2119. end
  2120. else
  2121. expanded_attrs[attr] = value
  2122. end
  2123. end
  2124. expanded_attrs
  2125. end
  2126. # Sanitizes a hash of attribute/value pairs into SQL conditions for a WHERE clause.
  2127. # { :name => "foo'bar", :group_id => 4 }
  2128. # # => "name='foo''bar' and group_id= 4"
  2129. # { :status => nil, :group_id => [1,2,3] }
  2130. # # => "status IS NULL and group_id IN (1,2,3)"
  2131. # { :age => 13..18 }
  2132. # # => "age BETWEEN 13 AND 18"
  2133. # { 'other_records.id' => 7 }
  2134. # # => "`other_records`.`id` = 7"
  2135. # { :other_records => { :id => 7 } }
  2136. # # => "`other_records`.`id` = 7"
  2137. # And for value objects on a composed_of relationship:
  2138. # { :address => Address.new("123 abc st.", "chicago") }
  2139. # # => "address_street='123 abc st.' and address_city='chicago'"
  2140. def sanitize_sql_hash_for_conditions(attrs, default_table_name = quoted_table_name, top_level = true)
  2141. attrs = expand_hash_conditions_for_aggregates(attrs)
  2142. conditions = attrs.map do |attr, value|
  2143. table_name = default_table_name
  2144. if not value.is_a?(Hash)
  2145. attr = attr.to_s
  2146. # Extract table name from qualified attribute names.
  2147. if attr.include?('.') and top_level
  2148. attr_table_name, attr = attr.split('.', 2)
  2149. attr_table_name = connection.quote_table_name(attr_table_name)
  2150. else
  2151. attr_table_name = table_name
  2152. end
  2153. attribute_condition("#{attr_table_name}.#{connection.quote_column_name(attr)}", value)
  2154. elsif top_level
  2155. sanitize_sql_hash_for_conditions(value, connection.quote_table_name(attr.to_s), false)
  2156. else
  2157. raise ActiveRecord::StatementInvalid
  2158. end
  2159. end.join(' AND ')
  2160. replace_bind_variables(conditions, expand_range_bind_variables(attrs.values))
  2161. end
  2162. alias_method :sanitize_sql_hash, :sanitize_sql_hash_for_conditions
  2163. # Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause.
  2164. # { :status => nil, :group_id => 1 }
  2165. # # => "status = NULL , group_id = 1"
  2166. def sanitize_sql_hash_for_assignment(attrs)
  2167. attrs.map do |attr, value|
  2168. "#{connection.quote_column_name(attr)} = #{quote_bound_value(value)}"
  2169. end.join(', ')
  2170. end
  2171. # Accepts an array of conditions. The array has each value
  2172. # sanitized and interpolated into the SQL statement.
  2173. # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
  2174. def sanitize_sql_array(ary)
  2175. statement, *values = ary
  2176. if values.first.is_a?(Hash) and statement =~ /:\w+/
  2177. replace_named_bind_variables(statement, values.first)
  2178. elsif statement.include?('?')
  2179. replace_bind_variables(statement, values)
  2180. else
  2181. statement % values.collect { |value| connection.quote_string(value.to_s) }
  2182. end
  2183. end
  2184. alias_method :sanitize_conditions, :sanitize_sql
  2185. def replace_bind_variables(statement, values) #:nodoc:
  2186. raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
  2187. bound = values.dup
  2188. statement.gsub('?') { quote_bound_value(bound.shift) }
  2189. end
  2190. def replace_named_bind_variables(statement, bind_vars) #:nodoc:
  2191. statement.gsub(/(:?):([a-zA-Z]\w*)/) do
  2192. if $1 == ':' # skip postgresql casts
  2193. $& # return the whole match
  2194. elsif bind_vars.include?(match = $2.to_sym)
  2195. quote_bound_value(bind_vars[match])
  2196. else
  2197. raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
  2198. end
  2199. end
  2200. end
  2201. def expand_range_bind_variables(bind_vars) #:nodoc:
  2202. expanded = []
  2203. bind_vars.each do |var|
  2204. next if var.is_a?(Hash)
  2205. if var.is_a?(Range)
  2206. expanded << var.first
  2207. expanded << var.last
  2208. else
  2209. expanded << var
  2210. end
  2211. end
  2212. expanded
  2213. end
  2214. def quote_bound_value(value) #:nodoc:
  2215. if value.respond_to?(:map) && !value.acts_like?(:string)
  2216. if value.respond_to?(:empty?) && value.empty?
  2217. connection.quote(nil)
  2218. else
  2219. value.map { |v| connection.quote(v) }.join(',')
  2220. end
  2221. else
  2222. connection.quote(value)
  2223. end
  2224. end
  2225. def raise_if_bind_arity_mismatch(statement, expected, provided) #:nodoc:
  2226. unless expected == provided
  2227. raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}"
  2228. end
  2229. end
  2230. VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset,
  2231. :order, :select, :readonly, :group, :having, :from, :lock ]
  2232. def validate_find_options(options) #:nodoc:
  2233. options.assert_valid_keys(VALID_FIND_OPTIONS)
  2234. end
  2235. def set_readonly_option!(options) #:nodoc:
  2236. # Inherit :readonly from finder scope if set. Otherwise,
  2237. # if :joins is not blank then :readonly defaults to true.
  2238. unless options.has_key?(:readonly)
  2239. if scoped_readonly = scope(:find, :readonly)
  2240. options[:readonly] = scoped_readonly
  2241. elsif !options[:joins].blank? && !options[:select]
  2242. options[:readonly] = true
  2243. end
  2244. end
  2245. end
  2246. def encode_quoted_value(value) #:nodoc:
  2247. quoted_value = connection.quote(value)
  2248. quoted_value = "'#{quoted_value[1..-2].gsub(/\'/, "\\\\'")}'" if quoted_value.include?("\\\'") # (for ruby mode) "
  2249. quoted_value
  2250. end
  2251. end
  2252. public
  2253. # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
  2254. # attributes but not yet saved (pass a hash with key names matching the associated table column names).
  2255. # In both instances, valid attribute keys are determined by the column names of the associated table --
  2256. # hence you can't have attributes that aren't part of the table columns.
  2257. def initialize(attributes = nil)
  2258. @attributes = attributes_from_column_definition
  2259. @attributes_cache = {}
  2260. @new_record = true
  2261. ensure_proper_type
  2262. self.attributes = attributes unless attributes.nil?
  2263. assign_attributes(self.class.send(:scope, :create)) if self.class.send(:scoped?, :create)
  2264. result = yield self if block_given?
  2265. callback(:after_initialize) if respond_to_without_attributes?(:after_initialize)
  2266. result
  2267. end
  2268. # A model instance's primary key is always available as model.id
  2269. # whether you name it the default 'id' or set it to something else.
  2270. def id
  2271. attr_name = self.class.primary_key
  2272. column = column_for_attribute(attr_name)
  2273. self.class.send(:define_read_method, :id, attr_name, column)
  2274. # now that the method exists, call it
  2275. self.send attr_name.to_sym
  2276. end
  2277. # Returns a String, which Action Pack uses for constructing an URL to this
  2278. # object. The default implementation returns this record's id as a String,
  2279. # or nil if this record's unsaved.
  2280. #
  2281. # For example, suppose that you have a User model, and that you have a
  2282. # <tt>map.resources :users</tt> route. Normally, +user_path+ will
  2283. # construct a path with the user object's 'id' in it:
  2284. #
  2285. # user = User.find_by_name('Phusion')
  2286. # user_path(user) # => "/users/1"
  2287. #
  2288. # You can override +to_param+ in your model to make +user_path+ construct
  2289. # a path using the user's name instead of the user's id:
  2290. #
  2291. # class User < ActiveRecord::Base
  2292. # def to_param # overridden
  2293. # name
  2294. # end
  2295. # end
  2296. #
  2297. # user = User.find_by_name('Phusion')
  2298. # user_path(user) # => "/users/Phusion"
  2299. def to_param
  2300. # We can't use alias_method here, because method 'id' optimizes itself on the fly.
  2301. (id = self.id) ? id.to_s : nil # Be sure to stringify the id for routes
  2302. end
  2303. # Returns a cache key that can be used to identify this record.
  2304. #
  2305. # ==== Examples
  2306. #
  2307. # Product.new.cache_key # => "products/new"
  2308. # Product.find(5).cache_key # => "products/5" (updated_at not available)
  2309. # Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
  2310. def cache_key
  2311. case
  2312. when new_record?
  2313. "#{self.class.model_name.cache_key}/new"
  2314. when timestamp = self[:updated_at]
  2315. "#{self.class.model_name.cache_key}/#{id}-#{timestamp.to_s(:number)}"
  2316. else
  2317. "#{self.class.model_name.cache_key}/#{id}"
  2318. end
  2319. end
  2320. def id_before_type_cast #:nodoc:
  2321. read_attribute_before_type_cast(self.class.primary_key)
  2322. end
  2323. def quoted_id #:nodoc:
  2324. quote_value(id, column_for_attribute(self.class.primary_key))
  2325. end
  2326. # Sets the primary ID.
  2327. def id=(value)
  2328. write_attribute(self.class.primary_key, value)
  2329. end
  2330. # Returns true if this object hasn't been saved yet -- that is, a record for the object doesn't exist yet; otherwise, returns false.
  2331. def new_record?
  2332. @new_record || false
  2333. end
  2334. # :call-seq:
  2335. # save(perform_validation = true)
  2336. #
  2337. # Saves the model.
  2338. #
  2339. # If the model is new a record gets created in the database, otherwise
  2340. # the existing record gets updated.
  2341. #
  2342. # If +perform_validation+ is true validations run. If any of them fail
  2343. # the action is cancelled and +save+ returns +false+. If the flag is
  2344. # false validations are bypassed altogether. See
  2345. # ActiveRecord::Validations for more information.
  2346. #
  2347. # There's a series of callbacks associated with +save+. If any of the
  2348. # <tt>before_*</tt> callbacks return +false+ the action is cancelled and
  2349. # +save+ returns +false+. See ActiveRecord::Callbacks for further
  2350. # details.
  2351. def save
  2352. create_or_update
  2353. end
  2354. # Saves the model.
  2355. #
  2356. # If the model is new a record gets created in the database, otherwise
  2357. # the existing record gets updated.
  2358. #
  2359. # With <tt>save!</tt> validations always run. If any of them fail
  2360. # ActiveRecord::RecordInvalid gets raised. See ActiveRecord::Validations
  2361. # for more information.
  2362. #
  2363. # There's a series of callbacks associated with <tt>save!</tt>. If any of
  2364. # the <tt>before_*</tt> callbacks return +false+ the action is cancelled
  2365. # and <tt>save!</tt> raises ActiveRecord::RecordNotSaved. See
  2366. # ActiveRecord::Callbacks for further details.
  2367. def save!
  2368. create_or_update || raise(RecordNotSaved)
  2369. end
  2370. # Deletes the record in the database and freezes this instance to
  2371. # reflect that no changes should be made (since they can't be
  2372. # persisted). Returns the frozen instance.
  2373. #
  2374. # The row is simply removed with a SQL +DELETE+ statement on the
  2375. # record's primary key, and no callbacks are executed.
  2376. #
  2377. # To enforce the object's +before_destroy+ and +after_destroy+
  2378. # callbacks, Observer methods, or any <tt>:dependent</tt> association
  2379. # options, use <tt>#destroy</tt>.
  2380. def delete
  2381. self.class.delete(id) unless new_record?
  2382. @destroyed = true
  2383. freeze
  2384. end
  2385. # Deletes the record in the database and freezes this instance to reflect that no changes should
  2386. # be made (since they can't be persisted).
  2387. def destroy
  2388. unless new_record?
  2389. connection.delete(
  2390. "DELETE FROM #{self.class.quoted_table_name} " +
  2391. "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quoted_id}",
  2392. "#{self.class.name} Destroy"
  2393. )
  2394. end
  2395. @destroyed = true
  2396. freeze
  2397. end
  2398. # Returns a clone of the record that hasn't been assigned an id yet and
  2399. # is treated as a new record. Note that this is a "shallow" clone:
  2400. # it copies the object's attributes only, not its associations.
  2401. # The extent of a "deep" clone is application-specific and is therefore
  2402. # left to the application to implement according to its need.
  2403. def clone
  2404. attrs = clone_attributes(:read_attribute_before_type_cast)
  2405. attrs.delete(self.class.primary_key)
  2406. record = self.class.new
  2407. record.send :instance_variable_set, '@attributes', attrs
  2408. record
  2409. end
  2410. # Returns an instance of the specified +klass+ with the attributes of the current record. This is mostly useful in relation to
  2411. # single-table inheritance structures where you want a subclass to appear as the superclass. This can be used along with record
  2412. # identification in Action Pack to allow, say, <tt>Client < Company</tt> to do something like render <tt>:partial => @client.becomes(Company)</tt>
  2413. # to render that instance using the companies/company partial instead of clients/client.
  2414. #
  2415. # Note: The new instance will share a link to the same attributes as the original class. So any change to the attributes in either
  2416. # instance will affect the other.
  2417. def becomes(klass)
  2418. klass.new.tap do |became|
  2419. became.instance_variable_set("@attributes", @attributes)
  2420. became.instance_variable_set("@attributes_cache", @attributes_cache)
  2421. became.instance_variable_set("@new_record", new_record?)
  2422. end
  2423. end
  2424. # Updates a single attribute and saves the record without going through the normal validation procedure.
  2425. # This is especially useful for boolean flags on existing records. The regular +update_attribute+ method
  2426. # in Base is replaced with this when the validations module is mixed in, which it is by default.
  2427. def update_attribute(name, value)
  2428. send(name.to_s + '=', value)
  2429. save(false)
  2430. end
  2431. # Updates all the attributes from the passed-in Hash and saves the record. If the object is invalid, the saving will
  2432. # fail and false will be returned.
  2433. def update_attributes(attributes)
  2434. with_transaction_returning_status(:update_attributes_inside_transaction, attributes)
  2435. end
  2436. def update_attributes_inside_transaction(attributes) #:nodoc:
  2437. self.attributes = attributes
  2438. save
  2439. end
  2440. # Updates an object just like Base.update_attributes but calls save! instead of save so an exception is raised if the record is invalid.
  2441. def update_attributes!(attributes)
  2442. with_transaction_returning_status(:update_attributes_inside_transaction!, attributes)
  2443. end
  2444. def update_attributes_inside_transaction!(attributes) #:nodoc:
  2445. self.attributes = attributes
  2446. save!
  2447. end
  2448. # Initializes +attribute+ to zero if +nil+ and adds the value passed as +by+ (default is 1).
  2449. # The increment is performed directly on the underlying attribute, no setter is invoked.
  2450. # Only makes sense for number-based attributes. Returns +self+.
  2451. def increment(attribute, by = 1)
  2452. self[attribute] ||= 0
  2453. self[attribute] += by
  2454. self
  2455. end
  2456. # Wrapper around +increment+ that saves the record. This method differs from
  2457. # its non-bang version in that it passes through the attribute setter.
  2458. # Saving is not subjected to validation checks. Returns +true+ if the
  2459. # record could be saved.
  2460. def increment!(attribute, by = 1)
  2461. increment(attribute, by).update_attribute(attribute, self[attribute])
  2462. end
  2463. # Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
  2464. # The decrement is performed directly on the underlying attribute, no setter is invoked.
  2465. # Only makes sense for number-based attributes. Returns +self+.
  2466. def decrement(attribute, by = 1)
  2467. self[attribute] ||= 0
  2468. self[attribute] -= by
  2469. self
  2470. end
  2471. # Wrapper around +decrement+ that saves the record. This method differs from
  2472. # its non-bang version in that it passes through the attribute setter.
  2473. # Saving is not subjected to validation checks. Returns +true+ if the
  2474. # record could be saved.
  2475. def decrement!(attribute, by = 1)
  2476. decrement(attribute, by).update_attribute(attribute, self[attribute])
  2477. end
  2478. # Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
  2479. # if the predicate returns +true+ the attribute will become +false+. This
  2480. # method toggles directly the underlying value without calling any setter.
  2481. # Returns +self+.
  2482. def toggle(attribute)
  2483. self[attribute] = !send("#{attribute}?")
  2484. self
  2485. end
  2486. # Wrapper around +toggle+ that saves the record. This method differs from
  2487. # its non-bang version in that it passes through the attribute setter.
  2488. # Saving is not subjected to validation checks. Returns +true+ if the
  2489. # record could be saved.
  2490. def toggle!(attribute)
  2491. toggle(attribute).update_attribute(attribute, self[attribute])
  2492. end
  2493. # Reloads the attributes of this object from the database.
  2494. # The optional options argument is passed to find when reloading so you
  2495. # may do e.g. record.reload(:lock => true) to reload the same record with
  2496. # an exclusive row lock.
  2497. def reload(options = nil)
  2498. clear_aggregation_cache
  2499. clear_association_cache
  2500. @attributes.update(self.class.send(:with_exclusive_scope) { self.class.find(self.id, options) }.instance_variable_get('@attributes'))
  2501. @attributes_cache = {}
  2502. self
  2503. end
  2504. # Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
  2505. # "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).
  2506. # (Alias for the protected read_attribute method).
  2507. def [](attr_name)
  2508. read_attribute(attr_name)
  2509. end
  2510. # Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
  2511. # (Alias for the protected write_attribute method).
  2512. def []=(attr_name, value)
  2513. write_attribute(attr_name, value)
  2514. end
  2515. # Allows you to set all the attributes at once by passing in a hash with keys
  2516. # matching the attribute names (which again matches the column names).
  2517. #
  2518. # If +guard_protected_attributes+ is true (the default), then sensitive
  2519. # attributes can be protected from this form of mass-assignment by using
  2520. # the +attr_protected+ macro. Or you can alternatively specify which
  2521. # attributes *can* be accessed with the +attr_accessible+ macro. Then all the
  2522. # attributes not included in that won't be allowed to be mass-assigned.
  2523. #
  2524. # class User < ActiveRecord::Base
  2525. # attr_protected :is_admin
  2526. # end
  2527. #
  2528. # user = User.new
  2529. # user.attributes = { :username => 'Phusion', :is_admin => true }
  2530. # user.username # => "Phusion"
  2531. # user.is_admin? # => false
  2532. #
  2533. # user.send(:attributes=, { :username => 'Phusion', :is_admin => true }, false)
  2534. # user.is_admin? # => true
  2535. def attributes=(new_attributes, guard_protected_attributes = true)
  2536. return if new_attributes.nil?
  2537. attributes = new_attributes.dup
  2538. attributes.stringify_keys!
  2539. attributes = remove_attributes_protected_from_mass_assignment(attributes) if guard_protected_attributes
  2540. assign_attributes(attributes) if attributes and attributes.any?
  2541. end
  2542. # Returns a hash of all the attributes with their names as keys and the values of the attributes as values.
  2543. def attributes
  2544. attrs = {}
  2545. attribute_names.each { |name| attrs[name] = read_attribute(name) }
  2546. attrs
  2547. end
  2548. # Returns a hash of attributes before typecasting and deserialization.
  2549. def attributes_before_type_cast
  2550. self.attribute_names.inject({}) do |attrs, name|
  2551. attrs[name] = read_attribute_before_type_cast(name)
  2552. attrs
  2553. end
  2554. end
  2555. # Returns an <tt>#inspect</tt>-like string for the value of the
  2556. # attribute +attr_name+. String attributes are elided after 50
  2557. # characters, and Date and Time attributes are returned in the
  2558. # <tt>:db</tt> format. Other attributes return the value of
  2559. # <tt>#inspect</tt> without modification.
  2560. #
  2561. # person = Person.create!(:name => "David Heinemeier Hansson " * 3)
  2562. #
  2563. # person.attribute_for_inspect(:name)
  2564. # # => '"David Heinemeier Hansson David Heinemeier Hansson D..."'
  2565. #
  2566. # person.attribute_for_inspect(:created_at)
  2567. # # => '"2009-01-12 04:48:57"'
  2568. def attribute_for_inspect(attr_name)
  2569. value = read_attribute(attr_name)
  2570. if value.is_a?(String) && value.length > 50
  2571. "#{value[0..50]}...".inspect
  2572. elsif value.is_a?(Date) || value.is_a?(Time)
  2573. %("#{value.to_s(:db)}")
  2574. else
  2575. value.inspect
  2576. end
  2577. end
  2578. # Returns true if the specified +attribute+ has been set by the user or by a database load and is neither
  2579. # nil nor empty? (the latter only applies to objects that respond to empty?, most notably Strings).
  2580. def attribute_present?(attribute)
  2581. value = read_attribute(attribute)
  2582. !value.blank?
  2583. end
  2584. # Returns true if the given attribute is in the attributes hash
  2585. def has_attribute?(attr_name)
  2586. @attributes.has_key?(attr_name.to_s)
  2587. end
  2588. # Returns an array of names for the attributes available on this object sorted alphabetically.
  2589. def attribute_names
  2590. @attributes.keys.sort
  2591. end
  2592. # Returns the column object for the named attribute.
  2593. def column_for_attribute(name)
  2594. self.class.columns_hash[name.to_s]
  2595. end
  2596. # Returns true if the +comparison_object+ is the same object, or is of the same type and has the same id.
  2597. def ==(comparison_object)
  2598. comparison_object.equal?(self) ||
  2599. (comparison_object.instance_of?(self.class) &&
  2600. comparison_object.id == id &&
  2601. !comparison_object.new_record?)
  2602. end
  2603. # Delegates to ==
  2604. def eql?(comparison_object)
  2605. self == (comparison_object)
  2606. end
  2607. # Delegates to id in order to allow two records of the same type and id to work with something like:
  2608. # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
  2609. def hash
  2610. id.hash
  2611. end
  2612. # Freeze the attributes hash such that associations are still accessible, even on destroyed records.
  2613. def freeze
  2614. @attributes.freeze; self
  2615. end
  2616. # Returns +true+ if the attributes hash has been frozen.
  2617. def frozen?
  2618. @attributes.frozen?
  2619. end
  2620. # Returns +true+ if the record has been destroyed.
  2621. def destroyed?
  2622. @destroyed
  2623. end
  2624. # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
  2625. # attributes will be marked as read only since they cannot be saved.
  2626. def readonly?
  2627. defined?(@readonly) && @readonly == true
  2628. end
  2629. # Marks this record as read only.
  2630. def readonly!
  2631. @readonly = true
  2632. end
  2633. # Returns the contents of the record as a nicely formatted string.
  2634. def inspect
  2635. attributes_as_nice_string = self.class.column_names.collect { |name|
  2636. if has_attribute?(name) || new_record?
  2637. "#{name}: #{attribute_for_inspect(name)}"
  2638. end
  2639. }.compact.join(", ")
  2640. "#<#{self.class} #{attributes_as_nice_string}>"
  2641. end
  2642. private
  2643. # Assigns attributes, dealing nicely with both multi and single paramater attributes
  2644. # Assumes attributes is a hash
  2645. def assign_attributes(attributes={})
  2646. multiparameter_attributes = []
  2647. attributes.each do |k, v|
  2648. if k.to_s.include?("(")
  2649. multiparameter_attributes << [ k, v ]
  2650. else
  2651. respond_to?(:"#{k}=") ? send(:"#{k}=", v) : raise(UnknownAttributeError, "unknown attribute: #{k}")
  2652. end
  2653. end
  2654. assign_multiparameter_attributes(multiparameter_attributes) unless multiparameter_attributes.empty?
  2655. end
  2656. def create_or_update
  2657. raise ReadOnlyRecord if readonly?
  2658. result = new_record? ? create : update
  2659. result != false
  2660. end
  2661. # Updates the associated record with values matching those of the instance attributes.
  2662. # Returns the number of affected rows.
  2663. def update(attribute_names = @attributes.keys)
  2664. quoted_attributes = attributes_with_quotes(false, false, attribute_names)
  2665. return 0 if quoted_attributes.empty?
  2666. connection.update(
  2667. "UPDATE #{self.class.quoted_table_name} " +
  2668. "SET #{quoted_comma_pair_list(connection, quoted_attributes)} " +
  2669. "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quote_value(id)}",
  2670. "#{self.class.name} Update"
  2671. )
  2672. end
  2673. # Creates a record with values matching those of the instance attributes
  2674. # and returns its id.
  2675. def create
  2676. if self.id.nil? && connection.prefetch_primary_key?(self.class.table_name)
  2677. self.id = connection.next_sequence_value(self.class.sequence_name)
  2678. end
  2679. quoted_attributes = attributes_with_quotes
  2680. statement = if quoted_attributes.empty?
  2681. connection.empty_insert_statement(self.class.table_name)
  2682. else
  2683. "INSERT INTO #{self.class.quoted_table_name} " +
  2684. "(#{quoted_column_names.join(', ')}) " +
  2685. "VALUES(#{quoted_attributes.values.join(', ')})"
  2686. end
  2687. self.id = connection.insert(statement, "#{self.class.name} Create",
  2688. self.class.primary_key, self.id, self.class.sequence_name)
  2689. @new_record = false
  2690. id
  2691. end
  2692. # Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord::Base descendant.
  2693. # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to do Reply.new without having to
  2694. # set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself. No such attribute would be set for objects of the
  2695. # Message class in that example.
  2696. def ensure_proper_type
  2697. unless self.class.descends_from_active_record?
  2698. write_attribute(self.class.inheritance_column, self.class.sti_name)
  2699. end
  2700. end
  2701. def convert_number_column_value(value)
  2702. if value == false
  2703. 0
  2704. elsif value == true
  2705. 1
  2706. elsif value.is_a?(String) && value.blank?
  2707. nil
  2708. else
  2709. value
  2710. end
  2711. end
  2712. def remove_attributes_protected_from_mass_assignment(attributes)
  2713. safe_attributes =
  2714. if self.class.accessible_attributes.nil? && self.class.protected_attributes.nil?
  2715. attributes.reject { |key, value| attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) }
  2716. elsif self.class.protected_attributes.nil?
  2717. attributes.reject { |key, value| !self.class.accessible_attributes.include?(key.gsub(/\(.+/, "")) || attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) }
  2718. elsif self.class.accessible_attributes.nil?
  2719. attributes.reject { |key, value| self.class.protected_attributes.include?(key.gsub(/\(.+/,"")) || attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) }
  2720. else
  2721. raise "Declare either attr_protected or attr_accessible for #{self.class}, but not both."
  2722. end
  2723. removed_attributes = attributes.keys - safe_attributes.keys
  2724. if removed_attributes.any?
  2725. log_protected_attribute_removal(removed_attributes)
  2726. end
  2727. safe_attributes
  2728. end
  2729. # Removes attributes which have been marked as readonly.
  2730. def remove_readonly_attributes(attributes)
  2731. unless self.class.readonly_attributes.nil?
  2732. attributes.delete_if { |key, value| self.class.readonly_attributes.include?(key.gsub(/\(.+/,"")) }
  2733. else
  2734. attributes
  2735. end
  2736. end
  2737. def log_protected_attribute_removal(*attributes)
  2738. logger.debug "WARNING: Can't mass-assign these protected attributes: #{attributes.join(', ')}"
  2739. end
  2740. # The primary key and inheritance column can never be set by mass-assignment for security reasons.
  2741. def attributes_protected_by_default
  2742. default = [ self.class.primary_key, self.class.inheritance_column ]
  2743. default << 'id' unless self.class.primary_key.eql? 'id'
  2744. default
  2745. end
  2746. # Returns a copy of the attributes hash where all the values have been safely quoted for use in
  2747. # an SQL statement.
  2748. def attributes_with_quotes(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
  2749. quoted = {}
  2750. connection = self.class.connection
  2751. attribute_names.each do |name|
  2752. if (column = column_for_attribute(name)) && (include_primary_key || !column.primary)
  2753. value = read_attribute(name)
  2754. # We need explicit to_yaml because quote() does not properly convert Time/Date fields to YAML.
  2755. if value && self.class.serialized_attributes.has_key?(name) && (value.acts_like?(:date) || value.acts_like?(:time))
  2756. value = value.to_yaml
  2757. end
  2758. quoted[name] = connection.quote(value, column)
  2759. end
  2760. end
  2761. include_readonly_attributes ? quoted : remove_readonly_attributes(quoted)
  2762. end
  2763. # Quote strings appropriately for SQL statements.
  2764. def quote_value(value, column = nil)
  2765. self.class.connection.quote(value, column)
  2766. end
  2767. # Interpolate custom SQL string in instance context.
  2768. # Optional record argument is meant for custom insert_sql.
  2769. def interpolate_sql(sql, record = nil)
  2770. instance_eval("%@#{sql.gsub('@', '\@')}@")
  2771. end
  2772. # Initializes the attributes array with keys matching the columns from the linked table and
  2773. # the values matching the corresponding default value of that column, so
  2774. # that a new instance, or one populated from a passed-in Hash, still has all the attributes
  2775. # that instances loaded from the database would.
  2776. def attributes_from_column_definition
  2777. self.class.columns.inject({}) do |attributes, column|
  2778. attributes[column.name] = column.default unless column.name == self.class.primary_key
  2779. attributes
  2780. end
  2781. end
  2782. # Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
  2783. # by calling new on the column type or aggregation type (through composed_of) object with these parameters.
  2784. # So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
  2785. # written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
  2786. # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum, f for Float,
  2787. # s for String, and a for Array. If all the values for a given attribute are empty, the attribute will be set to nil.
  2788. def assign_multiparameter_attributes(pairs)
  2789. execute_callstack_for_multiparameter_attributes(
  2790. extract_callstack_for_multiparameter_attributes(pairs)
  2791. )
  2792. end
  2793. def instantiate_time_object(name, values)
  2794. if self.class.send(:create_time_zone_conversion_attribute?, name, column_for_attribute(name))
  2795. Time.zone.local(*values)
  2796. else
  2797. Time.time_with_datetime_fallback(@@default_timezone, *values)
  2798. end
  2799. end
  2800. def execute_callstack_for_multiparameter_attributes(callstack)
  2801. errors = []
  2802. callstack.each do |name, values_with_empty_parameters|
  2803. begin
  2804. klass = (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)).klass
  2805. # in order to allow a date to be set without a year, we must keep the empty values.
  2806. # Otherwise, we wouldn't be able to distinguish it from a date with an empty day.
  2807. values = values_with_empty_parameters.reject(&:nil?)
  2808. if values.empty?
  2809. send(name + "=", nil)
  2810. else
  2811. value = if Time == klass
  2812. instantiate_time_object(name, values)
  2813. elsif Date == klass
  2814. begin
  2815. values = values_with_empty_parameters.collect do |v| v.nil? ? 1 : v end
  2816. Date.new(*values)
  2817. rescue ArgumentError => ex # if Date.new raises an exception on an invalid date
  2818. instantiate_time_object(name, values).to_date # we instantiate Time object and convert it back to a date thus using Time's logic in handling invalid dates
  2819. end
  2820. else
  2821. klass.new(*values)
  2822. end
  2823. send(name + "=", value)
  2824. end
  2825. rescue => ex
  2826. errors << AttributeAssignmentError.new("error on assignment #{values.inspect} to #{name}", ex, name)
  2827. end
  2828. end
  2829. unless errors.empty?
  2830. raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes"
  2831. end
  2832. end
  2833. def extract_callstack_for_multiparameter_attributes(pairs)
  2834. attributes = { }
  2835. for pair in pairs
  2836. multiparameter_name, value = pair
  2837. attribute_name = multiparameter_name.split("(").first
  2838. attributes[attribute_name] = [] unless attributes.include?(attribute_name)
  2839. parameter_value = value.empty? ? nil : type_cast_attribute_value(multiparameter_name, value)
  2840. attributes[attribute_name] << [ find_parameter_position(multiparameter_name), parameter_value ]
  2841. end
  2842. attributes.each { |name, values| attributes[name] = values.sort_by{ |v| v.first }.collect { |v| v.last } }
  2843. end
  2844. def type_cast_attribute_value(multiparameter_name, value)
  2845. multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value
  2846. end
  2847. def find_parameter_position(multiparameter_name)
  2848. multiparameter_name.scan(/\(([0-9]*).*\)/).first.first
  2849. end
  2850. # Returns a comma-separated pair list, like "key1 = val1, key2 = val2".
  2851. def comma_pair_list(hash)
  2852. hash.map { |k,v| "#{k} = #{v}" }.join(", ")
  2853. end
  2854. def quoted_column_names(attributes = attributes_with_quotes)
  2855. connection = self.class.connection
  2856. attributes.keys.collect do |column_name|
  2857. connection.quote_column_name(column_name)
  2858. end
  2859. end
  2860. def self.quoted_table_name
  2861. self.connection.quote_table_name(self.table_name)
  2862. end
  2863. def quote_columns(quoter, hash)
  2864. hash.inject({}) do |quoted, (name, value)|
  2865. quoted[quoter.quote_column_name(name)] = value
  2866. quoted
  2867. end
  2868. end
  2869. def quoted_comma_pair_list(quoter, hash)
  2870. comma_pair_list(quote_columns(quoter, hash))
  2871. end
  2872. def object_from_yaml(string)
  2873. return string unless string.is_a?(String) && string =~ /^---/
  2874. YAML::load(string) rescue string
  2875. end
  2876. def clone_attributes(reader_method = :read_attribute, attributes = {})
  2877. self.attribute_names.inject(attributes) do |attrs, name|
  2878. attrs[name] = clone_attribute_value(reader_method, name)
  2879. attrs
  2880. end
  2881. end
  2882. def clone_attribute_value(reader_method, attribute_name)
  2883. value = send(reader_method, attribute_name)
  2884. value.duplicable? ? value.clone : value
  2885. rescue TypeError, NoMethodError
  2886. value
  2887. end
  2888. end
  2889. Base.class_eval do
  2890. extend QueryCache::ClassMethods
  2891. include Validations
  2892. include Locking::Optimistic, Locking::Pessimistic
  2893. include AttributeMethods
  2894. include Dirty
  2895. include Callbacks, Observing, Timestamp
  2896. include Associations, AssociationPreload, NamedScope
  2897. # AutosaveAssociation needs to be included before Transactions, because we want
  2898. # #save_with_autosave_associations to be wrapped inside a transaction.
  2899. include AutosaveAssociation, NestedAttributes
  2900. include Aggregations, Transactions, Reflection, Batches, Calculations, Serialization
  2901. end
  2902. end
  2903. # TODO: Remove this and make it work with LAZY flag
  2904. require 'active_record/connection_adapters/abstract_adapter'