Update to Rails 2.3.9 and itextomml 1.3.27

This commit is contained in:
Jacques Distler 2010-09-05 15:24:15 -05:00
parent 113e0af736
commit ef30cc22df
200 changed files with 3065 additions and 1204 deletions

View file

@ -1,8 +1,5 @@
*2.3.9 (September 4, 2010)*
*2.3.8 (May 24, 2010)*
* Version bump.
*2.3.7 (May 24, 2010)*
* Version bump.

View file

@ -192,7 +192,7 @@ spec = Gem::Specification.new do |s|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
end
s.add_dependency('activesupport', '= 2.3.8' + PKG_BUILD)
s.add_dependency('activesupport', '= 2.3.9' + PKG_BUILD)
s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite"
s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite"

View file

@ -12,6 +12,8 @@ require 'rbench'
__DIR__ = File.dirname(__FILE__)
$:.unshift "#{__DIR__}/../lib"
$:.unshift "#{__DIR__}/../../activesupport/lib"
require 'active_record'
conn = { :adapter => 'mysql',

View file

@ -282,7 +282,11 @@ module ActiveRecord
end
through_records.flatten!
else
records.first.class.preload_associations(records, through_association)
options = {}
options[:include] = reflection.options[:include] || reflection.options[:source] if reflection.options[:conditions]
options[:order] = reflection.options[:order]
options[:conditions] = reflection.options[:conditions]
records.first.class.preload_associations(records, through_association, options)
through_records = records.map {|record| record.send(through_association)}.flatten
end
through_records.compact!
@ -357,7 +361,13 @@ module ActiveRecord
table_name = reflection.klass.quoted_table_name
if interface = reflection.options[:as]
conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} #{in_or_equals_for_ids(ids)} and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.sti_name}'"
parent_type = if reflection.active_record.abstract_class?
self.base_class.sti_name
else
reflection.active_record.sti_name
end
conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} #{in_or_equals_for_ids(ids)} and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{parent_type}'"
else
foreign_key = reflection.primary_key_name
conditions = "#{reflection.klass.quoted_table_name}.#{foreign_key} #{in_or_equals_for_ids(ids)}"

View file

@ -1782,7 +1782,7 @@ module ActiveRecord
end
def using_limitable_reflections?(reflections)
reflections.collect(&:collection?).length.zero?
reflections.none?(&:collection?)
end
def column_aliases(join_dependency)

View file

@ -234,8 +234,9 @@ module ActiveRecord
# See destroy for more info.
def destroy_all
load_target
destroy(@target)
reset_target!
destroy(@target).tap do
reset_target!
end
end
def create(attrs = {})
@ -349,7 +350,17 @@ module ActiveRecord
begin
if !loaded?
if @target.is_a?(Array) && @target.any?
@target = find_target + @target.find_all {|t| t.new_record? }
@target = find_target.map do |f|
i = @target.index(f)
if i
@target.delete_at(i).tap do |t|
keys = ["id"] + t.changes.keys + (f.attribute_names - t.attribute_names)
t.attributes = f.attributes.except(*keys)
end
else
f
end
end + @target
else
@target = find_target
end
@ -364,6 +375,17 @@ module ActiveRecord
end
def method_missing(method, *args)
case method.to_s
when 'find_or_create'
return find(:first, :conditions => args.first) || create(args.first)
when /^find_or_create_by_(.*)$/
rest = $1
return send("find_by_#{rest}", *args) ||
method_missing("create_by_#{rest}", *args)
when /^create_by_(.*)$/
return create($1.split('_and_').zip(args).inject({}) { |h,kv| k,v=kv ; h[k] = v ; h })
end
if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
if block_given?
super { |*block_args| yield(*block_args) }
@ -411,7 +433,14 @@ module ActiveRecord
callback(:before_add, record)
yield(record) if block_given?
@target ||= [] unless loaded?
@target << record unless @reflection.options[:uniq] && @target.include?(record)
index = @target.index(record)
unless @reflection.options[:uniq] && index
if index
@target[index] = record
else
@target << record
end
end
callback(:after_add, record)
set_inverse_instance(record, @owner)
record

View file

@ -230,10 +230,6 @@ module ActiveRecord
# It's also possible to instantiate related objects, so a Client class belonging to the clients
# table with a +master_id+ foreign key can instantiate master through Client#master.
def method_missing(method_id, *args, &block)
if method_id == :to_ary || method_id == :to_str
raise NoMethodError, "undefined method `#{method_id}' for #{inspect}:#{self.class}"
end
method_name = method_id.to_s
if self.class.private_method_defined?(method_name)

View file

@ -146,12 +146,12 @@ module ActiveRecord
# add_autosave_association_callbacks(reflect_on_association(name))
# end
ASSOCIATION_TYPES.each do |type|
module_eval %{
module_eval <<-CODE, __FILE__, __LINE__ + 1
def #{type}(name, options = {})
super
add_autosave_association_callbacks(reflect_on_association(name))
end
}
CODE
end
# Adds a validate and save callback for the association as specified by

View file

@ -1,5 +1,6 @@
require 'yaml'
require 'set'
require 'active_support/core_ext/class/attribute'
module ActiveRecord #:nodoc:
# Generic Active Record exception class.
@ -515,7 +516,7 @@ module ActiveRecord #:nodoc:
@@timestamped_migrations = true
# Determine whether to store the full constant name including namespace when using STI
superclass_delegating_accessor :store_full_sti_class
class_attribute :store_full_sti_class
self.store_full_sti_class = false
# Stores the default scope for the class
@ -935,11 +936,18 @@ module ActiveRecord #:nodoc:
def reset_counters(id, *counters)
object = find(id)
counters.each do |association|
child_class = reflect_on_association(association).klass
counter_name = child_class.reflect_on_association(self.name.downcase.to_sym).counter_cache_column
child_class = reflect_on_association(association.to_sym).klass
belongs_name = self.name.demodulize.underscore.to_sym
counter_name = child_class.reflect_on_association(belongs_name).counter_cache_column
value = object.send(association).count
connection.update("UPDATE #{quoted_table_name} SET #{connection.quote_column_name(counter_name)} = #{object.send(association).count} WHERE #{connection.quote_column_name(primary_key)} = #{quote_value(object.id)}", "#{name} UPDATE")
connection.update(<<-CMD, "#{name} UPDATE")
UPDATE #{quoted_table_name}
SET #{connection.quote_column_name(counter_name)} = #{value}
WHERE #{connection.quote_column_name(primary_key)} = #{quote_value(object.id)}
CMD
end
return true
end
# A generic "counter updater" implementation, intended primarily to be
@ -972,19 +980,13 @@ module ActiveRecord #:nodoc:
# # SET comment_count = comment_count + 1,
# # WHERE id IN (10, 15)
def update_counters(id, counters)
updates = counters.inject([]) { |list, (counter_name, increment)|
sign = increment < 0 ? "-" : "+"
list << "#{connection.quote_column_name(counter_name)} = COALESCE(#{connection.quote_column_name(counter_name)}, 0) #{sign} #{increment.abs}"
}.join(", ")
if id.is_a?(Array)
ids_list = id.map {|i| quote_value(i)}.join(', ')
condition = "IN (#{ids_list})"
else
condition = "= #{quote_value(id)}"
updates = counters.map do |counter_name, value|
operator = value < 0 ? '-' : '+'
quoted_column = connection.quote_column_name(counter_name)
"#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
end
update_all(updates, "#{connection.quote_column_name(primary_key)} #{condition}")
update_all(updates.join(', '), primary_key => id )
end
# Increment a number field by one, usually representing a count.
@ -1284,6 +1286,8 @@ module ActiveRecord #:nodoc:
# Turns the +table_name+ back into a class name following the reverse rules of +table_name+.
def class_name(table_name = table_name) # :nodoc:
ActiveSupport::Deprecation.warn("ActiveRecord::Base#class_name is deprecated and will be removed in Rails 2.3.9.", caller)
# remove any prefix and/or suffix from the table name
class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].camelize
class_name = class_name.singularize if pluralize_table_names
@ -2642,7 +2646,7 @@ module ActiveRecord #:nodoc:
# 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.
def becomes(klass)
returning klass.new do |became|
klass.new.tap do |became|
became.instance_variable_set("@attributes", @attributes)
became.instance_variable_set("@attributes_cache", @attributes_cache)
became.instance_variable_set("@new_record", new_record?)
@ -2660,12 +2664,20 @@ module ActiveRecord #:nodoc:
# 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.
def update_attributes(attributes)
with_transaction_returning_status(:update_attributes_inside_transaction, attributes)
end
def update_attributes_inside_transaction(attributes) #:nodoc:
self.attributes = attributes
save
end
# Updates an object just like Base.update_attributes but calls save! instead of save so an exception is raised if the record is invalid.
def update_attributes!(attributes)
with_transaction_returning_status(:update_attributes_inside_transaction!, attributes)
end
def update_attributes_inside_transaction!(attributes) #:nodoc:
self.attributes = attributes
save!
end

