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

@ -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