Class: ActiveRecord::Base
Active Record objects don‘t specify their attributes directly, but rather infer them from the table definition with which they‘re linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.
See the mapping rules in table_name and the full example in files/README.html for more insight.
Creation
Active Records accept constructor parameters either in a hash or as a block. The hash method is especially useful when you‘re receiving the data from somewhere else, like an HTTP request. It works like this:
user = User.new(:name => "David", :occupation => "Code Artist") user.name # => "David"
You can also use block initialization:
user = User.new do |u|
u.name = "David"
u.occupation = "Code Artist"
end
And of course you can just create a bare object and specify the attributes after the fact:
user = User.new user.name = "David" user.occupation = "Code Artist"
Conditions
Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement. The array form is to be used when the condition input is tainted and requires sanitization. The string form can be used for statements that don‘t involve tainted data. The hash form works much like the array form, except only equality and range is possible. Examples:
class User < ActiveRecord::Base
def self.authenticate_unsafely(user_name, password)
find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'")
end
def self.authenticate_safely(user_name, password)
find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ])
end
def self.authenticate_safely_simply(user_name, password)
find(:first, :conditions => { :user_name => user_name, :password => password })
end
end
The authenticate_unsafely method inserts the parameters directly into the query and is thus susceptible to SQL-injection attacks if the user_name and password parameters come directly from an HTTP request. The authenticate_safely and authenticate_safely_simply both will sanitize the user_name and password before inserting them in the query, which will ensure that an attacker can‘t escape the query and fake the login (or worse).
When using multiple parameters in the conditions, it can easily become hard to read exactly what the fourth or fifth question mark is supposed to represent. In those cases, you can resort to named bind variables instead. That‘s done by replacing the question marks with symbols and supplying a hash with values for the matching symbol keys:
Company.find(:first, :conditions => [
"id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
{ :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' }
])
Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND operator. For instance:
Student.find(:all, :conditions => { :first_name => "Harvey", :status => 1 })
Student.find(:all, :conditions => params[:student])
A range may be used in the hash to use the SQL BETWEEN operator:
Student.find(:all, :conditions => { :grade => 9..12 })
Overwriting default accessors
All column values are automatically available through basic accessors on the Active Record object, but sometimes you want to specialize this behavior. This can be done by overwriting the default accessors (using the same name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things. Example:
class Song < ActiveRecord::Base
# Uses an integer of seconds to hold the length of the song
def length=(minutes)
write_attribute(:length, minutes * 60)
end
def length
read_attribute(:length) / 60
end
end
You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and read_attribute(:attribute) as a shorter form.
Attribute query methods
In addition to the basic accessors, query methods are also automatically available on the Active Record object. Query methods allow you to test whether an attribute value is present.
For example, an Active Record User with the name attribute has a name? method that you can call to determine whether the user has a name:
user = User.new(:name => "David") user.name? # => true anonymous = User.new(:name => "") anonymous.name? # => false
Accessing attributes before they have been typecasted
Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first. That can be done by using the <attribute>_before_type_cast accessors that all attributes have. For example, if your Account model has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast.
This is especially useful in validation situations where the user might supply a string for an integer field and you want to display the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn‘t what you want.
Dynamic attribute-based finders
Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by appending the name of an attribute to find_by_ or find_all_by_, so you get finders like Person.find_by_user_name, Person.find_all_by_last_name, Payment.find_by_transaction_id. So instead of writing Person.find(:first, :conditions => ["user_name = ?", user_name]), you just do Person.find_by_user_name(user_name). And instead of writing Person.find(:all, :conditions => ["last_name = ?", last_name]), you just do Person.find_all_by_last_name(last_name).
It‘s also possible to use multiple attributes in the same find by separating them with "and", so you get finders like Person.find_by_user_name_and_password or even Payment.find_by_purchaser_and_state_and_country. So instead of writing Person.find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password]), you just do Person.find_by_user_name_and_password(user_name, password).
It‘s even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is actually Person.find_by_user_name(user_name, options). So you could call Payment.find_all_by_amount(50, :order => "created_on").
The same dynamic finder style can be used to create the object if it doesn‘t already exist. This dynamic finder is called with find_or_create_by_ 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:
# No 'Summer' tag exists
Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")
# Now the 'Summer' tag does exist
Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
# Now 'Bob' exist and is an 'admin'
User.find_or_create_by_name('Bob', :age => 40) { |u| u.admin = true }
Use the find_or_initialize_by_ finder if you want to return a new record without saving it first. Protected attributes won‘t be setted unless they are given in a block. For example:
# No 'Winter' tag exists
winter = Tag.find_or_initialize_by_name("Winter")
winter.new_record? # true
To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of a list of parameters. For example:
Tag.find_or_create_by_name(:name => "rails", :creator => current_user)
That will either find an existing tag named "rails", or create a new one while setting the user that created it.
Saving arrays, hashes, and other non-mappable objects in text columns
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. This makes it possible to store arrays, hashes, and other non-mappable objects without doing any additional work. Example:
class User < ActiveRecord::Base
serialize :preferences
end
user = User.create(:preferences => { "background" => "black", "display" => large })
User.find(user.id).preferences # => { "background" => "black", "display" => large }
You can also specify a class option as the second parameter that‘ll raise an exception if a serialized object is retrieved as a descendent of a class not in the hierarchy. Example:
class User < ActiveRecord::Base
serialize :preferences, Hash
end
user = User.create(:preferences => %w( one two three ))
User.find(user.id).preferences # raises SerializationTypeMismatch
Single table inheritance
Active Record allows inheritance by storing the name of the class in a column that by default is named "type" (can be changed by overwriting Base.inheritance_column). This means that an inheritance looking like this:
class Company < ActiveRecord::Base; end class Firm < Company; end class Client < Company; end class PriorityClient < Client; end
When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then fetch this row again using Company.find(:first, "name = ‘37signals’") and it will return a Firm object.
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 like normal subclasses with no special magic for differentiating between them or reloading the right type with find.
Note, all the attributes for all the cases are kept in the same table. Read more: www.martinfowler.com/eaaCatalog/singleTableInheritance.html
Connection to multiple databases in different models
Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection. All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection. For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection and Course *and all its subclasses* will use this connection instead.
This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool.
Exceptions
- ActiveRecordError — generic error class and superclass of all other errors raised by Active Record
- AdapterNotSpecified — the configuration hash used in establish_connection didn‘t include an :adapter key.
- AdapterNotFound — the :adapter key used in establish_connection specified a non-existent adapter (or a bad spelling of an existing one).
- AssociationTypeMismatch — the object assigned to the association wasn‘t of the type specified in the association definition.
- SerializationTypeMismatch — the serialized object wasn‘t of the class specified as the second parameter.
- ConnectionNotEstablished — no connection has been established. Use establish_connection before querying.
- RecordNotFound — no record responded to the find* method. Either the row with the given ID doesn‘t exist or the row didn‘t meet the additional restrictions.
- StatementInvalid — the database server rejected the SQL statement. The precise error is added in the message. Either the record with the given ID doesn‘t exist or the record didn‘t meet the additional restrictions.
- MultiparameterAssignmentErrors — collection of errors that occurred during a mass assignment using the +attributes=+ method. The errors property of this exception contains an array of AttributeAssignmentError objects that should be inspected to determine which attributes triggered the errors.
- AttributeAssignmentError — an error occurred while doing a mass assignment through the +attributes=+ method. You can inspect the attribute property of the exception object to determine which attribute triggered the error.
Note: The attributes listed are class-level attributes (accessible from both the class and instance level). So it‘s possible to assign a logger to the class through Base.logger= which will then be used by all instances in the current object space.
Child modules and classes
Class ActiveRecord::Base::ConnectionSpecification
Constants
| Name | Value |
|---|---|
| VALID_FIND_OPTIONS | [ :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :group, :from, :lock ] |
Aliases
| Old name | New name |
|---|---|
| set_table_name | table_name= |
| set_primary_key | primary_key= |
| set_inheritance_column | inheritance_column= |
| set_sequence_name | sequence_name= |
| sanitize_sql_for_conditions | sanitize_sql |
| sanitize_sql_hash_for_conditions | sanitize_sql_hash |
| sanitize_sql | sanitize_conditions |
Attributes
| Name | Read/write? |
|---|---|
| abstract_class | RW |
Public Class Methods
=== (object)
Overwrite the default class equality method to provide support for association proxies.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1241 1241: def ===(object) 1242: object.is_a?(self) 1243: end
abstract_class? ()
Returns whether this class is a base AR class. If A is a base class and B descends from A, then B.base_class will return B.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1257 1257: def abstract_class? 1258: defined?(@abstract_class) && @abstract_class == true 1259: end
accessible_attributes (
Returns an array of all the attributes that have been made accessible to mass-assignment.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 890 890: def accessible_attributes # nodoc 891: read_inheritable_attribute("attr_accessible") 892: end
active_connection_name (
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 54 54: def active_connection_name #nodoc 55: @active_connection_name ||= 56: if active_connections[name] || @@defined_connections[name] 57: name 58: elsif self == ActiveRecord::Base 59: nil 60: else 61: superclass.active_connection_name 62: end 63: end
allow_concurrency= (threaded)
set concurrency support flag (not thread safe, like most of the methods in this file)
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 41 41: def allow_concurrency=(threaded) #nodoc 42: logger.debug "allow_concurrency=#{threaded}" if logger 43: return if @@allow_concurrency == threaded 44: clear_all_cached_connections! 45: @@allow_concurrency = threaded 46: method_prefix = threaded ? "thread_safe" : "single_threaded" 47: sing = (class << self; self; end) 48: [:active_connections, :scoped_methods].each do |method| 49: sing.send(:alias_method, method, "#{method_prefix}_#{method}") 50: end 51: log_connections if logger 52: end
attr_accessible (*attributes)
Similar to the attr_protected macro, this protects attributes of your model from mass-assignment, such as new(attributes) and attributes=(attributes) however, it does it in the opposite way. This locks all attributes and only allows access to the attributes specified. Assignment to attributes not in this list will be ignored and need to be set using the direct writer methods instead. This is meant to protect sensitive attributes from being overwritten by URL/form hackers. If you‘d rather start from an all-open default and restrict attributes as needed, have a look at attr_protected.
Options
*attributes A comma separated list of symbols that represent columns not to be protected
Examples
class Customer < ActiveRecord::Base
attr_accessible :name, :nickname
end
customer = Customer.new(:name => "David", :nickname => "Dave", :credit_rating => "Excellent")
customer.credit_rating # => nil
customer.attributes = { :name => "Jolly fellow", :credit_rating => "Superb" }
customer.credit_rating # => nil
customer.credit_rating = "Average"
customer.credit_rating # => "Average"
# File vendor/rails/activerecord/lib/active_record/base.rb, line 885 885: def attr_accessible(*attributes) 886: write_inheritable_attribute("attr_accessible", Set.new(attributes.map(&:to_s)) + (accessible_attributes || [])) 887: end
attr_protected (*attributes)
Attributes named in this macro are protected from mass-assignment, such as new(attributes) and attributes=(attributes). Their assignment will simply be ignored. Instead, you can use the direct writer methods to do assignment. This is meant to protect sensitive attributes from being overwritten by URL/form hackers. Example:
class Customer < ActiveRecord::Base
attr_protected :credit_rating
end
customer = Customer.new("name" => David, "credit_rating" => "Excellent")
customer.credit_rating # => nil
customer.attributes = { "description" => "Jolly fellow", "credit_rating" => "Superb" }
customer.credit_rating # => nil
customer.credit_rating = "Average"
customer.credit_rating # => "Average"
To start from an all-closed default and enable attributes as needed, have a look at attr_accessible.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 851 851: def attr_protected(*attributes) 852: write_inheritable_attribute("attr_protected", Set.new(attributes.map(&:to_s)) + (protected_attributes || [])) 853: end
attr_readonly (*attributes)
Attributes listed as readonly can be set for a new record, but will be ignored in database updates afterwards.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 895 895: def attr_readonly(*attributes) 896: write_inheritable_attribute("attr_readonly", Set.new(attributes.map(&:to_s)) + (readonly_attributes || [])) 897: end
base_class ()
Returns the base AR subclass that this class descends from. If A extends AR::Base, A.base_class will return A. If B descends from A through some arbitrarily deep hierarchy, B.base_class will return A.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1248 1248: def base_class 1249: class_of_active_record_descendant(self) 1250: end
benchmark (title, log_level = Logger::DEBUG, use_silence = true) {|| ...}
Log and benchmark multiple statements in a single block. Example:
Project.benchmark("Creating project") do
project = Project.create("name" => "stuff")
project.create_manager("name" => "David")
project.milestones << Milestone.find(:all)
end
The benchmark is only recorded if the current level of the logger is less than or equal to the log_level, which makes it easy to include benchmarking statements in production software that will remain inexpensive because the benchmark will only be conducted if the log level is low enough.
The logging of the multiple statements is turned off unless use_silence is set to false.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1221 1221: def benchmark(title, log_level = Logger::DEBUG, use_silence = true) 1222: if logger && logger.level <= log_level 1223: result = nil 1224: seconds = Benchmark.realtime { result = use_silence ? silence { yield } : yield } 1225: logger.add(log_level, "#{title} (#{'%.5f' % seconds})") 1226: result 1227: else 1228: yield 1229: end 1230: end
class_name (table_name = table_name)
Turns the table_name back into a class name following the reverse rules of table_name.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1091 1091: def class_name(table_name = table_name) # nodoc 1092: # remove any prefix and/or suffix from the table name 1093: class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].camelize 1094: class_name = class_name.singularize if pluralize_table_names 1095: class_name 1096: end
clear_active_connection_name (
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 65 65: def clear_active_connection_name #nodoc 66: @active_connection_name = nil 67: subclasses.each { |klass| klass.clear_active_connection_name } 68: end
clear_active_connections! ()
Clears the cache which maps classes to connections.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 84 84: def clear_active_connections! 85: clear_cache!(@@active_connections) do |name, conn| 86: conn.disconnect! 87: end 88: end
clear_reloadable_connections! ()
Clears the cache which maps classes
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 91 91: def clear_reloadable_connections! 92: if @@allow_concurrency 93: # With concurrent connections @@active_connections is 94: # a hash keyed by thread id. 95: @@active_connections.each do |thread_id, conns| 96: conns.each do |name, conn| 97: if conn.requires_reloading? 98: conn.disconnect! 99: @@active_connections[thread_id].delete(name) 100: end 101: end 102: end 103: else 104: @@active_connections.each do |name, conn| 105: if conn.requires_reloading? 106: conn.disconnect! 107: @@active_connections.delete(name) 108: end 109: end 110: end 111: end
column_methods_hash (
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 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 is available.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1142 1142: def column_methods_hash #nodoc 1143: @dynamic_methods_hash ||= column_names.inject(Hash.new(false)) do |methods, attr| 1144: attr_name = attr.to_s 1145: methods[attr.to_sym] = attr_name 1146: methods["#{attr}=".to_sym] = attr_name 1147: methods["#{attr}?".to_sym] = attr_name 1148: methods["#{attr}_before_type_cast".to_sym] = attr_name 1149: methods 1150: end 1151: end
column_names ()
Returns an array of column names as strings.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1129 1129: def column_names 1130: @column_names ||= columns.map { |column| column.name } 1131: end
columns ()
Returns an array of column objects for the table associated with this class.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1115 1115: def columns 1116: unless defined?(@columns) && @columns 1117: @columns = connection.columns(table_name, "#{name} Columns") 1118: @columns.each { |column| column.primary = column.name == primary_key } 1119: end 1120: @columns 1121: end
columns_hash ()
Returns a hash of column objects for the table associated with this class.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1124 1124: def columns_hash 1125: @columns_hash ||= columns.inject({}) { |hash, column| hash[column.name] = column; hash } 1126: end
connected? ()
Returns true if a connection that‘s accessible to this class has already been opened.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 268 268: def self.connected? 269: active_connections[active_connection_name] ? true : false 270: end
connection ()
Returns the connection currently associated with the class. This can also be used to "borrow" the connection to do database work unrelated to any of the specific Active Records.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 73 73: def connection 74: if defined?(@active_connection_name) && (conn = active_connections[@active_connection_name]) 75: conn 76: else 77: # retrieve_connection sets the cache key. 78: conn = retrieve_connection 79: active_connections[@active_connection_name] = conn 80: end 81: end
connection= (spec)
Set the connection for the class.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 286 286: def self.connection=(spec) #nodoc 287: if spec.kind_of?(ActiveRecord::ConnectionAdapters::AbstractAdapter) 288: active_connections[name] = spec 289: elsif spec.kind_of?(ConnectionSpecification) 290: config = spec.config.reverse_merge(:allow_concurrency => @@allow_concurrency) 291: self.connection = self.send(spec.adapter_method, config) 292: elsif spec.nil? 293: raise ConnectionNotEstablished 294: else 295: establish_connection spec 296: end 297: end
content_columns ()
Returns an array of column objects where the primary id, all columns ending in "_id" or "_count", and columns used for single table inheritance have been removed.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1135 1135: def content_columns 1136: @content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column } 1137: end
count_by_sql (sql)
Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part. The use of this method should be restricted to complicated SQL queries that can‘t be executed using the ActiveRecord::Calculations class methods. Look into those before using this.
Options
sql: An SQL statement which should return a count query from the database, see the example below
Examples
Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
# File vendor/rails/activerecord/lib/active_record/base.rb, line 761 761: def count_by_sql(sql) 762: sql = sanitize_conditions(sql) 763: connection.select_value(sql, "#{name} Count").to_i 764: end
create (attributes = nil)
Creates an object (or multiple objects) and saves it to the database, if validations pass. The resulting object is returned whether the object was saved successfully to the database or not.
The attributes parameter can be either be a Hash or an Array of Hashes. These Hashes describe the attributes on the objects that are to be created.
Examples
# Create a single new object
User.create(:first_name => 'Jamie')
# Create an Array of new objects
User.create([{:first_name => 'Jamie'}, {:first_name => 'Jeremy'}])
# File vendor/rails/activerecord/lib/active_record/base.rb, line 595 595: def create(attributes = nil) 596: if attributes.is_a?(Array) 597: attributes.collect { |attr| create(attr) } 598: else 599: object = new(attributes) 600: object.save 601: object 602: end 603: end
decrement_counter (counter_name, id)
Decrement a number field by one, usually representing a count.
This works the same as increment_counter but reduces the column value by 1 instead of increasing it.
Options
counter_name The name of the field that should be decremented id The id of the object that should be decremented
Examples
# Decrement the post_count column for the record with an id of 5 DiscussionBoard.decrement_counter(:post_count, 5)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 829 829: def decrement_counter(counter_name, id) 830: update_counters(id, counter_name => -1) 831: end
delete (id)
Delete an object (or multiple objects) where the id given matches the primary_key. A SQL DELETE command is executed on the database which means that no callbacks are fired off running this. This is an efficient method of deleting records that don‘t need cleaning up after or other actions to be taken.
Objects are not instantiated with this method.
Options
id Can be either an Integer or an Array of Integers
Examples
# Delete a single object Todo.delete(1) # Delete multiple objects todos = [1,2,3] Todo.delete(todos)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 650 650: def delete(id) 651: delete_all([ "#{connection.quote_column_name(primary_key)} IN (?)", id ]) 652: end
delete_all (conditions = nil)
Deletes the records matching conditions without instantiating the records first, and hence not calling the destroy method and invoking callbacks. This is a single SQL query, much more efficient than destroy_all.
Options
conditions Conditions are specified the same way as with find method.
Example
Post.delete_all "person_id = 5 AND (category = 'Something' OR category = 'Else')"
This deletes the affected posts all at once with a single DELETE query. If you need to destroy dependent associations or call your before_ or after_destroy callbacks, use the destroy_all method instead.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 744 744: def delete_all(conditions = nil) 745: sql = "DELETE FROM #{quoted_table_name} " 746: add_conditions!(sql, conditions, scope(:find)) 747: connection.delete(sql, "#{name} Delete all") 748: end
descends_from_active_record? ()
True if this isn‘t a concrete subclass needing a STI type condition.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1171 1171: def descends_from_active_record? 1172: if superclass.abstract_class? 1173: superclass.descends_from_active_record? 1174: else 1175: superclass == Base || !columns_hash.include?(inheritance_column) 1176: end 1177: end
destroy (id)
Destroy an object (or multiple objects) that has the given id, the object is instantiated first, therefore all callbacks and filters are fired off before the object is deleted. This method is less efficient than ActiveRecord#delete but allows cleanup methods and other actions to be run.
This essentially finds the object (or multiple objects) with the given id, creates a new object from the attributes, and then calls destroy on it.
Options
id Can be either an Integer or an Array of Integers
Examples
# Destroy a single object Todo.destroy(1) # Destroy multiple objects todos = [1,2,3] Todo.destroy(todos)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 673 673: def destroy(id) 674: if id.is_a?(Array) 675: id.map { |one_id| destroy(one_id) } 676: else 677: find(id).destroy 678: end 679: end
destroy_all (conditions = nil)
Destroys the records matching conditions by instantiating each record and calling the destroy method. This means at least 2*N database queries to destroy N records, so avoid destroy_all if you are deleting many records. If you want to simply delete records without worrying about dependent associations or callbacks, use the much faster delete_all method instead.
Options
conditions Conditions are specified the same way as with find method.
Example
Person.destroy_all "last_login < '2004-04-04'"
This loads and destroys each person one by one, including its dependent associations and before_ and after_destroy callbacks.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 726 726: def destroy_all(conditions = nil) 727: find(:all, :conditions => conditions).each { |object| object.destroy } 728: end
establish_connection (spec = nil)
Establishes the connection to the database. Accepts a hash as input where the :adapter key must be specified with the name of a database adapter (in lower-case) example for regular databases (MySQL, Postgresql, etc):
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "myuser",
:password => "mypass",
:database => "somedatabase"
)
Example for SQLite database:
ActiveRecord::Base.establish_connection(
:adapter => "sqlite",
:database => "path/to/dbfile"
)
Also accepts keys as strings (for parsing from yaml for example):
ActiveRecord::Base.establish_connection(
"adapter" => "sqlite",
"database" => "path/to/dbfile"
)
The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError may be returned on an error.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 204 204: def self.establish_connection(spec = nil) 205: case spec 206: when nil 207: raise AdapterNotSpecified unless defined? RAILS_ENV 208: establish_connection(RAILS_ENV) 209: when ConnectionSpecification 210: clear_active_connection_name 211: @active_connection_name = name 212: @@defined_connections[name] = spec 213: when Symbol, String 214: if configuration = configurations[spec.to_s] 215: establish_connection(configuration) 216: else 217: raise AdapterNotSpecified, "#{spec} database is not configured" 218: end 219: else 220: spec = spec.symbolize_keys 221: unless spec.key?(:adapter) then raise AdapterNotSpecified, "database configuration does not specify adapter" end 222: 223: begin 224: require 'rubygems' 225: gem "activerecord-#{spec[:adapter]}-adapter" 226: require "active_record/connection_adapters/#{spec[:adapter]}_adapter" 227: rescue LoadError 228: begin 229: require "active_record/connection_adapters/#{spec[:adapter]}_adapter" 230: rescue LoadError 231: raise "Please install the #{spec[:adapter]} adapter: `gem install activerecord-#{spec[:adapter]}-adapter` (#{$!})" 232: end 233: end 234: 235: adapter_method = "#{spec[:adapter]}_connection" 236: if !respond_to?(adapter_method) 237: raise AdapterNotFound, "database configuration specifies nonexistent #{spec[:adapter]} adapter" 238: end 239: 240: remove_connection 241: establish_connection(ConnectionSpecification.new(spec, adapter_method)) 242: end 243: end
exists? (id_or_conditions)
Checks whether a record exists in the database that matches conditions given. These conditions can either be a single integer representing a primary key id to be found, or a condition to be matched like using ActiveRecord#find.
The id_or_conditions parameter can be an Integer or a String if you want to search the primary key column of the table for a matching id, or if you‘re looking to match against a condition you can use an Array or a Hash.
Possible gotcha: You can‘t pass in a condition as a string e.g. "name = ‘Jamie’", this would be sanitized and then queried against the primary key column as "id = ‘name = \’Jamie"
Examples
Person.exists?(5)
Person.exists?('5')
Person.exists?(:name => "David")
Person.exists?(['name LIKE ?', "%#{query}%"])
# File vendor/rails/activerecord/lib/active_record/base.rb, line 573 573: def exists?(id_or_conditions) 574: connection.select_all( 575: construct_finder_sql( 576: :select => "#{quoted_table_name}.#{primary_key}", 577: :conditions => expand_id_conditions(id_or_conditions), 578: :limit => 1 579: ), 580: "#{name} Exists" 581: ).size > 0 582: end
find (*args)
Find operates with four different retrieval approaches:
- 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]). If no record can be found for all of the listed ids, then RecordNotFound will be raised.
- Find first: This will return the first record matched by the options used. These options can either be specific conditions or merely an order. If no record can be matched, nil is returned.
- Find last: This will return the last record matched by the options used. These options can either be specific conditions or merely an order. If no record can be matched, nil is returned.
- Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned.
All approaches accept an options hash as their last parameter. The options are:
- :conditions: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
- :order: An SQL fragment like "created_at DESC, name".
- :group: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
- :limit: An integer determining the limit on the number of rows that should be returned.
- :offset: An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.
- :joins: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). 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. Pass :readonly => false to override.
- :include: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer to already defined associations. See eager loading under Associations.
- :select: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not include the joined columns.
- :from: By default, this is the table name of the class, but can be changed to an alternate table name (or even the name of a database view).
- :readonly: Mark the returned records read-only so they cannot be saved or updated.
- :lock: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". :lock => true gives connection‘s default exclusive lock, usually "FOR UPDATE".
Person.find(1) # returns the object for ID = 1 Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6) Person.find([7, 17]) # returns an array for objects with IDs in (7, 17) Person.find([1]) # returns an array for the object with ID = 1 Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC")
Note that returned records may not be in the same order as the ids you provide since database rows are unordered. Give an explicit :order to ensure the results are sorted.
Person.find(:first) # returns the first object fetched by SELECT * FROM people Person.find(:first, :conditions => [ "user_name = ?", user_name]) Person.find(:first, :order => "created_on DESC", :offset => 5)
Person.find(:last) # returns the last object fetched by SELECT * FROM people Person.find(:last, :conditions => [ "user_name = ?", user_name]) Person.find(:last, :order => "created_on DESC", :offset => 5)
Examples for find all:
Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50) Person.find(:all, :offset => 10, :limit => 10) Person.find(:all, :include => [ :account, :friends ]) Person.find(:all, :group => "category")
Example for find with a lock. Imagine two concurrent transactions: each will read person.visits == 2, add 1 to it, and save, resulting in two saves of person.visits = 3. By locking the row, the second transaction has to wait until the first is finished; we get the expected person.visits == 4.
Person.transaction do
person = Person.find(1, :lock => true)
person.visits += 1
person.save!
end
# File vendor/rails/activerecord/lib/active_record/base.rb, line 505 505: def find(*args) 506: options = args.extract_options! 507: validate_find_options(options) 508: set_readonly_option!(options) 509: 510: case args.first 511: when :first then find_initial(options) 512: when :last then find_last(options) 513: when :all then find_every(options) 514: else find_from_ids(args, options) 515: end 516: end
find_by_sql (sql)
Executes a custom sql query against your database and returns all the results. The results will be returned as an array with columns requested encapsulated as attributes of the model you call this method from. If you call +Product.find_by_sql+ then the results will be returned in a Product object with the attributes you specified in the SQL query.
If you call a complicated SQL query which spans multiple tables the columns specified by the SELECT will be attributes of the model, whether or not they are columns of the corresponding table.
The sql parameter is a full sql query as a string. It will be called as is, there will be no database agnostic conversions performed. This should be a last resort because using, for example, MySQL specific terms will lock you to using that particular database engine or require you to change your call if you switch engines
Examples
# A simple sql query spanning multiple tables
Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
> [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
# You can use the same string replacement techniques as you can with ActiveRecord#find
Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
> [#<Post:0x36bff9c @attributes={"first_name"=>"The Cheap Man Buys Twice"}>, ...]
# File vendor/rails/activerecord/lib/active_record/base.rb, line 553 553: def find_by_sql(sql) 554: connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) } 555: end
finder_needs_type_condition? (
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1179 1179: def finder_needs_type_condition? #nodoc 1180: # This is like this because benchmarking justifies the strange :false stuff 1181: :true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true) 1182: end
first (*args)
This is an alias for find(:first). You can pass in all the same arguments to this method as you can to find(:first)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 520 520: def first(*args) 521: find(:first, *args) 522: end
get_primary_key (base_name)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 997 997: def get_primary_key(base_name) #nodoc 998: key = 'id' 999: case primary_key_prefix_type 1000: when :table_name 1001: key = Inflector.foreign_key(base_name, false) 1002: when :table_name_with_underscore 1003: key = Inflector.foreign_key(base_name) 1004: end 1005: key 1006: end
human_attribute_name (attribute_key_name)
Transforms attribute key names into a more humane format, such as "First name" instead of "first_name". Example:
Person.human_attribute_name("first_name") # => "First name"
Deprecated in favor of just calling "first_name".humanize
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1166 1166: def human_attribute_name(attribute_key_name) #nodoc 1167: attribute_key_name.humanize 1168: end
increment_counter (counter_name, id)
Increment a number field by one, usually representing a count.
This is used for caching aggregate values, so that they don‘t need to be computed every time. For example, a DiscussionBoard may cache post_count and comment_count otherwise every time the board is shown it would have to run an SQL query to find how many posts and comments there are.
Options
counter_name The name of the field that should be incremented id The id of the object that should be incremented
Examples
# Increment the post_count column for the record with an id of 5 DiscussionBoard.increment_counter(:post_count, 5)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 812 812: def increment_counter(counter_name, id) 813: update_counters(id, counter_name => 1) 814: end
inheritance_column ()
Defines the column name for use with single table inheritance — can be set in subclasses like so: self.inheritance_column = "type_id"
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1010 1010: def inheritance_column 1011: @inheritance_column ||= "type".freeze 1012: end
inherited (child)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 361 361: def self.inherited(child) #nodoc 362: @@subclasses[self] ||= [] 363: @@subclasses[self] << child 364: super 365: end
inspect ()
Returns a string like ‘Post id:integer, title:string, body:text‘
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1185 1185: def inspect 1186: if self == Base 1187: super 1188: elsif abstract_class? 1189: "#{super}(abstract)" 1190: elsif table_exists? 1191: attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', ' 1192: "#{super}(#{attr_list})" 1193: else 1194: "#{super}(Table doesn't exist)" 1195: end 1196: end
last (*args)
This is an alias for find(:last). You can pass in all the same arguments to this method as you can to find(:last)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 526 526: def last(*args) 527: find(:last, *args) 528: end
log_connections (
connection state logging
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 300 300: def self.log_connections #nodoc 301: if logger 302: logger.info "Defined connections: #{@@defined_connections.inspect}" 303: logger.info "Active connections: #{active_connections.inspect}" 304: logger.info "Active connection name: #{@active_connection_name}" 305: end 306: end
mysql_connection (config)
Establishes a connection to the database that‘s used by all Active Record objects.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 72 72: def self.mysql_connection(config) # nodoc 73: config = config.symbolize_keys 74: host = config[:host] 75: port = config[:port] 76: socket = config[:socket] 77: username = config[:username] ? config[:username].to_s : 'root' 78: password = config[:password].to_s 79: 80: if config.has_key?(:database) 81: database = config[:database] 82: else 83: raise ArgumentError, "No database specified. Missing argument: database." 84: end 85: 86: require_mysql 87: mysql = Mysql.init 88: mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslkey] 89: 90: ConnectionAdapters::MysqlAdapter.new(mysql, logger, [host, username, password, database, port, socket], config) 91: end
new (attributes = nil) {|self if block_given?| ...}
New objects can be instantiated as either empty (pass no construction parameter) or pre-set with attributes but not yet saved (pass a hash with key names matching the associated table column names). In both instances, valid attribute keys are determined by the column names of the associated table — hence you can‘t have attributes that aren‘t part of the table columns.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2072 2072: def initialize(attributes = nil) 2073: @attributes = attributes_from_column_definition 2074: @attributes_cache = {} 2075: @new_record = true 2076: ensure_proper_type 2077: self.attributes = attributes unless attributes.nil? 2078: self.class.send(:scope, :create).each { |att,value| self.send("#{att}=", value) } if self.class.send(:scoped?, :create) 2079: result = yield self if block_given? 2080: callback(:after_initialize) if respond_to_without_attributes?(:after_initialize) 2081: result 2082: end
postgresql_connection (config)
Establishes a connection to the database that‘s used by all Active Record objects
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 22 22: def self.postgresql_connection(config) # nodoc 23: config = config.symbolize_keys 24: host = config[:host] 25: port = config[:port] || 5432 26: username = config[:username].to_s 27: password = config[:password].to_s 28: 29: if config.has_key?(:database) 30: database = config[:database] 31: else 32: raise ArgumentError, "No database specified. Missing argument: database." 33: end 34: 35: # The postgres drivers don't allow the creation of an unconnected PGconn object, 36: # so just pass a nil connection object for the time being. 37: ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, [host, port, nil, nil, database, username, password], config) 38: end
primary_key ()
Defines the primary key field — can be overridden in subclasses. Overwriting will negate any effect of the primary_key_prefix_type setting, though.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 987 987: def primary_key 988: reset_primary_key 989: end
protected_attributes (
Returns an array of all the attributes that have been protected from mass-assignment.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 856 856: def protected_attributes # nodoc 857: read_inheritable_attribute("attr_protected") 858: end
quote_value (value, column = nil)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1199 1199: def quote_value(value, column = nil) #nodoc 1200: connection.quote(value,column) 1201: end
readonly_attributes ()
Returns an array of all the attributes that have been specified as readonly.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 900 900: def readonly_attributes 901: read_inheritable_attribute("attr_readonly") 902: end
remove_connection (klass=self)
Remove the connection for this class. This will close the active connection and the defined connection (if they exist). The result can be used as an argument for establish_connection, for easily re-establishing the connection.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 276 276: def self.remove_connection(klass=self) 277: spec = @@defined_connections[klass.name] 278: konn = active_connections[klass.name] 279: @@defined_connections.delete_if { |key, value| value == spec } 280: active_connections.delete_if { |key, value| value == konn } 281: konn.disconnect! if konn 282: spec.config if spec 283: end
require_mysql ()
# File vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb, line 47 47: def self.require_mysql 48: # Include the MySQL driver if one hasn't already been loaded 49: unless defined? Mysql 50: begin 51: require_library_or_gem 'mysql' 52: rescue LoadError => cannot_require_mysql 53: # Use the bundled Ruby/MySQL driver if no driver is already in place 54: begin 55: ActiveRecord::Base.logger.info( 56: "WARNING: You're using the Ruby-based MySQL library that ships with Rails. This library is not suited for production. " + 57: "Please install the C-based MySQL library instead (gem install mysql)." 58: ) if ActiveRecord::Base.logger 59: 60: require 'active_record/vendor/mysql' 61: rescue LoadError 62: raise cannot_require_mysql 63: end 64: end 65: end 66: 67: # Define Mysql::Result.all_hashes 68: MysqlCompat.define_all_hashes_method! 69: end
reset_column_information ()
Resets all the cached information about columns, which will cause them to be reloaded on the next request.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1154 1154: def reset_column_information 1155: generated_methods.each { |name| undef_method(name) } 1156: @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = @generated_methods = @inheritance_column = nil 1157: end
reset_column_information_and_inheritable_attributes_for_all_subclasses (
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1159 1159: def reset_column_information_and_inheritable_attributes_for_all_subclasses#nodoc 1160: subclasses.each { |klass| klass.reset_inheritable_attributes; klass.reset_column_information } 1161: end
reset_primary_key (
# File vendor/rails/activerecord/lib/active_record/base.rb, line 991 991: def reset_primary_key #nodoc 992: key = get_primary_key(base_class.name) 993: set_primary_key(key) 994: key 995: end
reset_sequence_name (
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1020 1020: def reset_sequence_name #nodoc 1021: default = connection.default_sequence_name(table_name, primary_key) 1022: set_sequence_name(default) 1023: default 1024: end
reset_subclasses (
# File vendor/rails/activerecord/lib/active_record/base.rb, line 367 367: def self.reset_subclasses #nodoc 368: nonreloadables = [] 369: subclasses.each do |klass| 370: unless Dependencies.autoloaded? klass 371: nonreloadables << klass 372: next 373: end 374: klass.instance_variables.each { |var| klass.send(:remove_instance_variable, var) } 375: klass.instance_methods(false).each { |m| klass.send :undef_method, m } 376: end 377: @@subclasses = {} 378: nonreloadables.each { |klass| (@@subclasses[klass.superclass] ||= []) << klass } 379: end
reset_table_name (
# File vendor/rails/activerecord/lib/active_record/base.rb, line 964 964: def reset_table_name #nodoc 965: base = base_class 966: 967: name = 968: # STI subclasses always use their superclass' table. 969: unless self == base 970: base.table_name 971: else 972: # Nested classes are prefixed with singular parent table name. 973: if parent < ActiveRecord::Base && !parent.abstract_class? 974: contained = parent.table_name 975: contained = contained.singularize if parent.pluralize_table_names 976: contained << '_' 977: end 978: name = "#{table_name_prefix}#{contained}#{undecorated_table_name(base.name)}#{table_name_suffix}" 979: end 980: 981: set_table_name(name) 982: name 983: end
retrieve_connection (
Locate the connection of the nearest super class. This can be an active or defined connection: if it is the latter, it will be opened and set as the active connection for the class it was defined for (not necessarily the current class).
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 249 249: def self.retrieve_connection #nodoc 250: # Name is nil if establish_connection hasn't been called for 251: # some class along the inheritance chain up to AR::Base yet. 252: if name = active_connection_name 253: if conn = active_connections[name] 254: # Verify the connection. 255: conn.verify!(@@verification_timeout) 256: elsif spec = @@defined_connections[name] 257: # Activate this connection specification. 258: klass = name.constantize 259: klass.connection = spec 260: conn = active_connections[name] 261: end 262: end 263: 264: conn or raise ConnectionNotEstablished 265: end
sanitize (object)
Used to sanitize objects before they‘re used in an SQL SELECT statement. Delegates to connection.quote.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1204 1204: def sanitize(object) #nodoc 1205: connection.quote(object) 1206: end
sequence_name (
Lazy-set the sequence name to the connection‘s default. This method is only ever called once since set_sequence_name overrides it.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1016 1016: def sequence_name #nodoc 1017: reset_sequence_name 1018: end
serialize (attr_name, class_name = Object)
If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, then specify the name of that attribute using this method and it will be handled automatically. The serialization is done through YAML. If class_name is specified, the serialized object must be of that class on retrieval or SerializationTypeMismatch will be raised.
Options
attr_name The field name that should be serialized class_name Optional, class name that the object type should be equal to
Example
# Serialize a preferences attribute
class User
serialize :preferences
end
# File vendor/rails/activerecord/lib/active_record/base.rb, line 919 919: def serialize(attr_name, class_name = Object) 920: serialized_attributes[attr_name.to_s] = class_name 921: end
serialized_attributes ()
Returns a hash of all the attributes that have been specified for serialization as keys and their class restriction as values.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 924 924: def serialized_attributes 925: read_inheritable_attribute("attr_serialized") or write_inheritable_attribute("attr_serialized", {}) 926: end
set_inheritance_column (value = nil, &block)
Sets the name of the inheritance column to use to the given value, or (if the value # is nil or false) to the value returned by the given block.
Example:
class Project < ActiveRecord::Base
set_inheritance_column do
original_inheritance_column + "_id"
end
end
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1064 1064: def set_inheritance_column(value = nil, &block) 1065: define_attr_method :inheritance_column, value, &block 1066: end
set_primary_key (value = nil, &block)
Sets the name of the primary key column to use to the given value, or (if the value is nil or false) to the value returned by the given block.
Example:
class Project < ActiveRecord::Base
set_primary_key "sysid"
end
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1048 1048: def set_primary_key(value = nil, &block) 1049: define_attr_method :primary_key, value, &block 1050: end
set_sequence_name (value = nil, &block)
Sets the name of the sequence to use when generating ids to the given value, or (if the value is nil or false) to the value returned by the given block. This is required for Oracle and is useful for any database which relies on sequences for primary key generation.
If a sequence name is not explicitly set when using Oracle or Firebird, it will default to the commonly used pattern of: #{table_name}_seq
If a sequence name is not explicitly set when using PostgreSQL, it will discover the sequence corresponding to your primary key for you.
Example:
class Project < ActiveRecord::Base
set_sequence_name "projectseq" # default would have been "project_seq"
end
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1085 1085: def set_sequence_name(value = nil, &block) 1086: define_attr_method :sequence_name, value, &block 1087: end
set_table_name (value = nil, &block)
Sets the table name to use to the given value, or (if the value is nil or false) to the value returned by the given block.
Example:
class Project < ActiveRecord::Base
set_table_name "project"
end
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1034 1034: def set_table_name(value = nil, &block) 1035: define_attr_method :table_name, value, &block 1036: end
silence () {|| ...}
Silences the logger for the duration of the block.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1233 1233: def silence 1234: old_logger_level, logger.level = logger.level, Logger::ERROR if logger 1235: yield 1236: ensure 1237: logger.level = old_logger_level if logger 1238: end
single_threaded_active_connections (
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 29 29: def single_threaded_active_connections #nodoc 30: @@active_connections 31: end
sqlite3_connection (config)
sqlite3 adapter reuses sqlite_connection.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb, line 6 6: def self.sqlite3_connection(config) # nodoc 7: parse_sqlite_config!(config) 8: 9: unless self.class.const_defined?(:SQLite3) 10: require_library_or_gem(config[:adapter]) 11: end 12: 13: db = SQLite3::Database.new( 14: config[:database], 15: :results_as_hash => true, 16: :type_translation => false 17: ) 18: 19: db.busy_timeout(config[:timeout]) unless config[:timeout].nil? 20: 21: ConnectionAdapters::SQLite3Adapter.new(db, logger) 22: end
sqlite_connection (config)
Establishes a connection to the database that‘s used by all Active Record objects
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb, line 7 7: def sqlite_connection(config) # nodoc 8: parse_sqlite_config!(config) 9: 10: unless self.class.const_defined?(:SQLite) 11: require_library_or_gem(config[:adapter]) 12: 13: db = SQLite::Database.new(config[:database], 0) 14: db.show_datatypes = "ON" if !defined? SQLite::Version 15: db.results_as_hash = true if defined? SQLite::Version 16: db.type_translation = false 17: 18: # "Downgrade" deprecated sqlite API 19: if SQLite.const_defined?(:Version) 20: ConnectionAdapters::SQLite2Adapter.new(db, logger) 21: else 22: ConnectionAdapters::DeprecatedSQLiteAdapter.new(db, logger) 23: end 24: end 25: end
table_exists? ()
Indicates whether the table associated with this class exists
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1099 1099: def table_exists? 1100: if connection.respond_to?(:tables) 1101: connection.tables.include? table_name 1102: else 1103: # if the connection adapter hasn't implemented tables, there are two crude tests that can be 1104: # used - see if getting column info raises an error, or if the number of columns returned is zero 1105: begin 1106: reset_column_information 1107: columns.size > 0 1108: rescue ActiveRecord::StatementInvalid 1109: false 1110: end 1111: end 1112: end
table_name ()
Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending directly from ActiveRecord. So if the hierarchy looks like: Reply < Message < ActiveRecord, then Message is used to guess the table name even when called on Reply. The rules used to do the guess are handled by the Inflector class in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb.
Nested classes are given table names prefixed by the singular form of the parent‘s table name. Enclosing modules are not considered. Examples:
class Invoice < ActiveRecord::Base; end; file class table_name invoice.rb Invoice invoices class Invoice < ActiveRecord::Base; class Lineitem < ActiveRecord::Base; end; end; file class table_name invoice.rb Invoice::Lineitem invoice_lineitems module Invoice; class Lineitem < ActiveRecord::Base; end; end; file class table_name invoice/lineitem.rb Invoice::Lineitem lineitems
Additionally, the class-level table_name_prefix is prepended and the table_name_suffix is appended. So if you have "myapp_" as a prefix, the table name guess for an Invoice class becomes "myapp_invoices". Invoice::Lineitem becomes "myapp_invoice_lineitems".
You can also overwrite this class method to allow for unguessable links, such as a Mouse class with a link to a "mice" table. Example:
class Mouse < ActiveRecord::Base
set_table_name "mice"
end
# File vendor/rails/activerecord/lib/active_record/base.rb, line 960 960: def table_name 961: reset_table_name 962: end
thread_safe_active_connections (
Retrieve the connection cache.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 25 25: def thread_safe_active_connections #nodoc 26: @@active_connections[Thread.current.object_id] ||= {} 27: end
update (id, attributes)
Updates an object (or multiple objects) and saves it to the database, if validations pass. The resulting object is returned whether the object was saved successfully to the database or not.
Options
id This should be the id or an array of ids to be updated attributes This should be a Hash of attributes to be set on the object, or an array of Hashes.
Examples
# Updating one record:
Person.update(15, {:user_name => 'Samuel', :group => 'expert'})
# Updating multiple records:
people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy"} }
Person.update(people.keys, people.values)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 621 621: def update(id, attributes) 622: if id.is_a?(Array) 623: idx = -1 624: id.collect { |one_id| idx += 1; update(one_id, attributes[idx]) } 625: else 626: object = find(id) 627: object.update_attributes(attributes) 628: object 629: end 630: end
update_all (updates, conditions = nil, options = {})
Updates all records with details given if they match a set of conditions supplied, limits and order can also be supplied.
Options
updates A String of column and value pairs that will be set on any records that match conditions conditions An SQL fragment like "administrator = 1" or [ "user_name = ?", username ].
See conditions in the intro for more info.
options Additional options are :limit and/or :order, see the examples for usage.
Examples
# Update all billing objects with the 3 different attributes given
Billing.update_all( "category = 'authorized', approved = 1, author = 'David'" )
# Update records that match our conditions
Billing.update_all( "author = 'David'", "title LIKE '%Rails%'" )
# Update records that match our conditions but limit it to 5 ordered by date
Billing.update_all( "author = 'David'", "title LIKE '%Rails%'",
:order => 'created_at', :limit => 5 )
# File vendor/rails/activerecord/lib/active_record/base.rb, line 702 702: def update_all(updates, conditions = nil, options = {}) 703: sql = "UPDATE #{quoted_table_name} SET #{sanitize_sql_for_assignment(updates)} " 704: scope = scope(:find) 705: add_conditions!(sql, conditions, scope) 706: add_order!(sql, options[:order], nil) 707: add_limit!(sql, options, nil) 708: connection.update(sql, "#{name} Update") 709: end
update_counters (id, counters)
A generic "counter updater" implementation, intended primarily to be used by increment_counter and decrement_counter, but which may also be useful on its own. It simply does a direct SQL update for the record with the given ID, altering the given hash of counters by the amount given by the corresponding value:
Options
id The id of the object you wish to update a counter on counters An Array of Hashes containing the names of the fields
to update as keys and the amount to update the field by as
values
Examples
# For the Post with id of 5, decrement the comment_count by 1, and # increment the action_count by 1 Post.update_counters 5, :comment_count => -1, :action_count => 1 # Executes the following SQL: # UPDATE posts # SET comment_count = comment_count - 1, # action_count = action_count + 1 # WHERE id = 5
# File vendor/rails/activerecord/lib/active_record/base.rb, line 789 789: def update_counters(id, counters) 790: updates = counters.inject([]) { |list, (counter_name, increment)| 791: sign = increment < 0 ? "-" : "+" 792: list << "#{connection.quote_column_name(counter_name)} = #{connection.quote_column_name(counter_name)} #{sign} #{increment.abs}" 793: }.join(", ") 794: update_all(updates, "#{connection.quote_column_name(primary_key)} = #{quote_value(id)}") 795: end
verify_active_connections! (
Verify active connections.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 114 114: def verify_active_connections! #nodoc 115: if @@allow_concurrency 116: remove_stale_cached_threads!(@@active_connections) do |name, conn| 117: conn.disconnect! 118: end 119: end 120: 121: active_connections.each_value do |connection| 122: connection.verify!(@@verification_timeout) 123: end 124: end
Protected Class Methods
aggregate_mapping (reflection)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1903 1903: def aggregate_mapping(reflection) 1904: mapping = reflection.options[:mapping] || [reflection.name, reflection.name] 1905: mapping.first.is_a?(Array) ? mapping : [mapping] 1906: end
class_name_of_active_record_descendant (klass)
Returns the name of the class descending directly from ActiveRecord in the inheritance hierarchy.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1874 1874: def class_name_of_active_record_descendant(klass) #nodoc 1875: klass.base_class.name 1876: end
class_of_active_record_descendant (klass)
Returns the class descending directly from ActiveRecord in the inheritance hierarchy.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1863 1863: def class_of_active_record_descendant(klass) 1864: if klass.superclass == Base || klass.superclass.abstract_class? 1865: klass 1866: elsif klass.superclass.nil? 1867: raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord" 1868: else 1869: class_of_active_record_descendant(klass.superclass) 1870: end 1871: end
compute_type (type_name)
Returns the class type of the record using the current module as a prefix. So descendents of MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1853 1853: def compute_type(type_name) 1854: modularized_name = type_name_with_module(type_name) 1855: begin 1856: class_eval(modularized_name, __FILE__, __LINE__) 1857: rescue NameError 1858: class_eval(type_name, __FILE__, __LINE__) 1859: end 1860: end
current_scoped_methods (
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1847 1847: def current_scoped_methods #nodoc 1848: scoped_methods.last 1849: end
encode_quoted_value (value)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2060 2060: def encode_quoted_value(value) #nodoc 2061: quoted_value = connection.quote(value) 2062: quoted_value = "'#{quoted_value[1..-2].gsub(/\'/, "\\\\'")}'" if quoted_value.include?("\\\'") # (for ruby mode) " 2063: quoted_value 2064: end
expand_hash_conditions_for_aggregates (attrs)
Accepts a hash of sql conditions and replaces those attributes that correspond to a composed_of relationship with their expanded aggregate attribute values. Given:
class Person < ActiveRecord::Base
composed_of :address, :class_name => "Address",
:mapping => [%w(address_street street), %w(address_city city)]
end
Then:
{ :address => Address.new("813 abc st.", "chicago") }
# => { :address_street => "813 abc st.", :address_city => "chicago" }
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1919 1919: def expand_hash_conditions_for_aggregates(attrs) 1920: expanded_attrs = {} 1921: attrs.each do |attr, value| 1922: unless (aggregation = reflect_on_aggregation(attr.to_sym)).nil? 1923: mapping = aggregate_mapping(aggregation) 1924: mapping.each do |field_attr, aggregate_attr| 1925: if mapping.size == 1 && !value.respond_to?(aggregate_attr) 1926: expanded_attrs[field_attr] = value 1927: else 1928: expanded_attrs[field_attr] = value.send(aggregate_attr) 1929: end 1930: end 1931: else 1932: expanded_attrs[attr] = value 1933: end 1934: end 1935: expanded_attrs 1936: end
expand_range_bind_variables (bind_vars)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2013 2013: def expand_range_bind_variables(bind_vars) #nodoc 2014: bind_vars.sum do |var| 2015: if var.is_a?(Range) 2016: [var.first, var.last] 2017: else 2018: [var] 2019: end 2020: end 2021: end
quote_bound_value (value)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2023 2023: def quote_bound_value(value) #nodoc 2024: if value.respond_to?(:map) && !value.is_a?(String) 2025: if value.respond_to?(:empty?) && value.empty? 2026: connection.quote(nil) 2027: else 2028: value.map { |v| connection.quote(v) }.join(',') 2029: end 2030: else 2031: connection.quote(value) 2032: end 2033: end
raise_if_bind_arity_mismatch (statement, expected, provided)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2035 2035: def raise_if_bind_arity_mismatch(statement, expected, provided) #nodoc 2036: unless expected == provided 2037: raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}" 2038: end 2039: end
replace_bind_variables (statement, values)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1996 1996: def replace_bind_variables(statement, values) #nodoc 1997: raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size) 1998: bound = values.dup 1999: statement.gsub('?') { quote_bound_value(bound.shift) } 2000: end
replace_named_bind_variables (statement, bind_vars)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2002 2002: def replace_named_bind_variables(statement, bind_vars) #nodoc 2003: statement.gsub(/:([a-zA-Z]\w*)/) do 2004: match = $1.to_sym 2005: if bind_vars.include?(match) 2006: quote_bound_value(bind_vars[match]) 2007: else 2008: raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}" 2009: end 2010: end 2011: end
sanitize_sql_array (ary)
Accepts an array of conditions. The array has each value sanitized and interpolated into the sql statement.
["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1983 1983: def sanitize_sql_array(ary) 1984: statement, *values = ary 1985: if values.first.is_a?(Hash) and statement =~ /:\w+/ 1986: replace_named_bind_variables(statement, values.first) 1987: elsif statement.include?('?') 1988: replace_bind_variables(statement, values) 1989: else 1990: statement % values.collect { |value| connection.quote_string(value.to_s) } 1991: end 1992: end
sanitize_sql_for_assignment (assignments)
Accepts an array, hash, or string of sql conditions and sanitizes them into a valid SQL fragment for a SET clause.
{ :name => nil, :group_id => 4 } returns "name = NULL , group_id='4'"
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1895 1895: def sanitize_sql_for_assignment(assignments) 1896: case assignments 1897: when Array; sanitize_sql_array(assignments) 1898: when Hash; sanitize_sql_hash_for_assignment(assignments) 1899: else assignments 1900: end 1901: end
sanitize_sql_for_conditions (condition)
Accepts an array, hash, or string of sql conditions and sanitizes them into a valid SQL fragment for a WHERE clause.
["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
{ :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'"
"name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'"
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1883 1883: def sanitize_sql_for_conditions(condition) 1884: case condition 1885: when Array; sanitize_sql_array(condition) 1886: when Hash; sanitize_sql_hash_for_conditions(condition) 1887: else condition 1888: end 1889: end
sanitize_sql_hash_for_assignment (attrs)
Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause.
{ :status => nil, :group_id => 1 }
# => "status = NULL , group_id = 1"
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1974 1974: def sanitize_sql_hash_for_assignment(attrs) 1975: attrs.map do |attr, value| 1976: "#{connection.quote_column_name(attr)} = #{quote_bound_value(value)}" 1977: end.join(', ') 1978: end
sanitize_sql_hash_for_conditions (attrs)
Sanitizes a hash of attribute/value pairs into SQL conditions for a WHERE clause.
{ :name => "foo'bar", :group_id => 4 }
# => "name='foo''bar' and group_id= 4"
{ :status => nil, :group_id => [1,2,3] }
# => "status IS NULL and group_id IN (1,2,3)"
{ :age => 13..18 }
# => "age BETWEEN 13 AND 18"
{ 'other_records.id' => 7 }
# => "`other_records`.`id` = 7"
And for value objects on a composed_of relationship:
{ :address => Address.new("123 abc st.", "chicago") }
# => "address_street='123 abc st.' and address_city='chicago'"
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1950 1950: def sanitize_sql_hash_for_conditions(attrs) 1951: attrs = expand_hash_conditions_for_aggregates(attrs) 1952: 1953: conditions = attrs.map do |attr, value| 1954: attr = attr.to_s 1955: 1956: # Extract table name from qualified attribute names. 1957: if attr.include?('.') 1958: table_name, attr = attr.split('.', 2) 1959: table_name = connection.quote_table_name(table_name) 1960: else 1961: table_name = quoted_table_name 1962: end 1963: 1964: "#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}" 1965: end.join(' AND ') 1966: 1967: replace_bind_variables(conditions, expand_range_bind_variables(attrs.values)) 1968: end
scope (method, key = nil)
Retrieve the scope for the given method and optional key.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1825 1825: def scope(method, key = nil) #nodoc 1826: if current_scoped_methods && (scope = current_scoped_methods[method]) 1827: key ? scope[key] : scope 1828: end 1829: end
scoped? (method, key = nil)
Test whether the given method and optional key are scoped.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1818 1818: def scoped?(method, key = nil) #nodoc 1819: if current_scoped_methods && (scope = current_scoped_methods[method]) 1820: !key || scope.has_key?(key) 1821: end 1822: end
set_readonly_option! (options)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2048 2048: def set_readonly_option!(options) #nodoc 2049: # Inherit :readonly from finder scope if set. Otherwise, 2050: # if :joins is not blank then :readonly defaults to true. 2051: unless options.has_key?(:readonly) 2052: if scoped_readonly = scope(:find, :readonly) 2053: options[:readonly] = scoped_readonly 2054: elsif !options[:joins].blank? && !options[:select] 2055: options[:readonly] = true 2056: end 2057: end 2058: end
single_threaded_scoped_methods (
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1836 1836: def single_threaded_scoped_methods #nodoc 1837: @scoped_methods ||= [] 1838: end
subclasses (
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1812 1812: def subclasses #nodoc 1813: @@subclasses[self] ||= [] 1814: @@subclasses[self] + extra = @@subclasses[self].inject([]) {|list, subclass| list + subclass.subclasses } 1815: end
thread_safe_scoped_methods (
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1831 1831: def thread_safe_scoped_methods #nodoc 1832: scoped_methods = (Thread.current[:scoped_methods] ||= {}) 1833: scoped_methods[self] ||= [] 1834: end
validate_find_options (options)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2044 2044: def validate_find_options(options) #nodoc 2045: options.assert_valid_keys(VALID_FIND_OPTIONS) 2046: end
with_exclusive_scope (method_scoping = {}, &block)
Works like with_scope, but discards any nested properties.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1808 1808: def with_exclusive_scope(method_scoping = {}, &block) 1809: with_scope(method_scoping, :overwrite, &block) 1810: end
with_scope (method_scoping = {}, action = :merge) {|| ...}
Scope parameters to method calls within the block. Takes a hash of method_name => parameters hash. method_name may be :find or :create. :find parameters may include the :conditions, :joins, :include, :offset, :limit, and :readonly options. :create parameters are an attributes hash.
class Article < ActiveRecord::Base
def self.create_with_scope
with_scope(:find => { :conditions => "blog_id = 1" }, :create => { :blog_id => 1 }) do
find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1
a = create(1)
a.blog_id # => 1
end
end
end
In nested scopings, all previous parameters are overwritten by the innermost rule, with the exception of :conditions and :include options in :find, which are merged.
class Article < ActiveRecord::Base
def self.find_with_scope
with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }, :create => { :blog_id => 1 }) do
with_scope(:find => { :limit => 10})
find(:all) # => SELECT * from articles WHERE blog_id = 1 LIMIT 10
end
with_scope(:find => { :conditions => "author_id = 3" })
find(:all) # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1
end
end
end
end
You can ignore any previous scopings by using the with_exclusive_scope method.
class Article < ActiveRecord::Base
def self.find_with_exclusive_scope
with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }) do
with_exclusive_scope(:find => { :limit => 10 })
find(:all) # => SELECT * from articles LIMIT 10
end
end
end
end
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1756 1756: def with_scope(method_scoping = {}, action = :merge, &block) 1757: method_scoping = method_scoping.method_scoping if method_scoping.respond_to?(:method_scoping) 1758: 1759: # Dup first and second level of hash (method and params). 1760: method_scoping = method_scoping.inject({}) do |hash, (method, params)| 1761: hash[method] = (params == true) ? params : params.dup 1762: hash 1763: end 1764: 1765: method_scoping.assert_valid_keys([ :find, :create ]) 1766: 1767: if f = method_scoping[:find] 1768: f.assert_valid_keys(VALID_FIND_OPTIONS) 1769: set_readonly_option! f 1770: end 1771: 1772: # Merge scopings 1773: if action == :merge && current_scoped_methods 1774: method_scoping = current_scoped_methods.inject(method_scoping) do |hash, (method, params)| 1775: case hash[method] 1776: when Hash 1777: if method == :find 1778: (hash[method].keys + params.keys).uniq.each do |key| 1779: merge = hash[method][key] && params[key] # merge if both scopes have the same key 1780: if key == :conditions && merge 1781: hash[method][key] = merge_conditions(params[key], hash[method][key]) 1782: elsif key == :include && merge 1783: hash[method][key] = merge_includes(hash[method][key], params[key]).uniq 1784: else 1785: hash[method][key] = hash[method][key] || params[key] 1786: end 1787: end 1788: else 1789: hash[method] = params.merge(hash[method]) 1790: end 1791: else 1792: hash[method] = params 1793: end 1794: hash 1795: end 1796: end 1797: 1798: self.scoped_methods << method_scoping 1799: 1800: begin 1801: yield 1802: ensure 1803: self.scoped_methods.pop 1804: end 1805: end
Private Class Methods
add_conditions! (sql, conditions, scope = :auto)
Adds a sanitized version of conditions to the sql string. Note that the passed-in sql string is changed. The optional scope argument is for the current :find scope.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1528 1528: def add_conditions!(sql, conditions, scope = :auto) 1529: scope = scope(:find) if :auto == scope 1530: conditions = [conditions] 1531: conditions << scope[:conditions] if scope 1532: conditions << type_condition if finder_needs_type_condition? 1533: merged_conditions = merge_conditions(*conditions) 1534: sql << "WHERE #{merged_conditions} " unless merged_conditions.blank? 1535: end
add_group! (sql, group, scope = :auto)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1481 1481: def add_group!(sql, group, scope = :auto) 1482: if group 1483: sql << " GROUP BY #{group}" 1484: else 1485: scope = scope(:find) if :auto == scope 1486: if scope && (scoped_group = scope[:group]) 1487: sql << " GROUP BY #{scoped_group}" 1488: end 1489: end 1490: end
add_joins! (sql, options, scope = :auto)
The optional scope argument is for the current :find scope.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1513 1513: def add_joins!(sql, options, scope = :auto) 1514: scope = scope(:find) if :auto == scope 1515: [(scope && scope[:joins]), options[:joins]].each do |join| 1516: case join 1517: when Symbol, Hash, Array 1518: join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, join, nil) 1519: sql << " #{join_dependency.join_associations.collect { |assoc| assoc.association_join }.join} " 1520: else 1521: sql << " #{join} " 1522: end 1523: end 1524: end
add_limit! (sql, options, scope = :auto)
The optional scope argument is for the current :find scope.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1493 1493: def add_limit!(sql, options, scope = :auto) 1494: scope = scope(:find) if :auto == scope 1495: 1496: if scope 1497: options[:limit] ||= scope[:limit] 1498: options[:offset] ||= scope[:offset] 1499: end 1500: 1501: connection.add_limit_offset!(sql, options) 1502: end
add_lock! (sql, options, scope = :auto)
The optional scope argument is for the current :find scope. The :lock option has precedence over a scoped :lock.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1506 1506: def add_lock!(sql, options, scope = :auto) 1507: scope = scope(:find) if :auto == scope 1508: options = options.reverse_merge(:lock => scope[:lock]) if scope 1509: connection.add_lock!(sql, options) 1510: end
add_order! (sql, order, scope = :auto)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1470 1470: def add_order!(sql, order, scope = :auto) 1471: scope = scope(:find) if :auto == scope 1472: scoped_order = scope[:order] if scope 1473: if order 1474: sql << " ORDER BY #{order}" 1475: sql << ", #{scoped_order}" if scoped_order 1476: else 1477: sql << " ORDER BY #{scoped_order}" if scoped_order 1478: end 1479: end
all_attributes_exists? (attribute_names)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1661 1661: def all_attributes_exists?(attribute_names) 1662: attribute_names = expand_attribute_names_for_aggregates(attribute_names) 1663: attribute_names.all? { |name| column_methods_hash.include?(name.to_sym) } 1664: end
attribute_condition (argument)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1666 1666: def attribute_condition(argument) 1667: case argument 1668: when nil then "IS ?" 1669: when Array, ActiveRecord::Associations::AssociationCollection then "IN (?)" 1670: when Range then "BETWEEN ? AND ?" 1671: else "= ?" 1672: end 1673: end
clear_all_cached_connections! ()
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 157 157: def clear_all_cached_connections! 158: if @@allow_concurrency 159: @@active_connections.each_value do |connection_hash_for_thread| 160: connection_hash_for_thread.each_value {|conn| conn.disconnect! } 161: connection_hash_for_thread.clear 162: end 163: else 164: @@active_connections.each_value {|conn| conn.disconnect! } 165: end 166: @@active_connections.clear 167: end
clear_cache! (cache, thread_id = nil, &block)
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 127 127: def clear_cache!(cache, thread_id = nil, &block) 128: if cache 129: if @@allow_concurrency 130: thread_id ||= Thread.current.object_id 131: thread_cache, cache = cache, cache[thread_id] 132: return unless cache 133: end 134: 135: cache.each(&block) if block_given? 136: cache.clear 137: end 138: ensure 139: if thread_cache && @@allow_concurrency 140: thread_cache.delete(thread_id) 141: end 142: end
construct_attributes_from_arguments (attribute_names, arguments)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1640 1640: def construct_attributes_from_arguments(attribute_names, arguments) 1641: attributes = {} 1642: attribute_names.each_with_index { |name, idx| attributes[name] = arguments[idx] } 1643: attributes 1644: end
construct_finder_sql (options)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1423 1423: def construct_finder_sql(options) 1424: scope = scope(:find) 1425: sql = "SELECT #{(scope && scope[:select]) || options[:select] || (options[:joins] && quoted_table_name + '.*') || '*'} " 1426: sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} " 1427: 1428: add_joins!(sql, options, scope) 1429: add_conditions!(sql, options[:conditions], scope) 1430: 1431: add_group!(sql, options[:group], scope) 1432: add_order!(sql, options[:order], scope) 1433: add_limit!(sql, options, scope) 1434: add_lock!(sql, options, scope) 1435: 1436: sql 1437: end
define_attr_method (name, value=nil, &block)
Defines an "attribute" method (like inheritance_column or table_name). A new (class) method will be created with the given name. If a value is specified, the new method will return that value (as a string). Otherwise, the given block will be used to compute the value of the method.
The original method will be aliased, with the new name being prefixed with "original_". This allows the new method to access the original value.
Example:
class A < ActiveRecord::Base
define_attr_method :primary_key, "sysid"
define_attr_method( :inheritance_column ) do
original_inheritance_column + "_id"
end
end
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1702 1702: def define_attr_method(name, value=nil, &block) 1703: sing = class << self; self; end 1704: sing.send :alias_method, "original_#{name}", name 1705: if block_given? 1706: sing.send :define_method, name, &block 1707: else 1708: # use eval instead of a block to work around a memory leak in dev 1709: # mode in fcgi 1710: sing.class_eval "def #{name}; #{value.to_s.inspect}; end" 1711: end 1712: end
determine_finder (match)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1628 1628: def determine_finder(match) 1629: match.captures.first == 'all_by' ? :find_every : :find_initial 1630: end
determine_instantiator (match)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1632 1632: def determine_instantiator(match) 1633: match.captures.first == 'initialize' ? :new : :create 1634: end
expand_attribute_names_for_aggregates (attribute_names)
Similar in purpose to expand_hash_conditions_for_aggregates.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1647 1647: def expand_attribute_names_for_aggregates(attribute_names) 1648: expanded_attribute_names = [] 1649: attribute_names.each do |attribute_name| 1650: unless (aggregation = reflect_on_aggregation(attribute_name.to_sym)).nil? 1651: aggregate_mapping(aggregation).each do |field_attr, aggregate_attr| 1652: expanded_attribute_names << field_attr 1653: end 1654: else 1655: expanded_attribute_names << attribute_name 1656: end 1657: end 1658: expanded_attribute_names 1659: end
expand_id_conditions (id_or_conditions)
Interpret Array and Hash as conditions and anything else as an id.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1676 1676: def expand_id_conditions(id_or_conditions) 1677: case id_or_conditions 1678: when Array, Hash then id_or_conditions 1679: else sanitize_sql(primary_key => id_or_conditions) 1680: end 1681: end
extract_attribute_names_from_match (match)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1636 1636: def extract_attribute_names_from_match(match) 1637: match.captures.last.split('_and_') 1638: end
find_every (options)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1296 1296: def find_every(options) 1297: include_associations = merge_includes(scope(:find, :include), options[:include]) 1298: 1299: if include_associations.any? && references_eager_loaded_tables?(options) 1300: records = find_with_associations(options) 1301: else 1302: records = find_by_sql(construct_finder_sql(options)) 1303: if include_associations.any? 1304: preload_associations(records, include_associations) 1305: end 1306: end 1307: 1308: records.each { |record| record.readonly! } if options[:readonly] 1309: 1310: records 1311: end
find_from_ids (ids, options)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1313 1313: def find_from_ids(ids, options) 1314: expects_array = ids.first.kind_of?(Array) 1315: return ids.first if expects_array && ids.first.empty? 1316: 1317: ids = ids.flatten.compact.uniq 1318: 1319: case ids.size 1320: when 0 1321: raise RecordNotFound, "Couldn't find #{name} without an ID" 1322: when 1 1323: result = find_one(ids.first, options) 1324: expects_array ? [ result ] : result 1325: else 1326: find_some(ids, options) 1327: end 1328: end
find_initial (options)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1262 1262: def find_initial(options) 1263: options.update(:limit => 1) unless options[:include] 1264: find_every(options).first 1265: end
find_last (options)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1267 1267: def find_last(options) 1268: order = options[:order] 1269: 1270: if order 1271: order = reverse_sql_order(order) 1272: elsif !scoped?(:find, :order) 1273: order = "#{table_name}.#{primary_key} DESC" 1274: end 1275: 1276: if scoped?(:find, :order) 1277: scoped_order = reverse_sql_order(scope(:find, :order)) 1278: scoped_methods.select { |s| s[:find].update(:order => scoped_order) } 1279: end 1280: 1281: find_initial(options.merge({ :order => order })) 1282: end
find_one (id, options)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1330 1330: def find_one(id, options) 1331: conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions] 1332: options.update :conditions => "#{quoted_table_name}.#{connection.quote_column_name(primary_key)} = #{quote_value(id,columns_hash[primary_key])}#{conditions}" 1333: 1334: # Use find_every(options).first since the primary key condition 1335: # already ensures we have a single record. Using find_initial adds 1336: # a superfluous :limit => 1. 1337: if result = find_every(options).first 1338: result 1339: else 1340: raise RecordNotFound, "Couldn't find #{name} with ID=#{id}#{conditions}" 1341: end 1342: end
find_some (ids, options)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1344 1344: def find_some(ids, options) 1345: conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions] 1346: ids_list = ids.map { |id| quote_value(id,columns_hash[primary_key]) }.join(',') 1347: options.update :conditions => "#{quoted_table_name}.#{connection.quote_column_name(primary_key)} IN (#{ids_list})#{conditions}" 1348: 1349: result = find_every(options) 1350: 1351: # Determine expected size from limit and offset, not just ids.size. 1352: expected_size = 1353: if options[:limit] && ids.size > options[:limit] 1354: options[:limit] 1355: else 1356: ids.size 1357: end 1358: 1359: # 11 ids with limit 3, offset 9 should give 2 results. 1360: if options[:offset] && (ids.size - options[:offset] < expected_size) 1361: expected_size = ids.size - options[:offset] 1362: end 1363: 1364: if result.size == expected_size 1365: result 1366: else 1367: raise RecordNotFound, "Couldn't find all #{name.pluralize} with IDs (#{ids_list})#{conditions} (found #{result.size} results, but was looking for #{expected_size})" 1368: end 1369: end
instantiate (record)
Finder methods must instantiate through this method to work with the single-table inheritance model that makes it possible to create objects of different types from the same table.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1374 1374: def instantiate(record) 1375: object = 1376: if subclass_name = record[inheritance_column] 1377: # No type given. 1378: if subclass_name.empty? 1379: allocate 1380: 1381: else 1382: # Ignore type if no column is present since it was probably 1383: # pulled in from a sloppy join. 1384: unless columns_hash.include?(inheritance_column) 1385: allocate 1386: 1387: else 1388: begin 1389: compute_type(subclass_name).allocate 1390: rescue NameError 1391: raise SubclassNotFound, 1392: "The single-table inheritance mechanism failed to locate the subclass: '#{record[inheritance_column]}'. " + 1393: "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " + 1394: "Please rename this column if you didn't intend it to be used for storing the inheritance class " + 1395: "or overwrite #{self.to_s}.inheritance_column to use another column for that information." 1396: end 1397: end 1398: end 1399: else 1400: allocate 1401: end 1402: 1403: object.instance_variable_set("@attributes", record) 1404: object.instance_variable_set("@attributes_cache", Hash.new) 1405: 1406: if object.respond_to_without_attributes?(:after_find) 1407: object.send(:callback, :after_find) 1408: end 1409: 1410: if object.respond_to_without_attributes?(:after_initialize) 1411: object.send(:callback, :after_initialize) 1412: end 1413: 1414: object 1415: end
merge_conditions (*conditions)
Merges conditions so that the result is a valid condition
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1445 1445: def merge_conditions(*conditions) 1446: segments = [] 1447: 1448: conditions.each do |condition| 1449: unless condition.blank? 1450: sql = sanitize_sql(condition) 1451: segments << sql unless sql.blank? 1452: end 1453: end 1454: 1455: "(#{segments.join(') AND (')})" unless segments.empty? 1456: end
merge_includes (first, second)
Merges includes so that the result is a valid include
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1440 1440: def merge_includes(first, second) 1441: (safe_to_array(first) + safe_to_array(second)).uniq 1442: end
method_missing (method_id, *arguments)
Enables dynamic finders like find_by_user_name(user_name) and find_by_user_name_and_password(user_name, password) that are turned into find(:first, :conditions => ["user_name = ?", user_name]) and find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password]) respectively. Also works for find(:all) by using find_all_by_amount(50) that is turned into find(:all, :conditions => ["amount = ?", 50]).
It‘s even possible to use all the additional parameters to find. For example, the full interface for find_all_by_amount is actually find_all_by_amount(amount, options).
This also enables you to initialize a record if it is not found, such as find_or_initialize_by_amount(amount) or find_or_create_by_user_and_password(user, password).
Each dynamic finder or initializer/creator is also defined in the class after it is first invoked, so that future attempts to use it do not run through method_missing.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1565 1565: def method_missing(method_id, *arguments) 1566: if match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(method_id.to_s) 1567: finder = determine_finder(match) 1568: 1569: attribute_names = extract_attribute_names_from_match(match) 1570: super unless all_attributes_exists?(attribute_names) 1571: 1572: self.class_eval %{ 1573: def self.#{method_id}(*args) 1574: options = args.extract_options! 1575: attributes = construct_attributes_from_arguments([:#{attribute_names.join(',:')}], args) 1576: finder_options = { :conditions => attributes } 1577: validate_find_options(options) 1578: set_readonly_option!(options) 1579: 1580: if options[:conditions] 1581: with_scope(:find => finder_options) do 1582: ActiveSupport::Deprecation.silence { send(:#{finder}, options) } 1583: end 1584: else 1585: ActiveSupport::Deprecation.silence { send(:#{finder}, options.merge(finder_options)) } 1586: end 1587: end 1588: }, __FILE__, __LINE__ 1589: send(method_id, *arguments) 1590: elsif match = /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/.match(method_id.to_s) 1591: instantiator = determine_instantiator(match) 1592: attribute_names = extract_attribute_names_from_match(match) 1593: super unless all_attributes_exists?(attribute_names) 1594: 1595: self.class_eval %{ 1596: def self.#{method_id}(*args) 1597: guard_protected_attributes = false 1598: 1599: if args[0].is_a?(Hash) 1600: guard_protected_attributes = true 1601: attributes = args[0].with_indifferent_access 1602: find_attributes = attributes.slice(*[:#{attribute_names.join(',:')}]) 1603: else 1604: find_attributes = attributes = construct_attributes_from_arguments([:#{attribute_names.join(',:')}], args) 1605: end 1606: 1607: options = { :conditions => find_attributes } 1608: set_readonly_option!(options) 1609: 1610: record = find_initial(options) 1611: 1612: if record.nil? 1613: record = self.new { |r| r.send(:attributes=, attributes, guard_protected_attributes) } 1614: #{'yield(record) if block_given?'} 1615: #{'record.save' if instantiator == :create} 1616: record 1617: else 1618: record 1619: end 1620: end 1621: }, __FILE__, __LINE__ 1622: send(method_id, *arguments) 1623: else 1624: super 1625: end 1626: end
parse_sqlite_config! (config)
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb, line 28 28: def parse_sqlite_config!(config) 29: config[:database] ||= config[:dbfile] 30: # Require database. 31: unless config[:database] 32: raise ArgumentError, "No database file specified. Missing argument: database" 33: end 34: 35: # Allow database path relative to RAILS_ROOT, but only if 36: # the database path is not the special path that tells 37: # Sqlite to build a database only in memory. 38: if Object.const_defined?(:RAILS_ROOT) && ':memory:' != config[:database] 39: config[:database] = File.expand_path(config[:database], RAILS_ROOT) 40: end 41: end
quoted_table_name ()
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2625 2625: def self.quoted_table_name 2626: self.connection.quote_table_name(self.table_name) 2627: end
remove_stale_cached_threads! (cache, &block)
Remove stale threads from the cache.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 145 145: def remove_stale_cached_threads!(cache, &block) 146: stale = Set.new(cache.keys) 147: 148: Thread.list.each do |thread| 149: stale.delete(thread.object_id) if thread.alive? 150: end 151: 152: stale.each do |thread_id| 153: clear_cache!(cache, thread_id, &block) 154: end 155: end
reverse_sql_order (order_query)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1284 1284: def reverse_sql_order(order_query) 1285: reversed_query = order_query.split(/,/).each { |s| 1286: if s.match(/\s(asc|ASC)$/) 1287: s.gsub!(/\s(asc|ASC)$/, ' DESC') 1288: elsif s.match(/\s(desc|DESC)$/) 1289: s.gsub!(/\s(desc|DESC)$/, ' ASC') 1290: elsif !s.match(/\s(asc|ASC|desc|DESC)$/) 1291: s.concat(' DESC') 1292: end 1293: }.join(',') 1294: end
safe_to_array (o)
Object#to_a is deprecated, though it does have the desired behavior
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1459 1459: def safe_to_array(o) 1460: case o 1461: when NilClass 1462: [] 1463: when Array 1464: o 1465: else 1466: [o] 1467: end 1468: end
type_condition ()
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1537 1537: def type_condition 1538: quoted_inheritance_column = connection.quote_column_name(inheritance_column) 1539: type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{name.demodulize}' ") do |condition, subclass| 1540: condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{subclass.name.demodulize}' " 1541: end 1542: 1543: " (#{type_condition}) " 1544: end
type_name_with_module (type_name)
Nest the type name in the same module as this class. Bar is "MyApp::Business::Bar" relative to MyApp::Business::Foo
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1419 1419: def type_name_with_module(type_name) 1420: (/^::/ =~ type_name) ? type_name : "#{parent.name}::#{type_name}" 1421: end
undecorated_table_name (class_name = base_class.name)
Guesses the table name, but does not decorate it with prefix and suffix information.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 1547 1547: def undecorated_table_name(class_name = base_class.name) 1548: table_name = Inflector.underscore(Inflector.demodulize(class_name)) 1549: table_name = Inflector.pluralize(table_name) if pluralize_table_names 1550: table_name 1551: end
Public Instance Methods
== (comparison_object)
Returns true if the comparison_object is the same object, or is of the same type and has the same id.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2353 2353: def ==(comparison_object) 2354: comparison_object.equal?(self) || 2355: (comparison_object.instance_of?(self.class) && 2356: comparison_object.id == id && 2357: !comparison_object.new_record?) 2358: end
[] (attr_name)
Returns the value of the attribute identified by attr_name after it has been typecast (for example, "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)). (Alias for the protected read_attribute method).
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2270 2270: def [](attr_name) 2271: read_attribute(attr_name) 2272: end
[]= (attr_name, value)
Updates the attribute identified by attr_name with the specified value. (Alias for the protected write_attribute method).
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2276 2276: def []=(attr_name, value) 2277: write_attribute(attr_name, value) 2278: end
attribute_for_inspect (attr_name)
Format attributes nicely for inspect.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2318 2318: def attribute_for_inspect(attr_name) 2319: value = read_attribute(attr_name) 2320: 2321: if value.is_a?(String) && value.length > 50 2322: "#{value[0..50]}...".inspect 2323: elsif value.is_a?(Date) || value.is_a?(Time) 2324: %("#{value.to_s(:db)}") 2325: else 2326: value.inspect 2327: end 2328: end
attribute_names ()
Returns an array of names for the attributes available on this object sorted alphabetically.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2343 2343: def attribute_names 2344: @attributes.keys.sort 2345: end
attribute_present? (attribute)
Returns true if the specified attribute has been set by the user or by a database load and is neither nil nor empty? (the latter only applies to objects that respond to empty?, most notably Strings).
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2332 2332: def attribute_present?(attribute) 2333: value = read_attribute(attribute) 2334: !value.blank? 2335: end
attributes (options = nil)
Returns a hash of all the attributes with their names as keys and the values of the attributes as values.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2302 2302: def attributes(options = nil) 2303: self.attribute_names.inject({}) do |attrs, name| 2304: attrs[name] = read_attribute(name) 2305: attrs 2306: end 2307: end
attributes= (new_attributes, guard_protected_attributes = true)
Allows you to set all the attributes at once by passing in a hash with keys matching the attribute names (which again matches the column names). Sensitive attributes can be protected from this form of mass-assignment by using the attr_protected macro. Or you can alternatively specify which attributes can be accessed with the attr_accessible macro. Then all the attributes not included in that won‘t be allowed to be mass-assigned.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2285 2285: def attributes=(new_attributes, guard_protected_attributes = true) 2286: return if new_attributes.nil? 2287: attributes = new_attributes.dup 2288: attributes.stringify_keys! 2289: 2290: multi_parameter_attributes = [] 2291: attributes = remove_attributes_protected_from_mass_assignment(attributes) if guard_protected_attributes 2292: 2293: attributes.each do |k, v| 2294: k.include?("(") ? multi_parameter_attributes << [ k, v ] : send(k + "=", v) 2295: end 2296: 2297: assign_multiparameter_attributes(multi_parameter_attributes) 2298: end
attributes_before_type_cast ()
Returns a hash of attributes before typecasting and deserialization.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2310 2310: def attributes_before_type_cast 2311: self.attribute_names.inject({}) do |attrs, name| 2312: attrs[name] = read_attribute_before_type_cast(name) 2313: attrs 2314: end 2315: end
becomes (klass)
Returns an instance of the specified klass with the attributes of the current record. This is mostly useful in relation to single-table inheritance structures where you want a subclass to appear as the superclass. This can be used along with record identification in Action Pack to allow, say, Client < Company to do something like render :partial => @client.becomes(Company) to render that instance using the companies/company partial instead of clients/client.
Note: The new instance will share a link to the same attributes as the original class. So any change to the attributes in either instance will affect the other.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2188 2188: def becomes(klass) 2189: returning klass.new do |became| 2190: became.instance_variable_set("@attributes", @attributes) 2191: became.instance_variable_set("@attributes_cache", @attributes_cache) 2192: became.instance_variable_set("@new_record", new_record?) 2193: end 2194: end
cache_key ()
Returns a cache key that can be used to identify this record. Examples:
Product.new.cache_key # => "products/new" Product.find(5).cache_key # => "products/5" (updated_at not available) Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2107 2107: def cache_key 2108: case 2109: when new_record? 2110: "#{self.class.name.tableize}/new" 2111: when self[:updated_at] 2112: "#{self.class.name.tableize}/#{id}-#{updated_at.to_s(:number)}" 2113: else 2114: "#{self.class.name.tableize}/#{id}" 2115: end 2116: end
clone ()
Returns a clone of the record that hasn‘t been assigned an id yet and is treated as a new record. Note that this is a "shallow" clone: it copies the object‘s attributes only, not its associations. The extent of a "deep" clone is application-specific and is therefore left to the application to implement according to its need.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2173 2173: def clone 2174: attrs = clone_attributes(:read_attribute_before_type_cast) 2175: attrs.delete(self.class.primary_key) 2176: record = self.class.new 2177: record.send :instance_variable_set, '@attributes', attrs 2178: record 2179: end
column_for_attribute (name)
Returns the column object for the named attribute.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2348 2348: def column_for_attribute(name) 2349: self.class.columns_hash[name.to_s] 2350: end
connection ()
Returns the connection currently associated with the class. This can also be used to "borrow" the connection to do database work that isn‘t easily done without going straight to SQL.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb, line 173 173: def connection 174: self.class.connection 175: end
decrement (attribute, by = 1)
Initializes the attribute to zero if nil and subtracts the value passed as by (default is one). Only makes sense for number-based attributes. Returns self.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2231 2231: def decrement(attribute, by = 1) 2232: self[attribute] ||= 0 2233: self[attribute] -= by 2234: self 2235: end
decrement! (attribute, by = 1)
Decrements the attribute and saves the record. Note: Updates made with this method aren‘t subjected to validation checks
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2239 2239: def decrement!(attribute, by = 1) 2240: decrement(attribute, by).update_attribute(attribute, self[attribute]) 2241: end
destroy ()
Deletes the record in the database and freezes this instance to reflect that no changes should be made (since they can‘t be persisted).
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2156 2156: def destroy 2157: unless new_record? 2158: connection.delete "DELETE FROM \#{self.class.quoted_table_name}\nWHERE \#{connection.quote_column_name(self.class.primary_key)} = \#{quoted_id}\n", "#{self.class.name} Destroy" 2159: end 2160: 2161: freeze 2162: end
eql? (comparison_object)
Delegates to ==
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2361 2361: def eql?(comparison_object) 2362: self == (comparison_object) 2363: end
freeze ()
Freeze the attributes hash such that associations are still accessible, even on destroyed records.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2372 2372: def freeze 2373: @attributes.freeze; self 2374: end
frozen? ()
Returns true if the attributes hash has been frozen.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2377 2377: def frozen? 2378: @attributes.frozen? 2379: end
has_attribute? (attr_name)
Returns true if the given attribute is in the attributes hash
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2338 2338: def has_attribute?(attr_name) 2339: @attributes.has_key?(attr_name.to_s) 2340: end
hash ()
Delegates to id in order to allow two records of the same type and id to work with something like:
[ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2367 2367: def hash 2368: id.hash 2369: end
id ()
A model instance‘s primary key is always available as model.id whether you name it the default ‘id’ or set it to something else.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2086 2086: def id 2087: attr_name = self.class.primary_key 2088: column = column_for_attribute(attr_name) 2089: 2090: self.class.send(:define_read_method, :id, attr_name, column) 2091: # now that the method exists, call it 2092: self.send attr_name.to_sym 2093: 2094: end
id= (value)
Sets the primary ID.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2127 2127: def id=(value) 2128: write_attribute(self.class.primary_key, value) 2129: end
id_before_type_cast (
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2118 2118: def id_before_type_cast #nodoc 2119: read_attribute_before_type_cast(self.class.primary_key) 2120: end
increment (attribute, by = 1)
Initializes the attribute to zero if nil and adds the value passed as by (default is one). Only makes sense for number-based attributes. Returns self.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2218 2218: def increment(attribute, by = 1) 2219: self[attribute] ||= 0 2220: self[attribute] += by 2221: self 2222: end
increment! (attribute, by = 1)
Increments the attribute and saves the record. Note: Updates made with this method aren‘t subjected to validation checks
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2226 2226: def increment!(attribute, by = 1) 2227: increment(attribute, by).update_attribute(attribute, self[attribute]) 2228: end
inspect ()
Returns the contents of the record as a nicely formatted string.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2393 2393: def inspect 2394: attributes_as_nice_string = self.class.column_names.collect { |name| 2395: if has_attribute?(name) || new_record? 2396: "#{name}: #{attribute_for_inspect(name)}" 2397: end 2398: }.compact.join(", ") 2399: "#<#{self.class} #{attributes_as_nice_string}>" 2400: end
new_record? ()
Returns true if this object hasn‘t been saved yet — that is, a record for the object doesn‘t exist yet.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2132 2132: def new_record? 2133: defined?(@new_record) && @new_record 2134: end
quoted_id (
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2122 2122: def quoted_id #nodoc 2123: quote_value(id, column_for_attribute(self.class.primary_key)) 2124: end
readonly! ()
Marks this record as read only.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2388 2388: def readonly! 2389: @readonly = true 2390: end
readonly? ()
Returns true if the record is read only. Records loaded through joins with piggy-back attributes will be marked as read only since they cannot be saved.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2383 2383: def readonly? 2384: defined?(@readonly) && @readonly == true 2385: end
reload (options = nil)
Reloads the attributes of this object from the database. The optional options argument is passed to find when reloading so you may do e.g. record.reload(:lock => true) to reload the same record with an exclusive row lock.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2259 2259: def reload(options = nil) 2260: clear_aggregation_cache 2261: clear_association_cache 2262: @attributes.update(self.class.find(self.id, options).instance_variable_get('@attributes')) 2263: @attributes_cache = {} 2264: self 2265: end
save ()
- No record exists: Creates a new record with values matching those of the object attributes.
- A record does exist: Updates the record with values matching those of the object attributes.
Note: If your model specifies any validations then the method declaration dynamically changes to:
save(perform_validation=true)
Calling save(false) saves the model without running validations. See ActiveRecord::Validations for more information.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2144 2144: def save 2145: create_or_update 2146: end
save! ()
Attempts to save the record, but instead of just returning false if it couldn‘t happen, it raises a RecordNotSaved exception
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2150 2150: def save! 2151: create_or_update || raise(RecordNotSaved) 2152: end
to_param ()
Enables Active Record objects to be used as URL parameters in Action Pack automatically.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2097 2097: def to_param 2098: # We can't use alias_method here, because method 'id' optimizes itself on the fly. 2099: (id = self.id) ? id.to_s : nil # Be sure to stringify the id for routes 2100: end
toggle (attribute)
Turns an attribute that‘s currently true into false and vice versa. Returns self.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2244 2244: def toggle(attribute) 2245: self[attribute] = !send("#{attribute}?") 2246: self 2247: end
toggle! (attribute)
Toggles the attribute and saves the record. Note: Updates made with this method aren‘t subjected to validation checks
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2251 2251: def toggle!(attribute) 2252: toggle(attribute).update_attribute(attribute, self[attribute]) 2253: end
update_attribute (name, value)
Updates a single attribute and saves the record. This is especially useful for boolean flags on existing records. Note: This method is overwritten by the Validation module that‘ll make sure that updates made with this method aren‘t subjected to validation checks. Hence, attributes can be updated even if the full object isn‘t valid.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2199 2199: def update_attribute(name, value) 2200: send(name.to_s + '=', value) 2201: save 2202: end
update_attributes (attributes)
Updates all the attributes from the passed-in Hash and saves the record. If the object is invalid, the saving will fail and false will be returned.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2206 2206: def update_attributes(attributes) 2207: self.attributes = attributes 2208: save 2209: end
update_attributes! (attributes)
Updates an object just like Base.update_attributes but calls save! instead of save so an exception is raised if the record is invalid.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2212 2212: def update_attributes!(attributes) 2213: self.attributes = attributes 2214: save! 2215: end
Private Instance Methods
assign_multiparameter_attributes (pairs)
Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done by calling new on the column type or aggregation type (through composed_of) object with these parameters. So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the parentheses to have the parameters typecasted before they‘re used in the constructor. Use i for Fixnum, f for Float, s for String, and a for Array. If all the values for a given attribute are empty, the attribute will be set to nil.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2543 2543: def assign_multiparameter_attributes(pairs) 2544: execute_callstack_for_multiparameter_attributes( 2545: extract_callstack_for_multiparameter_attributes(pairs) 2546: ) 2547: end
attributes_from_column_definition ()
Initializes the attributes array with keys matching the columns from the linked table and the values matching the corresponding default value of that column, so that a new instance, or one populated from a passed-in Hash, still has all the attributes that instances loaded from the database would.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2530 2530: def attributes_from_column_definition 2531: self.class.columns.inject({}) do |attributes, column| 2532: attributes[column.name] = column.default unless column.name == self.class.primary_key 2533: attributes 2534: end 2535: end
attributes_protected_by_default ()
The primary key and inheritance column can never be set by mass-assignment for security reasons.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2496 2496: def attributes_protected_by_default 2497: default = [ self.class.primary_key, self.class.inheritance_column ] 2498: default << 'id' unless self.class.primary_key.eql? 'id' 2499: default 2500: end
attributes_with_quotes (include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
Returns a copy of the attributes hash where all the values have been safely quoted for use in an SQL statement.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2504 2504: def attributes_with_quotes(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys) 2505: quoted = {} 2506: connection = self.class.connection 2507: attribute_names.each do |name| 2508: if column = column_for_attribute(name) 2509: quoted[name] = connection.quote(read_attribute(name), column) unless !include_primary_key && column.primary 2510: end 2511: end 2512: include_readonly_attributes ? quoted : remove_readonly_attributes(quoted) 2513: end
clone_attribute_value (reader_method, attribute_name)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2652 2652: def clone_attribute_value(reader_method, attribute_name) 2653: value = send(reader_method, attribute_name) 2654: value.duplicable? ? value.clone : value 2655: rescue TypeError, NoMethodError 2656: value 2657: end
clone_attributes (reader_method = :read_attribute, attributes = {})
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2645 2645: def clone_attributes(reader_method = :read_attribute, attributes = {}) 2646: self.attribute_names.inject(attributes) do |attrs, name| 2647: attrs[name] = clone_attribute_value(reader_method, name) 2648: attrs 2649: end 2650: end
comma_pair_list (hash)
Returns a comma-separated pair list, like "key1 = val1, key2 = val2".
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2614 2614: def comma_pair_list(hash) 2615: hash.inject([]) { |list, pair| list << "#{pair.first} = #{pair.last}" }.join(", ") 2616: end
convert_number_column_value (value)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2456 2456: def convert_number_column_value(value) 2457: case value 2458: when FalseClass; 0 2459: when TrueClass; 1 2460: when ''; nil 2461: else value 2462: end 2463: end
create ()
Creates a record with values matching those of the instance attributes and returns its id.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2424 2424: def create 2425: if self.id.nil? && connection.prefetch_primary_key?(self.class.table_name) 2426: self.id = connection.next_sequence_value(self.class.sequence_name) 2427: end 2428: 2429: quoted_attributes = attributes_with_quotes 2430: 2431: statement = if quoted_attributes.empty? 2432: connection.empty_insert_statement(self.class.table_name) 2433: else 2434: "INSERT INTO #{self.class.quoted_table_name} " + 2435: "(#{quoted_column_names.join(', ')}) " + 2436: "VALUES(#{quoted_attributes.values.join(', ')})" 2437: end 2438: 2439: self.id = connection.insert(statement, "#{self.class.name} Create", 2440: self.class.primary_key, self.id, self.class.sequence_name) 2441: 2442: @new_record = false 2443: id 2444: end
create_or_update ()
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2403 2403: def create_or_update 2404: raise ReadOnlyRecord if readonly? 2405: result = new_record? ? create : update 2406: result != false 2407: end
ensure_proper_type ()
Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord descendent. Considering the hierarchy Reply < Message < ActiveRecord, this makes it possible to do Reply.new without having to set Reply = "Reply" yourself. No such attribute would be set for objects of the Message class in that example.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2450 2450: def ensure_proper_type 2451: unless self.class.descends_from_active_record? 2452: write_attribute(self.class.inheritance_column, Inflector.demodulize(self.class.name)) 2453: end 2454: end
execute_callstack_for_multiparameter_attributes (callstack)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2557 2557: def execute_callstack_for_multiparameter_attributes(callstack) 2558: errors = [] 2559: callstack.each do |name, values| 2560: klass = (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)).klass 2561: if values.empty? 2562: send(name + "=", nil) 2563: else 2564: begin 2565: value = if Time == klass 2566: instantiate_time_object(name, values) 2567: elsif Date == klass 2568: begin 2569: Date.new(*values) 2570: rescue ArgumentError => ex # if Date.new raises an exception on an invalid date 2571: 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 2572: end 2573: else 2574: klass.new(*values) 2575: end 2576: 2577: send(name + "=", value) 2578: rescue => ex 2579: errors << AttributeAssignmentError.new("error on assignment #{values.inspect} to #{name}", ex, name) 2580: end 2581: end 2582: end 2583: unless errors.empty? 2584: raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes" 2585: end 2586: end
extract_callstack_for_multiparameter_attributes (pairs)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2588 2588: def extract_callstack_for_multiparameter_attributes(pairs) 2589: attributes = { } 2590: 2591: for pair in pairs 2592: multiparameter_name, value = pair 2593: attribute_name = multiparameter_name.split("(").first 2594: attributes[attribute_name] = [] unless attributes.include?(attribute_name) 2595: 2596: unless value.empty? 2597: attributes[attribute_name] << 2598: [ find_parameter_position(multiparameter_name), type_cast_attribute_value(multiparameter_name, value) ] 2599: end 2600: end 2601: 2602: attributes.each { |name, values| attributes[name] = values.sort_by{ |v| v.first }.collect { |v| v.last } } 2603: end
find_parameter_position (multiparameter_name)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2609 2609: def find_parameter_position(multiparameter_name) 2610: multiparameter_name.scan(/\(([0-9]*).*\)/).first.first 2611: end
instantiate_time_object (name, values)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2549 2549: def instantiate_time_object(name, values) 2550: if Time.zone && self.class.time_zone_aware_attributes && !self.class.skip_time_zone_conversion_for_attributes.include?(name.to_sym) 2551: Time.zone.local(*values) 2552: else 2553: Time.time_with_datetime_fallback(@@default_timezone, *values) 2554: end 2555: end
interpolate_sql (sql, record = nil)
Interpolate custom sql string in instance context. Optional record argument is meant for custom insert_sql.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2522 2522: def interpolate_sql(sql, record = nil) 2523: instance_eval("%@#{sql.gsub('@', '\@')}@") 2524: end
object_from_yaml (string)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2640 2640: def object_from_yaml(string) 2641: return string unless string.is_a?(String) 2642: YAML::load(string) rescue string 2643: end
quote_columns (quoter, hash)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2629 2629: def quote_columns(quoter, hash) 2630: hash.inject({}) do |quoted, (name, value)| 2631: quoted[quoter.quote_column_name(name)] = value 2632: quoted 2633: end 2634: end
quote_value (value, column = nil)
Quote strings appropriately for SQL statements.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2516 2516: def quote_value(value, column = nil) 2517: self.class.connection.quote(value, column) 2518: end
quoted_column_names (attributes = attributes_with_quotes)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2618 2618: def quoted_column_names(attributes = attributes_with_quotes) 2619: connection = self.class.connection 2620: attributes.keys.collect do |column_name| 2621: connection.quote_column_name(column_name) 2622: end 2623: end
quoted_comma_pair_list (quoter, hash)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2636 2636: def quoted_comma_pair_list(quoter, hash) 2637: comma_pair_list(quote_columns(quoter, hash)) 2638: end
remove_attributes_protected_from_mass_assignment (attributes)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2465 2465: def remove_attributes_protected_from_mass_assignment(attributes) 2466: safe_attributes = 2467: if self.class.accessible_attributes.nil? && self.class.protected_attributes.nil? 2468: attributes.reject { |key, value| attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) } 2469: elsif self.class.protected_attributes.nil? 2470: attributes.reject { |key, value| !self.class.accessible_attributes.include?(key.gsub(/\(.+/, "")) || attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) } 2471: elsif self.class.accessible_attributes.nil? 2472: attributes.reject { |key, value| self.class.protected_attributes.include?(key.gsub(/\(.+/,"")) || attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) } 2473: else 2474: raise "Declare either attr_protected or attr_accessible for #{self.class}, but not both." 2475: end 2476: 2477: removed_attributes = attributes.keys - safe_attributes.keys 2478: 2479: if removed_attributes.any? 2480: logger.debug "WARNING: Can't mass-assign these protected attributes: #{removed_attributes.join(', ')}" 2481: end 2482: 2483: safe_attributes 2484: end
remove_readonly_attributes (attributes)
Removes attributes which have been marked as readonly.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2487 2487: def remove_readonly_attributes(attributes) 2488: unless self.class.readonly_attributes.nil? 2489: attributes.delete_if { |key, value| self.class.readonly_attributes.include?(key.gsub(/\(.+/,"")) } 2490: else 2491: attributes 2492: end 2493: end
type_cast_attribute_value (multiparameter_name, value)
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2605 2605: def type_cast_attribute_value(multiparameter_name, value) 2606: multiparameter_name =~ /\([0-9]*([a-z])\)/ ? value.send("to_" + $1) : value 2607: end
update (attribute_names = @attributes.keys)
Updates the associated record with values matching those of the instance attributes. Returns the number of affected rows.
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2411 2411: def update(attribute_names = @attributes.keys) 2412: quoted_attributes = attributes_with_quotes(false, false, attribute_names) 2413: return 0 if quoted_attributes.empty? 2414: connection.update( 2415: "UPDATE #{self.class.quoted_table_name} " + 2416: "SET #{quoted_comma_pair_list(connection, quoted_attributes)} " + 2417: "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quote_value(id)}", 2418: "#{self.class.name} Update" 2419: ) 2420: end