View file

@ -10,7 +10,7 @@ module ActiveRecord
##
# :singleton-method:
# The connection handler
superclass_delegating_accessor :connection_handler
class_attribute :connection_handler
self.connection_handler = ConnectionAdapters::ConnectionHandler.new
# Returns the connection currently associated with the class. This can

View file

@ -195,6 +195,7 @@ module ActiveRecord
# remove_column(:suppliers, :qualification)
# remove_columns(:suppliers, :qualification, :experience)
def remove_column(table_name, *column_names)
raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
column_names.flatten.each do |column_name|
execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
end

View file

@ -211,6 +211,12 @@ module ActiveRecord
log_info(sql, name, 0)
nil
end
rescue SystemExit, SignalException, NoMemoryError => e
# Don't re-wrap these exceptions. They are probably not being caused by invalid
# sql, but rather some external stimulus beyond the responsibilty of this code.
# Additionaly, wrapping these exceptions with StatementInvalid would lead to
# meaningful loss of data, such as losing SystemExit#status.
raise e
rescue Exception => e
# Log message and raise exception.
# Set last_verification to 0, so that connection gets verified

View file

@ -315,6 +315,7 @@ module ActiveRecord
rows = []
result.each { |row| rows << row }
result.free
@connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
rows
end
@ -638,6 +639,7 @@ module ActiveRecord
result = execute(sql, name)
rows = result.all_hashes
result.free
@connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
rows
end

View file

@ -25,7 +25,7 @@ module ActiveRecord
module ConnectionAdapters #:nodoc:
class SQLite3Adapter < SQLiteAdapter # :nodoc:
def table_structure(table_name)
returning structure = @connection.table_info(quote_table_name(table_name)) do
@connection.table_info(quote_table_name(table_name)).tap do |structure|
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
end
end

View file

@ -269,6 +269,7 @@ module ActiveRecord
end
def remove_column(table_name, *column_names) #:nodoc:
raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
column_names.flatten.each do |column_name|
alter_table(table_name) do |definition|
definition.columns.delete(definition[column_name])
@ -329,7 +330,7 @@ module ActiveRecord
end
def table_structure(table_name)
returning structure = execute("PRAGMA table_info(#{quote_table_name(table_name)})") do
execute("PRAGMA table_info(#{quote_table_name(table_name)})").tap do |structure|
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
end
end

View file

@ -44,7 +44,7 @@ module ActiveRecord
base.alias_method_chain :update, :dirty
base.alias_method_chain :reload, :dirty
base.superclass_delegating_accessor :partial_updates
base.class_attribute :partial_updates
base.partial_updates = true
base.send(:extend, ClassMethods)

View file

@ -11,23 +11,23 @@ en:
accepted: "must be accepted"
empty: "can't be empty"
blank: "can't be blank"
too_long: "is too long (maximum is {{count}} characters)"
too_short: "is too short (minimum is {{count}} characters)"
wrong_length: "is the wrong length (should be {{count}} characters)"
too_long: "is too long (maximum is %{count} characters)"
too_short: "is too short (minimum is %{count} characters)"
wrong_length: "is the wrong length (should be %{count} characters)"
taken: "has already been taken"
not_a_number: "is not a number"
greater_than: "must be greater than {{count}}"
greater_than_or_equal_to: "must be greater than or equal to {{count}}"
equal_to: "must be equal to {{count}}"
less_than: "must be less than {{count}}"
less_than_or_equal_to: "must be less than or equal to {{count}}"
greater_than: "must be greater than %{count}"
greater_than_or_equal_to: "must be greater than or equal to %{count}"
equal_to: "must be equal to %{count}"
less_than: "must be less than %{count}"
less_than_or_equal_to: "must be less than or equal to %{count}"
odd: "must be odd"
even: "must be even"
record_invalid: "Validation failed: {{errors}}"
record_invalid: "Validation failed: %{errors}"
# Append your own errors here or at the model/attributes scope.
full_messages:
format: "{{attribute}} {{message}}"
format: "%{attribute} %{message}"
# You can define own errors for models or model attributes.
# The values :model, :attribute and :value are always available for interpolation.
@ -35,7 +35,7 @@ en:
# For example,
# models:
# user:
# blank: "This is a custom blank message for {{model}}: {{attribute}}"
# blank: "This is a custom blank message for %{model}: %{attribute}"
# attributes:
# login:
# blank: "This is a custom blank message for User login"

View file

@ -128,6 +128,7 @@ module ActiveRecord
end
end
@destroyed = true
freeze
end

View file

@ -516,7 +516,7 @@ module ActiveRecord
raise DuplicateMigrationNameError.new(name.camelize)
end
klasses << returning(MigrationProxy.new) do |migration|
klasses << (MigrationProxy.new).tap do |migration|
migration.name = name.camelize
migration.version = version
migration.filename = file

View file

@ -8,10 +8,7 @@ module ActiveRecord
#
# You can define a scope that applies to all finders using ActiveRecord::Base.default_scope.
def self.included(base)
base.class_eval do
extend ClassMethods
named_scope :scoped, lambda { |scope| scope }
end
base.extend ClassMethods
end
module ClassMethods
@ -19,6 +16,10 @@ module ActiveRecord
read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
end
def scoped(scope, &block)
Scope.new(self, scope, &block)
end
# Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query,
# such as <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>.
#
@ -84,18 +85,22 @@ module ActiveRecord
# assert_equal expected_options, Shirt.colored('red').proxy_options
def named_scope(name, options = {}, &block)
name = name.to_sym
scopes[name] = lambda do |parent_scope, *args|
Scope.new(parent_scope, case options
when Hash
options
when Proc
options.call(*args)
if self.model_name != parent_scope.model_name
options.bind(parent_scope).call(*args)
else
options.call(*args)
end
end, &block)
end
(class << self; self end).instance_eval do
define_method name do |*args|
scopes[name].call(self, *args)
end
singleton_class.send :define_method, name do |*args|
scopes[name].call(self, *args)
end
end
end

View file

@ -286,7 +286,9 @@ module ActiveRecord
assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy])
elsif attributes['id']
raise_nested_attributes_record_not_found(association_name, attributes['id'])
existing_record = self.class.reflect_on_association(association_name).klass.find(attributes['id'])
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
self.send(association_name.to_s+'=', existing_record)
elsif !reject_new_record?(association_name, attributes)
method = "build_#{association_name}"
@ -356,11 +358,16 @@ module ActiveRecord
unless reject_new_record?(association_name, attributes)
association.build(attributes.except(*UNASSIGNABLE_KEYS))
end
elsif existing_records.size == 0 # Existing record but not yet associated
existing_record = self.class.reflect_on_association(association_name).klass.find(attributes['id'])
association.send(:add_record_to_target_with_callbacks, existing_record) unless association.loaded?
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s }
association.send(:add_record_to_target_with_callbacks, existing_record) unless association.loaded?
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
else
raise_nested_attributes_record_not_found(association_name, attributes['id'])
end
end
end
@ -380,7 +387,7 @@ module ActiveRecord
ConnectionAdapters::Column.value_to_boolean(hash['_destroy'])
end
# Determines if a new record should be build by checking for
# Determines if a new record should be built by checking for
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
# association and evaluates to +true+.
def reject_new_record?(association_name, attributes)
@ -396,9 +403,5 @@ module ActiveRecord
end
end
def raise_nested_attributes_record_not_found(association_name, record_id)
reflection = self.class.reflect_on_association(association_name)
raise RecordNotFound, "Couldn't find #{reflection.klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
end
end
end

View file

@ -74,7 +74,7 @@ module ActiveRecord #:nodoc:
end
def serializable_record
returning(serializable_record = {}) do
{}.tap do |serializable_record|
serializable_names.each { |name| serializable_record[name] = @record.send(name) }
add_includes do |association, records, opts|
if records.is_a?(Enumerable)

View file

@ -184,7 +184,7 @@ module ActiveRecord
# Look up a session by id and unmarshal its data if found.
def find_by_session_id(session_id)
if record = @@connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{@@connection.quote(session_id)}")
if record = connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{connection.quote(session_id)}")
new(:session_id => session_id, :marshaled_data => record['data'])
end
end
@ -310,6 +310,14 @@ module ActiveRecord
return true
end
def destroy(env)
if sid = current_session_id(env)
Base.silence do
get_session_model(env, sid).destroy
end
end
end
def get_session_model(env, sid)
if env[ENV_SESSION_OPTIONS_KEY][:id].nil?
env[SESSION_RECORD_KEY] = find_session(sid)

View file

@ -80,7 +80,7 @@ module ActiveRecord
# Wraps an error message into a full_message format.
#
# The default full_message format for any locale is <tt>"{{attribute}} {{message}}"</tt>.
# The default full_message format for any locale is <tt>"%{attribute} %{message}"</tt>.
# One can specify locale specific default full_message format by storing it as a
# translation for the key <tt>:"activerecord.errors.full_messages.format"</tt>.
#
@ -109,7 +109,7 @@ module ActiveRecord
keys = [
:"full_messages.#{@message}",
:'full_messages.format',
'{{attribute}} {{message}}'
'%{attribute} %{message}'
]
options.merge!(:default => keys, :message => self.message)
@ -604,13 +604,13 @@ module ActiveRecord
#
# class Person < ActiveRecord::Base
# validates_length_of :first_name, :maximum=>30
# validates_length_of :last_name, :maximum=>30, :message=>"less than {{count}} if you don't mind"
# validates_length_of :last_name, :maximum=>30, :message=>"less than %{count} if you don't mind"
# validates_length_of :fax, :in => 7..32, :allow_nil => true
# validates_length_of :phone, :in => 7..32, :allow_blank => true
# validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
# validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least {{count}} character"
# validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with {{count}} characters... don't play me."
# validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least {{count}} words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
# validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least %{count} character"
# validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with %{count} characters... don't play me."
# validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least %{count} words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
# end
#
# Configuration options:
@ -621,9 +621,9 @@ module ActiveRecord
# * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>.
# * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
# * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
# * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is {{count}} characters)").
# * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is {{count}} characters)").
# * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be {{count}} characters)").
# * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %{count} characters)").
# * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %{count} characters)").
# * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be %{count} characters)").
# * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
@ -825,7 +825,7 @@ module ActiveRecord
if scope = configuration[:scope]
Array(scope).map do |scope_item|
scope_value = record.send(scope_item)
condition_sql << " AND " << attribute_condition("#{record.class.quoted_table_name}.#{scope_item}", scope_value)
condition_sql << " AND " << attribute_condition("#{record.class.quoted_table_name}.#{connection.quote_column_name(scope_item)}", scope_value)
condition_params << scope_value
end
end
@ -885,7 +885,7 @@ module ActiveRecord
# class Person < ActiveRecord::Base
# validates_inclusion_of :gender, :in => %w( m f )
# validates_inclusion_of :age, :in => 0..99
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension {{value}} is not included in the list"
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %{value} is not included in the list"
# end
#
# Configuration options:
@ -919,7 +919,7 @@ module ActiveRecord
# class Person < ActiveRecord::Base
# validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
# validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension {{value}} is not allowed"
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %{value} is not allowed"
# end
#
# Configuration options:

View file

@ -2,7 +2,7 @@ module ActiveRecord
module VERSION #:nodoc:
MAJOR = 2
MINOR = 3
TINY = 8
TINY = 9
STRING = [MAJOR, MINOR, TINY].join('.')
end

View file

@ -65,15 +65,14 @@ class AdapterTest < ActiveRecord::TestCase
end
def test_not_specifying_database_name_for_cross_database_selects
assert_nothing_raised do
ActiveRecord::Base.establish_connection({
:adapter => 'mysql',
:username => 'rails'
})
ActiveRecord::Base.connection.execute "SELECT activerecord_unittest.pirates.*, activerecord_unittest2.courses.* FROM activerecord_unittest.pirates, activerecord_unittest2.courses"
begin
assert_nothing_raised do
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['arunit'].except(:database))
ActiveRecord::Base.connection.execute "SELECT activerecord_unittest.pirates.*, activerecord_unittest2.courses.* FROM activerecord_unittest.pirates, activerecord_unittest2.courses"
end
ensure
ActiveRecord::Base.establish_connection 'arunit'
end
ActiveRecord::Base.establish_connection 'arunit'
end
end

View file

@ -18,7 +18,7 @@ module Remembered
module ClassMethods
def remembered; @@remembered ||= []; end
def random_element; @@remembered.random_element; end
def sample; @@remembered.sample; end
end
end
@ -82,14 +82,14 @@ class EagerLoadPolyAssocsTest < ActiveRecord::TestCase
[Circle, Square, Triangle, NonPolyOne, NonPolyTwo].map(&:create!)
end
1.upto(NUM_SIMPLE_OBJS) do
PaintColor.create!(:non_poly_one_id => NonPolyOne.random_element.id)
PaintTexture.create!(:non_poly_two_id => NonPolyTwo.random_element.id)
PaintColor.create!(:non_poly_one_id => NonPolyOne.sample.id)
PaintTexture.create!(:non_poly_two_id => NonPolyTwo.sample.id)
end
1.upto(NUM_SHAPE_EXPRESSIONS) do
shape_type = [Circle, Square, Triangle].random_element
paint_type = [PaintColor, PaintTexture].random_element
ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.random_element.id,
:paint_type => paint_type.to_s, :paint_id => paint_type.random_element.id)
shape_type = [Circle, Square, Triangle].sample
paint_type = [PaintColor, PaintTexture].sample
ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.sample.id,
:paint_type => paint_type.to_s, :paint_id => paint_type.sample.id)
end
end

View file

@ -0,0 +1,19 @@
require 'cases/helper'
require 'models/tee'
require 'models/tie'
require 'models/polymorphic_design'
require 'models/polymorphic_price'
class EagerLoadNestedPolymorphicIncludeTest < ActiveRecord::TestCase
fixtures :tees, :ties, :polymorphic_designs, :polymorphic_prices
def test_eager_load_polymorphic_has_one_nested_under_polymorphic_belongs_to
designs = PolymorphicDesign.scoped(:include => {:designable => :polymorphic_price})
associated_price_ids = designs.map{|design| design.designable.polymorphic_price.id}
expected_price_ids = [1, 2, 3, 4]
assert expected_price_ids.all?{|expected_id| associated_price_ids.include?(expected_id)},
"Expected associated prices to be #{expected_price_ids.inspect} but they were #{associated_price_ids.sort.inspect}"
end
end

View file

@ -357,6 +357,13 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_equal comments(:more_greetings), Author.find(authors(:david).id, :include => :comments_with_order_and_conditions).comments_with_order_and_conditions.first
end
def test_eager_with_has_many_through_with_conditions_join_model_with_include
post_tags = Post.find(posts(:welcome).id).misc_tags
eager_post_tags = Post.find(1, :include => :misc_tags).misc_tags
assert_equal post_tags, eager_post_tags
end
def test_eager_with_has_many_through_join_model_with_include
author_comments = Author.find(authors(:david).id, :include => :comments_with_include).comments_with_include.to_a
assert_no_queries do

View file

@ -21,6 +21,68 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
Client.destroyed_client_ids.clear
end
def test_create_by
person = Person.create! :first_name => 'tenderlove'
post = Post.find :first
assert_equal [], person.readers
assert_nil person.readers.find_by_post_id(post.id)
reader = person.readers.create_by_post_id post.id
assert_equal 1, person.readers.count
assert_equal 1, person.readers.length
assert_equal post, person.readers.first.post
assert_equal person, person.readers.first.person
end
def test_create_by_multi
person = Person.create! :first_name => 'tenderlove'
post = Post.find :first
assert_equal [], person.readers
reader = person.readers.create_by_post_id_and_skimmer post.id, false
assert_equal 1, person.readers.count
assert_equal 1, person.readers.length
assert_equal post, person.readers.first.post
assert_equal person, person.readers.first.person
end
def test_find_or_create_by
person = Person.create! :first_name => 'tenderlove'
post = Post.find :first
assert_equal [], person.readers
assert_nil person.readers.find_by_post_id(post.id)
reader = person.readers.find_or_create_by_post_id post.id
assert_equal 1, person.readers.count
assert_equal 1, person.readers.length
assert_equal post, person.readers.first.post
assert_equal person, person.readers.first.person
end
def test_find_or_create
person = Person.create! :first_name => 'tenderlove'
post = Post.find :first
assert_equal [], person.readers
assert_nil person.readers.find(:first, :conditions => {
:post_id => post.id
})
reader = person.readers.find_or_create :post_id => post.id
assert_equal 1, person.readers.count
assert_equal 1, person.readers.length
assert_equal post, person.readers.first.post
assert_equal person, person.readers.first.person
end
def force_signal37_to_load_all_clients_of_firm
companies(:first_firm).clients_of_firm.each {|f| }
end
@ -486,7 +548,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert the_client.new_record?
end
def test_find_or_create
def test_find_or_create_updates_size
number_of_clients = companies(:first_firm).clients.size
the_client = companies(:first_firm).clients.find_or_create_by_name("Yet another client")
assert_equal number_of_clients + 1, companies(:first_firm, :reload).clients.size
@ -772,8 +834,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_destroy_all
force_signal37_to_load_all_clients_of_firm
assert !companies(:first_firm).clients_of_firm.empty?, "37signals has clients after load"
companies(:first_firm).clients_of_firm.destroy_all
clients = companies(:first_firm).clients_of_firm.to_a
assert !clients.empty?, "37signals has clients after load"
destroyed = companies(:first_firm).clients_of_firm.destroy_all
assert_equal clients.sort_by(&:id), destroyed.sort_by(&:id)
assert destroyed.all? { |client| client.frozen? }, "destroyed clients should be frozen"
assert companies(:first_firm).clients_of_firm.empty?, "37signals has no clients after destroy all"
assert companies(:first_firm).clients_of_firm(true).empty?, "37signals has no clients after destroy all and refresh"
end

View file

@ -18,6 +18,8 @@ require 'models/person'
require 'models/reader'
require 'models/parrot'
require 'models/pirate'
require 'models/ship'
require 'models/ship_part'
require 'models/treasure'
require 'models/price_estimate'
require 'models/club'
@ -29,6 +31,23 @@ class AssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :developers, :projects, :developers_projects,
:computers, :people, :readers
def test_loading_the_association_target_should_keep_child_records_marked_for_destruction
ship = Ship.create!(:name => "The good ship Dollypop")
part = ship.parts.create!(:name => "Mast")
part.mark_for_destruction
ship.parts.send(:load_target)
assert ship.parts[0].marked_for_destruction?
end
def test_loading_the_association_target_should_load_most_recent_attributes_for_child_records_marked_for_destruction
ship = Ship.create!(:name => "The good ship Dollypop")
part = ship.parts.create!(:name => "Mast")
part.mark_for_destruction
ShipPart.find(part.id).update_attribute(:name, 'Deck')
ship.parts.send(:load_target)
assert_equal 'Deck', ship.parts[0].name
end
def test_include_with_order_works
assert_nothing_raised {Account.find(:first, :order => 'id', :include => :firm)}
assert_nothing_raised {Account.find(:first, :order => :id, :include => :firm)}
@ -74,6 +93,16 @@ class AssociationsTest < ActiveRecord::TestCase
assert_queries(1) { assert_not_nil firm.clients(true).each {} }
end
end
def test_using_limitable_reflections_helper
using_limitable_reflections = lambda { |reflections| ActiveRecord::Base.send :using_limitable_reflections?, reflections }
belongs_to_reflections = [Tagging.reflect_on_association(:tag), Tagging.reflect_on_association(:super_tag)]
has_many_reflections = [Tag.reflect_on_association(:taggings), Developer.reflect_on_association(:projects)]
mixed_reflections = (belongs_to_reflections + has_many_reflections).uniq
assert using_limitable_reflections.call(belongs_to_reflections), "Belong to associations are limitable"
assert !using_limitable_reflections.call(has_many_reflections), "All has many style associations are not limitable"
assert !using_limitable_reflections.call(mixed_reflections), "No collection associations (has many style) should pass"
end
def test_storing_in_pstore
require "tmpdir"

View file

@ -1,6 +1,5 @@
require "cases/helper"
require 'models/post'
require 'models/author'
require 'models/event_author'
require 'models/topic'
require 'models/reply'
@ -588,17 +587,25 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_destroy_all
original_count = Topic.count
topics_by_mary = Topic.count(:conditions => mary = "author_name = 'Mary'")
conditions = "author_name = 'Mary'"
topics_by_mary = Topic.all(:conditions => conditions, :order => 'id')
assert ! topics_by_mary.empty?
Topic.destroy_all mary
assert_equal original_count - topics_by_mary, Topic.count
assert_difference('Topic.count', -topics_by_mary.size) do
destroyed = Topic.destroy_all(conditions).sort_by(&:id)
assert_equal topics_by_mary, destroyed
assert destroyed.all? { |topic| topic.frozen? }
end
end
def test_destroy_many
assert_equal 3, Client.count
Client.destroy([2, 3])
assert_equal 1, Client.count
clients = Client.find([2, 3], :order => 'id')
assert_difference('Client.count', -2) do
destroyed = Client.destroy([2, 3]).sort_by(&:id)
assert_equal clients, destroyed
assert destroyed.all? { |client| client.frozen? }
end
end
def test_delete_many
@ -612,55 +619,6 @@ class BasicsTest < ActiveRecord::TestCase
assert Topic.find(2).approved?
end
def test_increment_counter
Topic.increment_counter("replies_count", 1)
assert_equal 2, Topic.find(1).replies_count
Topic.increment_counter("replies_count", 1)
assert_equal 3, Topic.find(1).replies_count
end
def test_decrement_counter
Topic.decrement_counter("replies_count", 2)
assert_equal -1, Topic.find(2).replies_count
Topic.decrement_counter("replies_count", 2)
assert_equal -2, Topic.find(2).replies_count
end
def test_reset_counters
assert_equal 1, Topic.find(1).replies_count
Topic.increment_counter("replies_count", 1)
assert_equal 2, Topic.find(1).replies_count
Topic.reset_counters(1, :replies)
assert_equal 1, Topic.find(1).replies_count
end
def test_update_counter
category = categories(:general)
assert_nil category.categorizations_count
assert_equal 2, category.categorizations.count
Category.update_counters(category.id, "categorizations_count" => category.categorizations.count)
category.reload
assert_not_nil category.categorizations_count
assert_equal 2, category.categorizations_count
Category.update_counters(category.id, "categorizations_count" => category.categorizations.count)
category.reload
assert_not_nil category.categorizations_count
assert_equal 4, category.categorizations_count
category_2 = categories(:technology)
count_1, count_2 = (category.categorizations_count || 0), (category_2.categorizations_count || 0)
Category.update_counters([category.id, category_2.id], "categorizations_count" => 2)
category.reload; category_2.reload
assert_equal count_1 + 2, category.categorizations_count
assert_equal count_2 + 2, category_2.categorizations_count
end
def test_update_all
assert_equal Topic.count, Topic.update_all("content = 'bulk updated!'")
assert_equal "bulk updated!", Topic.find(1).content
@ -749,22 +707,24 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_class_name
assert_equal "Firm", ActiveRecord::Base.class_name("firms")
assert_equal "Category", ActiveRecord::Base.class_name("categories")
assert_equal "AccountHolder", ActiveRecord::Base.class_name("account_holder")
ActiveSupport::Deprecation.silence do
assert_equal "Firm", ActiveRecord::Base.class_name("firms")
assert_equal "Category", ActiveRecord::Base.class_name("categories")
assert_equal "AccountHolder", ActiveRecord::Base.class_name("account_holder")
ActiveRecord::Base.pluralize_table_names = false
assert_equal "Firms", ActiveRecord::Base.class_name( "firms" )
ActiveRecord::Base.pluralize_table_names = true
ActiveRecord::Base.pluralize_table_names = false
assert_equal "Firms", ActiveRecord::Base.class_name( "firms" )
ActiveRecord::Base.pluralize_table_names = true
ActiveRecord::Base.table_name_prefix = "test_"
assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms" )
ActiveRecord::Base.table_name_suffix = "_tests"
assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms_tests" )
ActiveRecord::Base.table_name_prefix = ""
assert_equal "Firm", ActiveRecord::Base.class_name( "firms_tests" )
ActiveRecord::Base.table_name_suffix = ""
assert_equal "Firm", ActiveRecord::Base.class_name( "firms" )
ActiveRecord::Base.table_name_prefix = "test_"
assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms" )
ActiveRecord::Base.table_name_suffix = "_tests"
assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms_tests" )
ActiveRecord::Base.table_name_prefix = ""
assert_equal "Firm", ActiveRecord::Base.class_name( "firms_tests" )
ActiveRecord::Base.table_name_suffix = ""
assert_equal "Firm", ActiveRecord::Base.class_name( "firms" )
end
end
def test_null_fields
@ -2090,7 +2050,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_inspect_instance
topic = topics(:first)
assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil>), topic.inspect
assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil, group: nil>), topic.inspect
end
def test_inspect_new_instance

View file

@ -48,6 +48,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase
def test_multi_results
rows = ActiveRecord::Base.connection.select_rows('CALL ten();')
assert_equal 10, rows[0][0].to_i, "ten() did not return 10 as expected: #{rows.inspect}"
assert @connection.active?, "Bad connection use by 'MysqlAdapter.select_rows'"
end
end

View file

@ -0,0 +1,84 @@
require 'cases/helper'
require 'models/topic'
require 'models/reply'
require 'models/category'
require 'models/categorization'
class CounterCacheTest < ActiveRecord::TestCase
fixtures :topics, :categories, :categorizations
class SpecialTopic < ::Topic
has_many :special_replies, :foreign_key => 'parent_id'
end
class SpecialReply < ::Reply
belongs_to :special_topic, :foreign_key => 'parent_id', :counter_cache => 'replies_count'
end
test "increment counter" do
topic = Topic.find(1)
assert_difference 'topic.reload.replies_count' do
Topic.increment_counter(:replies_count, topic.id)
end
end
test "decrement counter" do
topic = Topic.find(1)
assert_difference 'topic.reload.replies_count', -1 do
Topic.decrement_counter(:replies_count, topic.id)
end
end
test "reset counters" do
topic = Topic.find(1)
# throw the count off by 1
Topic.increment_counter(:replies_count, topic.id)
# check that it gets reset
assert_difference 'topic.reload.replies_count', -1 do
Topic.reset_counters(topic.id, :replies)
end
end
test "reset counters with string argument" do
topic = Topic.find(1)
Topic.increment_counter('replies_count', topic.id)
assert_difference 'topic.reload.replies_count', -1 do
Topic.reset_counters(topic.id, 'replies')
end
end
test "reset counters with modularized and camelized classnames" do
special = SpecialTopic.create!(:title => 'Special')
SpecialTopic.increment_counter(:replies_count, special.id)
assert_difference 'special.reload.replies_count', -1 do
SpecialTopic.reset_counters(special.id, :special_replies)
end
end
test "update counter with initial null value" do
category = categories(:general)
assert_equal 2, category.categorizations.count
assert_nil category.categorizations_count
Category.update_counters(category.id, :categorizations_count => category.categorizations.count)
assert_equal 2, category.reload.categorizations_count
end
test "update counter for decrement" do
topic = Topic.find(1)
assert_difference 'topic.reload.replies_count', -3 do
Topic.update_counters(topic.id, :replies_count => -3)
end
end
test "update counters of multiple records" do
t1, t2 = topics(:first, :second)
assert_difference ['t1.reload.replies_count', 't2.reload.replies_count'], 2 do
Topic.update_counters([t1.id, t2.id], :replies_count => 2)
end
end
end

View file

@ -53,7 +53,8 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_raises(ActiveRecord::StaleObjectError) { p2.destroy }
assert p1.destroy
assert_equal true, p1.frozen?
assert p1.frozen?
assert p1.destroyed?
assert_raises(ActiveRecord::RecordNotFound) { Person.find(1) }
end

View file

@ -739,6 +739,10 @@ if ActiveRecord::Base.connection.supports_migrations?
ActiveRecord::Base.connection.drop_table(:hats)
end
def test_remove_column_no_second_parameter_raises_exception
assert_raise(ArgumentError) { Person.connection.remove_column("funny") }
end
def test_change_type_of_not_null_column
assert_nothing_raised do
Topic.connection.change_column "topics", "written_on", :datetime, :null => false

View file

@ -9,6 +9,11 @@ require 'models/developer'
class NamedScopeTest < ActiveRecord::TestCase
fixtures :posts, :authors, :topics, :comments, :author_addresses
def test_named_scope_with_STI
assert_equal 5,Post.with_type_self.count
assert_equal 1,SpecialPost.with_type_self.count
end
def test_implements_enumerable
assert !Topic.find(:all).empty?
@ -265,7 +270,7 @@ class NamedScopeTest < ActiveRecord::TestCase
end
def test_rand_should_select_a_random_object_from_proxy
assert Topic.approved.random_element.is_a?(Topic)
assert Topic.approved.sample.is_a?(Topic)
end
def test_should_use_where_in_query_for_named_scope

View file

@ -175,12 +175,6 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
end
def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find Ship with ID=1234567890 for Pirate with ID=#{@pirate.id}" do
@pirate.ship_attributes = { :id => 1234567890 }
end
end
def test_should_take_a_hash_with_string_keys_and_update_the_associated_model
@pirate.reload.ship_attributes = { 'id' => @ship.id, 'name' => 'Davy Jones Gold Dagger' }
@ -330,10 +324,13 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
assert_equal 'Arr', @ship.pirate.catchphrase
end
def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find Pirate with ID=1234567890 for Ship with ID=#{@ship.id}" do
@ship.pirate_attributes = { :id => 1234567890 }
end
def test_should_associate_with_record_if_parent_record_is_not_saved
@ship.destroy
@pirate = Pirate.create(:catchphrase => 'Arr')
@ship = Ship.new(:name => 'Nights Dirty Lightning', :pirate_attributes => { :id => @pirate.id, :catchphrase => @pirate.catchphrase})
assert_equal @ship.name, 'Nights Dirty Lightning'
assert_equal @pirate, @ship.pirate
end
def test_should_take_a_hash_with_string_keys_and_update_the_associated_model
@ -437,6 +434,11 @@ module NestedAttributesOnACollectionAssociationTests
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.reload.name, @child_2.reload.name]
end
def test_should_assign_existing_children_if_parent_is_new
@pirate = Pirate.new({:catchphrase => "Don' botharr talkin' like one, savvy?"}.merge(@alternate_params))
assert_equal ['Grace OMalley', 'Privateers Greed'], [@pirate.send(@association_name)[0].name, @pirate.send(@association_name)[1].name]
end
def test_should_take_an_array_and_assign_the_attributes_to_the_associated_models
@pirate.send(association_setter, @alternate_params[association_getter].values)
@pirate.save
@ -465,6 +467,33 @@ module NestedAttributesOnACollectionAssociationTests
assert_equal 'Grace OMalley', @child_1.reload.name
end
def test_should_not_overwrite_unsaved_updates_when_loading_association
@pirate.reload
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
assert_equal 'Grace OMalley', @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.name
end
def test_should_preserve_order_when_not_overwriting_unsaved_updates
@pirate.reload
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
assert_equal @child_1.id, @pirate.send(@association_name).send(:load_target).first.id
end
def test_should_refresh_saved_records_when_not_overwriting_unsaved_updates
@pirate.reload
record = @pirate.class.reflect_on_association(@association_name).klass.new(:name => 'Grace OMalley')
@pirate.send(@association_name) << record
record.save!
@pirate.send(@association_name).last.update_attributes!(:name => 'Polly')
assert_equal 'Polly', @pirate.send(@association_name).send(:load_target).last.name
end
def test_should_not_remove_scheduled_destroys_when_loading_association
@pirate.reload
@pirate.send(association_setter, [{ :id => @child_1.id, :_destroy => '1' }])
assert @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.marked_for_destruction?
end
def test_should_take_a_hash_with_composite_id_keys_and_assign_the_attributes_to_the_associated_models
@child_1.stubs(:id).returns('ABC1X')
@child_2.stubs(:id).returns('ABC2X')
@ -479,8 +508,8 @@ module NestedAttributesOnACollectionAssociationTests
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.name, @child_2.name]
end
def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find #{@child_1.class.name} with ID=1234567890 for Pirate with ID=#{@pirate.id}" do
def test_should_not_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
assert_nothing_raised ActiveRecord::RecordNotFound do
@pirate.attributes = { association_getter => [{ :id => 1234567890 }] }
end
end
@ -781,7 +810,13 @@ class TestHasManyAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveR
@part = @ship.parts.create!(:name => "Mast")
@trinket = @part.trinkets.create!(:name => "Necklace")
end
test "if association is not loaded and association record is saved and then in memory record attributes should be saved" do
@ship.parts_attributes=[{:id => @part.id,:name =>'Deck'}]
assert_equal 1, @ship.parts.proxy_target.size
assert_equal 'Deck', @ship.parts[0].name
end
test "when grandchild changed in memory, saving parent should save grandchild" do
@trinket.name = "changed"
@ship.save
@ -810,4 +845,4 @@ class TestHasManyAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveR
ShipPart.create!(:ship => @ship, :name => "Stern")
assert_no_queries { @ship.valid? }
end
end
end

View file

@ -24,25 +24,25 @@ class ReflectionTest < ActiveRecord::TestCase
def test_read_attribute_names
assert_equal(
%w( id title author_name author_email_address bonus_time written_on last_read content approved replies_count parent_id parent_title type ).sort,
%w( id title author_name author_email_address bonus_time written_on last_read content group approved replies_count parent_id parent_title type ).sort,
@first.attribute_names
)
end
def test_columns
assert_equal 13, Topic.columns.length
assert_equal 14, Topic.columns.length
end
def test_columns_are_returned_in_the_order_they_were_declared
column_names = Topic.columns.map { |column| column.name }
assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id parent_title type), column_names
assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id parent_title type group), column_names
end
def test_content_columns
content_columns = Topic.content_columns
content_column_names = content_columns.map {|column| column.name}
assert_equal 9, content_columns.length
assert_equal %w(title author_name author_email_address written_on bonus_time last_read content approved parent_title).sort, content_column_names.sort
assert_equal 10, content_columns.length
assert_equal %w(title author_name author_email_address written_on bonus_time last_read content group approved parent_title).sort, content_column_names.sort
end
def test_column_string_type_and_limit

View file

@ -0,0 +1,16 @@
require "cases/helper"
require 'models/topic'
require 'models/minimalistic'
class StoredProcedureTest < ActiveRecord::TestCase
fixtures :topics
# Test that MySQL allows multiple results for stored procedures
if Mysql.const_defined?(:CLIENT_MULTI_RESULTS)
def test_multi_results_from_find_by_sql
topics = Topic.find_by_sql 'CALL topics();'
assert_equal 1, topics.size
assert ActiveRecord::Base.connection.active?, "Bad connection use by 'MysqlAdapter.select'"
end
end
end

View file

@ -3,10 +3,12 @@ require 'models/topic'
require 'models/reply'
require 'models/developer'
require 'models/book'
require 'models/author'
require 'models/post'
class TransactionTest < ActiveRecord::TestCase
self.use_transactional_fixtures = false
fixtures :topics, :developers
fixtures :topics, :developers, :authors, :posts
def setup
@first, @second = Topic.find(1, 2).sort_by { |t| t.id }
@ -34,6 +36,25 @@ class TransactionTest < ActiveRecord::TestCase
end
end
def test_update_attributes_should_rollback_on_failure
author = Author.find(1)
posts_count = author.posts.size
assert posts_count > 0
status = author.update_attributes(:name => nil, :post_ids => [])
assert !status
assert_equal posts_count, author.posts(true).size
end
def test_update_attributes_should_rollback_on_failure!
author = Author.find(1)
posts_count = author.posts.size
assert posts_count > 0
assert_raise(ActiveRecord::RecordInvalid) do
author.update_attributes!(:name => nil, :post_ids => [])
end
assert_equal posts_count, author.posts(true).size
end
def test_successful_with_return
class << Topic.connection
alias :real_commit_db_transaction :commit_db_transaction

View file

@ -486,20 +486,20 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
end
test ":default is only given to message if a symbol is supplied" do
store_translations(:errors => { :messages => { :"foo bar" => "You fooed: {{value}}." } })
store_translations(:errors => { :messages => { :"foo bar" => "You fooed: %{value}." } })
@reply.errors.add(:title, :inexistent, :default => "foo bar")
assert_equal "foo bar", @reply.errors[:title]
end
test "#generate_message passes the model attribute value for interpolation" do
store_translations(:errors => { :messages => { :foo => "You fooed: {{value}}." } })
store_translations(:errors => { :messages => { :foo => "You fooed: %{value}." } })
@reply.title = "da title"
assert_error_message 'You fooed: da title.', :title, :foo
end
test "#generate_message passes the human_name of the model for interpolation" do
store_translations(
:errors => { :messages => { :foo => "You fooed: {{model}}." } },
:errors => { :messages => { :foo => "You fooed: %{model}." } },
:models => { :topic => 'da topic' }
)
assert_error_message 'You fooed: da topic.', :title, :foo
@ -507,7 +507,7 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
test "#generate_message passes the human_name of the attribute for interpolation" do
store_translations(
:errors => { :messages => { :foo => "You fooed: {{attribute}}." } },
:errors => { :messages => { :foo => "You fooed: %{attribute}." } },
:attributes => { :topic => { :title => 'da topic title' } }
)
assert_error_message 'You fooed: da topic title.', :title, :foo
@ -607,17 +607,17 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
end
test "#full_message with a format present" do
store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :format => '{{attribute}}: {{message}}' } })
store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :format => '%{attribute}: %{message}' } })
assert_full_message 'Title: is kaputt', :title, :kaputt
end
test "#full_message with a type specific format present" do
store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :kaputt => '{{attribute}} {{message}}!' } })
store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :kaputt => '%{attribute} %{message}!' } })
assert_full_message 'Title is kaputt!', :title, :kaputt
end
test "#full_message with class-level specified custom message" do
store_translations(:errors => { :messages => { :broken => 'is kaputt' }, :full_messages => { :broken => '{{attribute}} {{message}}?!' } })
store_translations(:errors => { :messages => { :broken => 'is kaputt' }, :full_messages => { :broken => '%{attribute} %{message}?!' } })
assert_full_message 'Title is kaputt?!', :title, :kaputt, :message => :broken
end
@ -625,7 +625,7 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
store_translations(:my_errors => { :messages => { :kaputt => 'is kaputt' } })
assert_full_message 'Title is kaputt', :title, :kaputt, :scope => [:activerecord, :my_errors]
store_translations(:my_errors => { :full_messages => { :kaputt => '{{attribute}} {{message}}!' } })
store_translations(:my_errors => { :full_messages => { :kaputt => '%{attribute} %{message}!' } })
assert_full_message 'Title is kaputt!', :title, :kaputt, :scope => [:activerecord, :my_errors]
end
@ -763,7 +763,7 @@ class ActiveRecordDefaultErrorMessagesI18nTests < ActiveSupport::TestCase
end
test "custom message string interpolation" do
assert_equal 'custom message title', error_message(:invalid, :default => 'custom message {{value}}', :value => 'title')
assert_equal 'custom message title', error_message(:invalid, :default => 'custom message %{value}', :value => 'title')
end
end
@ -897,14 +897,14 @@ class ActiveRecordValidationsI18nFullMessagesFullStackTests < ActiveSupport::Tes
test "full_message format stored per custom error message key" do
assert_full_message("Name is broken!") do
store_translations :errors => { :messages => { :broken => 'is broken' }, :full_messages => { :broken => '{{attribute}} {{message}}!' } }
store_translations :errors => { :messages => { :broken => 'is broken' }, :full_messages => { :broken => '%{attribute} %{message}!' } }
I18nPerson.validates_presence_of :name, :message => :broken
end
end
test "full_message format stored per error type" do
assert_full_message("Name can't be blank!") do
store_translations :errors => { :full_messages => { :blank => '{{attribute}} {{message}}!' } }
store_translations :errors => { :full_messages => { :blank => '%{attribute} %{message}!' } }
I18nPerson.validates_presence_of :name
end
end
@ -912,7 +912,7 @@ class ActiveRecordValidationsI18nFullMessagesFullStackTests < ActiveSupport::Tes
test "full_message format stored as default" do
assert_full_message("Name: can't be blank") do
store_translations :errors => { :full_messages => { :format => '{{attribute}}: {{message}}' } }
store_translations :errors => { :full_messages => { :format => '%{attribute}: %{message}' } }
I18nPerson.validates_presence_of :name
end
end

View file

@ -434,6 +434,18 @@ class ValidationsTest < ActiveRecord::TestCase
end
end
def test_validate_uniqueness_with_reserved_word_as_scope
repair_validations(Reply) do
Topic.validates_uniqueness_of(:content, :scope => "group")
t1 = Topic.create "title" => "t1", "content" => "hello world2"
assert t1.valid?
t2 = Topic.create "title" => "t2", "content" => "hello world2"
assert !t2.valid?
end
end
def test_validate_uniqueness_scoped_to_defining_class
t = Topic.create("title" => "What, me worry?")
@ -678,7 +690,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_validate_format_with_formatted_message
Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be {{value}}")
Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be %{value}")
t = Topic.create(:title => 'Invalid title')
assert_equal "can't be Invalid title", t.errors.on(:title)
end
@ -741,7 +753,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_validates_inclusion_of_with_formatted_message
Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option {{value}} is not in the list" )
Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option %{value} is not in the list" )
assert Topic.create("title" => "a", "content" => "abc").valid?
@ -768,7 +780,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_validates_exclusion_of_with_formatted_message
Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option {{value}} is restricted" )
Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option %{value} is restricted" )
assert Topic.create("title" => "something", "content" => "abc")
@ -868,7 +880,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_optionally_validates_length_of_using_within_on_create
Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: {{count}}"
Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: %{count}"
t = Topic.create("title" => "thisisnotvalid", "content" => "whatever")
assert !t.save
@ -889,7 +901,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_optionally_validates_length_of_using_within_on_update
Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: {{count}}"
Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: %{count}"
t = Topic.create("title" => "vali", "content" => "whatever")
assert !t.save
@ -953,7 +965,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_validates_length_with_globally_modified_error_message
defaults = ActiveSupport::Deprecation.silence { ActiveRecord::Errors.default_error_messages }
original_message = defaults[:too_short]
defaults[:too_short] = 'tu est trops petit hombre {{count}}'
defaults[:too_short] = 'tu est trops petit hombre %{count}'
Topic.validates_length_of :title, :minimum => 10
t = Topic.create(:title => 'too short')
@ -1004,7 +1016,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_validates_length_of_custom_errors_for_minimum_with_message
Topic.validates_length_of( :title, :minimum=>5, :message=>"boo {{count}}" )
Topic.validates_length_of( :title, :minimum=>5, :message=>"boo %{count}" )
t = Topic.create("title" => "uhoh", "content" => "whatever")
assert !t.valid?
assert t.errors.on(:title)
@ -1012,7 +1024,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_validates_length_of_custom_errors_for_minimum_with_too_short
Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo {{count}}" )
Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo %{count}" )
t = Topic.create("title" => "uhoh", "content" => "whatever")
assert !t.valid?
assert t.errors.on(:title)
@ -1020,7 +1032,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_validates_length_of_custom_errors_for_maximum_with_message
Topic.validates_length_of( :title, :maximum=>5, :message=>"boo {{count}}" )
Topic.validates_length_of( :title, :maximum=>5, :message=>"boo %{count}" )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors.on(:title)
@ -1028,7 +1040,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_validates_length_of_custom_errors_for_in
Topic.validates_length_of(:title, :in => 10..20, :message => "hoo {{count}}")
Topic.validates_length_of(:title, :in => 10..20, :message => "hoo %{count}")
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors.on(:title)
@ -1041,7 +1053,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_validates_length_of_custom_errors_for_maximum_with_too_long
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}" )
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}" )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors.on(:title)
@ -1049,7 +1061,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_validates_length_of_custom_errors_for_is_with_message
Topic.validates_length_of( :title, :is=>5, :message=>"boo {{count}}" )
Topic.validates_length_of( :title, :is=>5, :message=>"boo %{count}" )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors.on(:title)
@ -1057,7 +1069,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_validates_length_of_custom_errors_for_is_with_wrong_length
Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo {{count}}" )
Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo %{count}" )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors.on(:title)
@ -1123,7 +1135,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_optionally_validates_length_of_using_within_on_create_utf8
with_kcode('UTF8') do
Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: {{count}}"
Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: %{count}"
t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever")
assert !t.save
@ -1146,7 +1158,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_optionally_validates_length_of_using_within_on_update_utf8
with_kcode('UTF8') do
Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: {{count}}"
Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: %{count}"
t = Topic.create("title" => "一二三4", "content" => "whatever")
assert !t.save
@ -1181,7 +1193,7 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_validates_length_of_with_block
Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least {{count}} words.",
Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least %{count} words.",
:tokenizer => lambda {|str| str.scan(/\w+/) }
t = Topic.create!(:content => "this content should be long enough")
assert t.valid?
@ -1356,7 +1368,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_if_validation_using_method_true
# When the method returns true
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true )
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => :condition_is_true )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors.on(:title)
@ -1365,7 +1377,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_unless_validation_using_method_true
# When the method returns true
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true )
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => :condition_is_true )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert !t.errors.on(:title)
@ -1373,7 +1385,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_if_validation_using_method_false
# When the method returns false
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true_but_its_not )
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => :condition_is_true_but_its_not )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert !t.errors.on(:title)
@ -1381,7 +1393,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_unless_validation_using_method_false
# When the method returns false
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true_but_its_not )
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => :condition_is_true_but_its_not )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors.on(:title)
@ -1390,7 +1402,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_if_validation_using_string_true
# When the evaluated string returns true
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "a = 1; a == 1" )
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => "a = 1; a == 1" )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors.on(:title)
@ -1399,7 +1411,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_unless_validation_using_string_true
# When the evaluated string returns true
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "a = 1; a == 1" )
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => "a = 1; a == 1" )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert !t.errors.on(:title)
@ -1407,7 +1419,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_if_validation_using_string_false
# When the evaluated string returns false
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "false")
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => "false")
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert !t.errors.on(:title)
@ -1415,7 +1427,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_unless_validation_using_string_false
# When the evaluated string returns false
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "false")
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => "false")
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors.on(:title)
@ -1424,7 +1436,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_if_validation_using_block_true
# When the block returns true
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
:if => Proc.new { |r| r.content.size > 4 } )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
@ -1434,7 +1446,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_unless_validation_using_block_true
# When the block returns true
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
:unless => Proc.new { |r| r.content.size > 4 } )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
@ -1443,7 +1455,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_if_validation_using_block_false
# When the block returns false
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
:if => Proc.new { |r| r.title != "uhohuhoh"} )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
@ -1452,7 +1464,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_unless_validation_using_block_false
# When the block returns false
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
:unless => Proc.new { |r| r.title != "uhohuhoh"} )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
@ -1634,13 +1646,13 @@ class ValidatesNumericalityTest < ActiveRecord::TestCase
end
def test_validates_numericality_with_numeric_message
Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than {{count}}"
Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than %{count}"
topic = Topic.new("title" => "numeric test", "approved" => 10)
assert !topic.valid?
assert_equal "smaller than 4", topic.errors.on(:approved)
Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than {{count}}"
Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than %{count}"
topic = Topic.new("title" => "numeric test", "approved" => 1)
assert !topic.valid?

View file

@ -0,0 +1,19 @@
awesome_tee_design:
id: 1
designable_id: 1
designable_type: Tee
sucky_tee_design:
id: 2
designable_id: 2
designable_type: Tee
awesome_hat_design:
id: 3
designable_id: 1
designable_type: Tie
sucky_hat_design:
id: 4
designable_id: 2
designable_type: Tie

View file

@ -0,0 +1,19 @@
awesome_tee_price:
id: 1
sellable_id: 1
sellable_type: Tee
sucky_tee_price:
id: 2
sellable_id: 2
sellable_type: Tee
awesome_hat_price:
id: 3
sellable_id: 1
sellable_type: Tie
sucky_hat_price:
id: 4
sellable_id: 2
sellable_type: Tie

View file

@ -0,0 +1,4 @@
awesome_tee:
id: 1
sucky_tee:
id: 2

View file

@ -0,0 +1,4 @@
awesome_tie:
id: 1
sucky_tie:
id: 2

View file

@ -106,6 +106,8 @@ class Author < ActiveRecord::Base
"#{id}-#{name}"
end
validates_presence_of :name
private
def log_before_adding(object)
@post_log << "before_adding#{object.id || '<new>'}"

View file

@ -1,3 +1,6 @@
require 'models/author'
require 'models/event'
class EventAuthor < ActiveRecord::Base
belongs_to :author
belongs_to :event

View file

@ -1,7 +1,7 @@
class Pirate < ActiveRecord::Base
belongs_to :parrot, :validate => true
belongs_to :non_validated_parrot, :class_name => 'Parrot'
has_and_belongs_to_many :parrots, :validate => true
has_and_belongs_to_many :parrots, :validate => true, :order => 'parrots.id ASC'
has_and_belongs_to_many :non_validated_parrots, :class_name => 'Parrot'
has_and_belongs_to_many :parrots_with_method_callbacks, :class_name => "Parrot",
:before_add => :log_before_add,
@ -21,7 +21,7 @@ class Pirate < ActiveRecord::Base
has_one :ship
has_one :update_only_ship, :class_name => 'Ship'
has_one :non_validated_ship, :class_name => 'Ship'
has_many :birds
has_many :birds, :order => 'birds.id ASC'
has_many :birds_with_method_callbacks, :class_name => "Bird",
:before_add => :log_before_add,
:after_add => :log_after_add,

View file

@ -0,0 +1,3 @@
class PolymorphicDesign < ActiveRecord::Base
belongs_to :designable, :polymorphic => true
end

View file

@ -0,0 +1,3 @@
class PolymorphicPrice < ActiveRecord::Base
belongs_to :sellable, :polymorphic => true
end

View file

@ -1,4 +1,5 @@
class Post < ActiveRecord::Base
named_scope :with_type_self, lambda{{:conditions => ["type=?", self.name]}}
named_scope :containing_the_letter_a, :conditions => "body LIKE '%a%'"
named_scope :ranked_by_comments, :order => "comments_count DESC"
named_scope :limit, lambda {|limit| {:limit => limit} }
@ -52,6 +53,7 @@ class Post < ActiveRecord::Base
end
end
has_many :misc_tags, :through => :taggings, :source => :tag, :conditions => "tags.name = 'Misc'"
has_many :funky_tags, :through => :taggings, :source => :tag
has_many :super_tags, :through => :taggings
has_one :tagging, :as => :taggable

View file

@ -0,0 +1,4 @@
class Tee < ActiveRecord::Base
has_one :polymorphic_design, :as => :designable
has_one :polymorphic_price, :as => :sellable
end

View file

@ -0,0 +1,4 @@
class Tie < ActiveRecord::Base
has_one :polymorphic_design, :as => :designable
has_one :polymorphic_price, :as => :sellable
end

View file

@ -19,6 +19,13 @@ CREATE PROCEDURE ten() SQL SECURITY INVOKER
BEGIN
select 10;
END
SQL
ActiveRecord::Base.connection.execute <<-SQL
CREATE PROCEDURE topics() SQL SECURITY INVOKER
BEGIN
select * from topics limit 1;
END
SQL
end

View file

@ -367,6 +367,16 @@ ActiveRecord::Schema.define do
t.column :updated_on, :datetime
end
create_table :polymorphic_designs, :force => true do |t|
t.integer :designable_id
t.string :designable_type
end
create_table :polymorphic_prices, :force => true do |t|
t.integer :sellable_id
t.string :sellable_type
end
create_table :posts, :force => true do |t|
t.integer :author_id
t.string :title, :null => false
@ -390,6 +400,7 @@ ActiveRecord::Schema.define do
create_table :readers, :force => true do |t|
t.integer :post_id, :null => false
t.integer :person_id, :null => false
t.boolean :skimmer, :default => false
end
create_table :shape_expressions, :force => true do |t|
@ -435,6 +446,8 @@ ActiveRecord::Schema.define do
t.datetime :ending
end
create_table :ties, :force => true
create_table :topics, :force => true do |t|
t.string :title
t.string :author_name
@ -448,6 +461,7 @@ ActiveRecord::Schema.define do
t.integer :parent_id
t.string :parent_title
t.string :type
t.string :group
end
create_table :taggings, :force => true do |t|
@ -462,6 +476,8 @@ ActiveRecord::Schema.define do
t.column :taggings_count, :integer, :default => 0
end
create_table :tees, :force => true
create_table :toys, :primary_key => :toy_id ,:force => true do |t|
t.string :name
t.integer :pet_id, :integer