aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionmailer/lib/action_mailer/railtie.rb4
-rw-r--r--actionpack/lib/action_controller/caching/pages.rb20
-rw-r--r--actionpack/lib/action_controller/railtie.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb2
-rw-r--r--actionpack/lib/action_view/lookup_context.rb2
-rw-r--r--actionpack/lib/action_view/path_set.rb6
-rw-r--r--actionpack/lib/action_view/template.rb2
-rw-r--r--actionpack/lib/action_view/template/resolver.rb2
-rw-r--r--actionpack/test/controller/caching_test.rb16
-rw-r--r--actionpack/test/dispatch/mount_test.rb18
-rw-r--r--actionpack/test/template/render_test.rb5
-rw-r--r--activemodel/lib/active_model/serializers/xml.rb1
-rw-r--r--activerecord/CHANGELOG3
-rw-r--r--activerecord/lib/active_record/associations.rb41
-rw-r--r--activerecord/lib/active_record/associations/class_methods/join_dependency.rb15
-rw-r--r--activerecord/lib/active_record/associations/class_methods/join_dependency/join_association.rb43
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb3
-rw-r--r--activerecord/lib/active_record/base.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb13
-rw-r--r--activerecord/lib/active_record/migration.rb59
-rw-r--r--activerecord/lib/active_record/observer.rb40
-rw-r--r--activerecord/lib/active_record/railties/databases.rake64
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb45
-rw-r--r--activerecord/lib/active_record/schema.rb6
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb37
-rw-r--r--activerecord/test/cases/associations/eager_test.rb5
-rw-r--r--activerecord/test/cases/base_test.rb16
-rw-r--r--activerecord/test/cases/lifecycle_test.rb16
-rw-r--r--activerecord/test/cases/migration_test.rb14
-rw-r--r--activerecord/test/cases/xml_serialization_test.rb21
-rw-r--r--railties/lib/rails/application.rb4
-rw-r--r--railties/lib/rails/application/configuration.rb19
-rw-r--r--railties/lib/rails/application/railties.rb8
-rw-r--r--railties/lib/rails/commands.rb3
-rw-r--r--railties/lib/rails/engine.rb12
-rw-r--r--railties/lib/rails/engine/railties.rb10
-rwxr-xr-xrailties/lib/rails/generators/rails/plugin_new/templates/Rakefile8
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb2
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb5
-rw-r--r--railties/test/application/configuration_test.rb5
-rw-r--r--railties/test/generators/plugin_new_generator_test.rb2
-rw-r--r--railties/test/railties/engine_test.rb19
43 files changed, 421 insertions, 207 deletions
diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb
index d67a5b6521..4ec478067f 100644
--- a/actionmailer/lib/action_mailer/railtie.rb
+++ b/actionmailer/lib/action_mailer/railtie.rb
@@ -19,8 +19,8 @@ module ActionMailer
options.stylesheets_dir ||= paths["public/stylesheets"].first
# make sure readers methods get compiled
- options.asset_path ||= nil
- options.asset_host ||= nil
+ options.asset_path ||= app.config.asset_path
+ options.asset_host ||= app.config.asset_host
ActiveSupport.on_load(:action_mailer) do
include AbstractController::UrlFor
diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb
index 104157d0b1..3e57d2c236 100644
--- a/actionpack/lib/action_controller/caching/pages.rb
+++ b/actionpack/lib/action_controller/caching/pages.rb
@@ -70,9 +70,9 @@ module ActionController #:nodoc:
# Manually cache the +content+ in the key determined by +path+. Example:
# cache_page "I'm the cached content", "/lists/show"
- def cache_page(content, path)
+ def cache_page(content, path, extension = nil)
return unless perform_caching
- path = page_cache_path(path)
+ path = page_cache_path(path, extension)
instrument_page_cache :write_page, path do
FileUtils.makedirs(File.dirname(path))
@@ -97,14 +97,16 @@ module ActionController #:nodoc:
end
private
- def page_cache_file(path)
+ def page_cache_file(path, extension)
name = (path.empty? || path == "/") ? "/index" : URI.parser.unescape(path.chomp('/'))
- name << page_cache_extension unless (name.split('/').last || name).include? '.'
+ unless (name.split('/').last || name).include? '.'
+ name << (extension || self.page_cache_extension)
+ end
return name
end
- def page_cache_path(path)
- page_cache_directory + page_cache_file(path)
+ def page_cache_path(path, extension = nil)
+ page_cache_directory + page_cache_file(path, extension)
end
def instrument_page_cache(name, path)
@@ -145,7 +147,11 @@ module ActionController #:nodoc:
request.path
end
- self.class.cache_page(content || response.body, path)
+ if (type = Mime::LOOKUP[self.content_type]) && (type_symbol = type.symbol).present?
+ extension = ".#{type_symbol}"
+ end
+
+ self.class.cache_page(content || response.body, path, extension)
end
end
diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb
index c5a661f2b0..f0c29825ba 100644
--- a/actionpack/lib/action_controller/railtie.rb
+++ b/actionpack/lib/action_controller/railtie.rb
@@ -27,8 +27,8 @@ module ActionController
options.page_cache_directory ||= paths["public"].first
# make sure readers methods get compiled
- options.asset_path ||= nil
- options.asset_host ||= nil
+ options.asset_path ||= app.config.asset_path
+ options.asset_host ||= app.config.asset_host
ActiveSupport.on_load(:action_controller) do
include app.routes.mounted_helpers
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 494cdbf308..430fcdbe07 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -331,7 +331,7 @@ module ActionDispatch
end
def define_generate_prefix(app, name)
- return unless app.respond_to?(:routes)
+ return unless app.respond_to?(:routes) && app.routes.respond_to?(:define_mounted_helper)
_route = @set.named_routes.routes[name.to_sym]
_routes = @set
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index 27f94a73a6..d524c68450 100644
--- a/actionpack/lib/action_view/lookup_context.rb
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -109,7 +109,7 @@ module ActionView
def args_for_lookup(name, prefix, partial, keys) #:nodoc:
name, prefix = normalize_name(name, prefix)
- [name, prefix, partial || false, @details, keys, details_key]
+ [name, prefix, partial || false, @details, details_key, keys]
end
# Support legacy foo.erb names even though we now ignore .erb
diff --git a/actionpack/lib/action_view/path_set.rb b/actionpack/lib/action_view/path_set.rb
index dc26d75ff3..fa35120a0d 100644
--- a/actionpack/lib/action_view/path_set.rb
+++ b/actionpack/lib/action_view/path_set.rb
@@ -10,10 +10,8 @@ module ActionView #:nodoc:
METHOD
end
- def find(path, prefix = nil, partial = false, details = {}, keys = [], key = nil)
- template = find_all(path, prefix, partial, details, keys, key).first
- raise MissingTemplate.new(self, "#{prefix}/#{path}", details, partial) unless template
- template
+ def find(*args)
+ find_all(*args).first || raise(MissingTemplate.new(self, "#{args[1]}/#{args[0]}", args[3], args[2]))
end
def find_all(*args)
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 831a19654e..0d8373ef14 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -275,7 +275,7 @@ module ActionView
end
arity = @handler.respond_to?(:arity) ? @handler.arity : @handler.method(:call).arity
- code = arity == 1 ? @handler.call(self) : @handler.call(self, view)
+ code = arity.abs == 1 ? @handler.call(self) : @handler.call(self, view)
# Make sure that the resulting String to be evalled is in the
# encoding of the code
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index 9f15661669..a17454da28 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -15,7 +15,7 @@ module ActionView
end
# Normalizes the arguments and passes it on to find_template.
- def find_all(name, prefix=nil, partial=false, details={}, locals=[], key=nil)
+ def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[])
cached(key, [name, prefix, partial], details, locals) do
find_templates(name, prefix, partial, details)
end
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 914ae56032..c7b54eb0ba 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -16,6 +16,7 @@ end
class PageCachingTestController < CachingController
caches_page :ok, :no_content, :if => Proc.new { |c| !c.request.format.json? }
caches_page :found, :not_found
+ caches_page :about_me
def ok
@@ -47,6 +48,14 @@ class PageCachingTestController < CachingController
def trailing_slash
render :text => "Sneak attack"
end
+
+ def about_me
+ respond_to do |format|
+ format.html {render :text => 'I am html'}
+ format.xml {render :text => 'I am xml'}
+ end
+ end
+
end
class PageCachingTest < ActionController::TestCase
@@ -111,6 +120,13 @@ class PageCachingTest < ActionController::TestCase
assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html")
end
+ def test_should_obey_http_accept_attribute
+ @request.env['HTTP_ACCEPT'] = 'text/xml'
+ get :about_me
+ assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/about_me.xml")
+ assert_equal 'I am xml', @response.body
+ end
+
def test_should_cache_with_trailing_slash_on_url
@controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash/'
assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html")
diff --git a/actionpack/test/dispatch/mount_test.rb b/actionpack/test/dispatch/mount_test.rb
index 0f584af31e..1a032539b9 100644
--- a/actionpack/test/dispatch/mount_test.rb
+++ b/actionpack/test/dispatch/mount_test.rb
@@ -2,6 +2,17 @@ require 'abstract_unit'
class TestRoutingMount < ActionDispatch::IntegrationTest
Router = ActionDispatch::Routing::RouteSet.new
+
+ class FakeEngine
+ def self.routes
+ Object.new
+ end
+
+ def self.call(env)
+ [200, {"Content-Type" => "text/html"}, ["OK"]]
+ end
+ end
+
Router.draw do
SprocketsApp = lambda { |env|
[200, {"Content-Type" => "text/html"}, ["#{env["SCRIPT_NAME"]} -- #{env["PATH_INFO"]}"]]
@@ -10,6 +21,8 @@ class TestRoutingMount < ActionDispatch::IntegrationTest
mount SprocketsApp, :at => "/sprockets"
mount SprocketsApp => "/shorthand"
+ mount FakeEngine, :at => "/fakeengine"
+
scope "/its_a" do
mount SprocketsApp, :at => "/sprocket"
end
@@ -33,4 +46,9 @@ class TestRoutingMount < ActionDispatch::IntegrationTest
get "/shorthand/omg"
assert_equal "/shorthand -- /omg", response.body
end
+
+ def test_with_fake_engine_does_not_call_invalid_method
+ get "/fakeengine"
+ assert_equal "OK", response.body
+ end
end \ No newline at end of file
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index 8087429d62..38bedd2e4e 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -225,6 +225,11 @@ module RenderTestCases
%'"#{template.class} #{view.class}"'
end
+ def test_render_inline_with_render_from_to_proc
+ ActionView::Template.register_template_handler :ruby_handler, :source.to_proc
+ assert_equal '3', @view.render(:inline => "(1 + 2).to_s", :type => :ruby_handler)
+ end
+
def test_render_inline_with_template_handler_with_view
ActionView::Template.register_template_handler :with_view, WithViewHandler
assert_equal 'ActionView::Template ActionView::Base', @view.render(:inline => "Hello, World!", :type => :with_view)
diff --git a/activemodel/lib/active_model/serializers/xml.rb b/activemodel/lib/active_model/serializers/xml.rb
index 26a134568c..b897baa614 100644
--- a/activemodel/lib/active_model/serializers/xml.rb
+++ b/activemodel/lib/active_model/serializers/xml.rb
@@ -17,6 +17,7 @@ module ActiveModel
def initialize(name, serializable, raw_value=nil)
@name, @serializable = name, serializable
+ raw_value = raw_value.in_time_zone if raw_value.respond_to?(:in_time_zone)
@value = raw_value || @serializable.send(name)
@type = compute_type
end
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index f46db909ba..9c2e311c75 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,8 @@
*Rails 3.1.0 (unreleased)*
+* Setting the id of a belongs_to object will update the reference to the
+object. [#2989 state:resolved]
+
* ActiveRecord::Base#dup and ActiveRecord::Base#clone semantics have changed
to closer match normal Ruby dup and clone semantics.
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 0d9171d876..cdc8f25119 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1223,12 +1223,14 @@ module ActiveRecord
if reflection.options[:polymorphic]
association_accessor_methods(reflection, BelongsToPolymorphicAssociation)
+ association_foreign_type_setter_method(reflection)
else
association_accessor_methods(reflection, BelongsToAssociation)
association_constructor_method(:build, reflection, BelongsToAssociation)
association_constructor_method(:create, reflection, BelongsToAssociation)
end
+ association_foreign_key_setter_method(reflection)
add_counter_cache_callbacks(reflection) if options[:counter_cache]
add_touch_callbacks(reflection, options[:touch]) if options[:touch]
@@ -1555,6 +1557,45 @@ module ActiveRecord
end
end
+ def association_foreign_key_setter_method(reflection)
+ setters = reflect_on_all_associations(:belongs_to).map do |belongs_to_reflection|
+ if belongs_to_reflection.primary_key_name == reflection.primary_key_name
+ "association_instance_set(:#{belongs_to_reflection.name}, nil);"
+ end
+ end.compact.join
+
+ if method_defined?(:"#{reflection.primary_key_name}=")
+ undef_method :"#{reflection.primary_key_name}="
+ end
+
+ class_eval <<-FILE, __FILE__, __LINE__ + 1
+ def #{reflection.primary_key_name}=(new_id)
+ write_attribute :#{reflection.primary_key_name}, new_id
+ if #{reflection.primary_key_name}_changed?
+ #{ setters }
+ end
+ end
+ FILE
+ end
+
+ def association_foreign_type_setter_method(reflection)
+ setters = reflect_on_all_associations(:belongs_to).map do |belongs_to_reflection|
+ if belongs_to_reflection.options[:foreign_type] == reflection.options[:foreign_type]
+ "association_instance_set(:#{belongs_to_reflection.name}, nil);"
+ end
+ end.compact.join
+
+ field = reflection.options[:foreign_type]
+ class_eval <<-FILE, __FILE__, __LINE__ + 1
+ def #{field}=(new_id)
+ write_attribute :#{field}, new_id
+ if #{field}_changed?
+ #{ setters }
+ end
+ end
+ FILE
+ end
+
def add_counter_cache_callbacks(reflection)
cache_column = reflection.counter_cache_column
diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb
index 13576e1aec..b6d85a7c7d 100644
--- a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb
@@ -15,7 +15,7 @@ module ActiveRecord
@associations = {}
@reflections = []
@table_aliases = Hash.new do |h,name|
- h[name] = count_aliases_from_table_joins(name)
+ h[name] = count_aliases_from_table_joins(name.downcase)
end
@table_aliases[base.table_name] = 1
build(associations)
@@ -49,13 +49,16 @@ module ActiveRecord
def count_aliases_from_table_joins(name)
return 0 if !@table_joins || Arel::Table === @table_joins
+ # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
+ quoted_name = active_record.connection.quote_table_name(name).downcase
+
@table_joins.grep(Arel::Nodes::Join).map { |join|
right = join.right
case right
when Arel::Table
right.name.downcase == name ? 1 : 0
when String
- count_aliases_from_string(right.downcase, name)
+ count_aliases_from_string(right.downcase, quoted_name)
else
0
end
@@ -63,12 +66,10 @@ module ActiveRecord
end
def count_aliases_from_string(join_sql, name)
- # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
- quoted_name = active_record.connection.quote_table_name(name.downcase).downcase
# Table names
- join_sql.scan(/join(?:\s+\w+)?\s+#{quoted_name}\son/).size +
+ join_sql.scan(/join(?:\s+\w+)?\s+#{name}\son/).size +
# Table aliases
- join_sql.scan(/join(?:\s+\w+)?\s+\S+\s+#{quoted_name}\son/).size
+ join_sql.scan(/join(?:\s+\w+)?\s+\S+\s+#{name}\son/).size
end
def instantiate(rows)
@@ -151,7 +152,7 @@ module ActiveRecord
build(association, parent, join_type)
end
when Hash
- associations.keys.sort{|a,b|a.to_s<=>b.to_s}.each do |name|
+ associations.keys.sort_by { |a| a.to_s }.each do |name|
join_association = build(name, parent, join_type)
build(associations[name], join_association, join_type)
end
diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency/join_association.rb
index 25511a092f..98536d23bc 100644
--- a/activerecord/lib/active_record/associations/class_methods/join_dependency/join_association.rb
+++ b/activerecord/lib/active_record/associations/class_methods/join_dependency/join_association.rb
@@ -42,6 +42,9 @@ module ActiveRecord
# depends on the state of the join dependency, but we want it to work the same way
# every time.
allocate_aliases
+ @table = Arel::Table.new(
+ table_name, :as => aliased_table_name, :engine => arel_engine
+ )
end
def ==(other)
@@ -65,12 +68,7 @@ module ActiveRecord
joining_relation.joins(self)
end
- def table
- @table ||= Arel::Table.new(
- table_name, :as => aliased_table_name, :engine => arel_engine
- )
- end
-
+ attr_reader :table
# More semantic name given we are talking about associations
alias_method :target_table, :table
@@ -117,20 +115,19 @@ module ActiveRecord
active_record.send(:sanitize_sql, condition, table_name)
end
- def join_target_table(relation, *conditions)
- relation = relation.join(target_table, join_type)
+ def join_target_table(relation, condition)
+ conditions = [condition]
# If the target table is an STI model then we must be sure to only include records of
# its type and its sub-types.
unless active_record.descends_from_active_record?
- sti_column = target_table[active_record.inheritance_column]
-
+ sti_column = target_table[active_record.inheritance_column]
+ subclasses = active_record.descendants
sti_condition = sti_column.eq(active_record.sti_name)
- active_record.descendants.each do |subclass|
- sti_condition = sti_condition.or(sti_column.eq(subclass.sti_name))
- end
- conditions << sti_condition
+ conditions << subclasses.inject(sti_condition) { |attr,subclass|
+ attr.or(sti_column.eq(subclass.sti_name))
+ }
end
# If the reflection has conditions, add them
@@ -138,14 +135,15 @@ module ActiveRecord
conditions << process_conditions(options[:conditions], aliased_table_name)
end
- relation = relation.on(*conditions)
+ join = relation.join(target_table, join_type)
+
+ join.on(*conditions)
end
def join_has_and_belongs_to_many_to(relation)
join_table = Arel::Table.new(
- options[:join_table], :engine => arel_engine,
- :as => @aliased_join_table_name
- )
+ options[:join_table]
+ ).alias(@aliased_join_table_name)
fk = options[:foreign_key] || reflection.active_record.to_s.foreign_key
klass_fk = options[:association_foreign_key] || reflection.klass.to_s.foreign_key
@@ -183,9 +181,8 @@ module ActiveRecord
def join_has_many_through_to(relation)
join_table = Arel::Table.new(
- through_reflection.klass.table_name, :engine => arel_engine,
- :as => @aliased_join_table_name
- )
+ through_reflection.klass.table_name
+ ).alias @aliased_join_table_name
jt_conditions = []
jt_foreign_key = first_key = second_key = nil
@@ -250,9 +247,9 @@ module ActiveRecord
join_target_table(
relation,
target_table["#{reflection.options[:as]}_id"].
- eq(parent_table[parent.primary_key]),
+ eq(parent_table[parent.primary_key]).and(
target_table["#{reflection.options[:as]}_type"].
- eq(parent.active_record.base_class.name)
+ eq(parent.active_record.base_class.name))
)
end
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index ad5a3e7562..506f6e878f 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -85,7 +85,8 @@ module ActiveRecord
def _read_attribute(attr_name)
attr_name = attr_name.to_s
attr_name = self.class.primary_key if attr_name == 'id'
- if value = @attributes[attr_name]
+ value = @attributes[attr_name]
+ unless value.nil?
if column = column_for_attribute(attr_name)
if unserializable_attribute?(attr_name, column)
unserialize_attribute(attr_name)
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index b55aaddbd7..7b9ce21ceb 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -1680,7 +1680,7 @@ MSG
if include_readonly_attributes || (!include_readonly_attributes && !self.class.readonly_attributes.include?(name))
value = read_attribute(name)
- if value && self.class.serialized_attributes.key?(name)
+ if !value.nil? && self.class.serialized_attributes.key?(name)
value = YAML.dump value
end
attrs[self.class.arel_table[name]] = value
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 4e770c37da..d4aefada22 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -442,12 +442,14 @@ module ActiveRecord
end
end
- def assume_migrated_upto_version(version, migrations_path = ActiveRecord::Migrator.migrations_path)
+ def assume_migrated_upto_version(version, migrations_paths = ActiveRecord::Migrator.migrations_paths)
+ migrations_paths = Array.wrap(migrations_paths)
version = version.to_i
sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
migrated = select_values("SELECT version FROM #{sm_table}").map { |v| v.to_i }
- versions = Dir["#{migrations_path}/[0-9]*_*.rb"].map do |filename|
+ paths = migrations_paths.map {|p| "#{p}/[0-9]*_*.rb" }
+ versions = Dir[*paths].map do |filename|
filename.split('/').last.split('_').first.to_i
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index ccc5085b84..a4b1aa7154 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -404,10 +404,7 @@ module ActiveRecord
# REFERENTIAL INTEGRITY ====================================
def supports_disable_referential_integrity?() #:nodoc:
- version = query("SHOW server_version")[0][0].split('.')
- version[0].to_i >= 8 && version[1].to_i >= 1
- rescue
- return false
+ postgresql_version >= 80100
end
def disable_referential_integrity #:nodoc:
@@ -956,8 +953,12 @@ module ActiveRecord
else
# Mimic PGconn.server_version behavior
begin
- query('SELECT version()')[0][0] =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
- ($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
+ if query('SELECT version()')[0][0] =~ /PostgreSQL ([0-9.]+)/
+ major, minor, tiny = $1.split(".")
+ (major.to_i * 10000) + (minor.to_i * 100) + tiny.to_i
+ else
+ 0
+ end
rescue
0
end
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 4dc67a0905..640111096d 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -1,3 +1,5 @@
+require "active_support/core_ext/array/wrap"
+
module ActiveRecord
# Exception that can be raised to stop migrations from going backwards.
class IrreversibleMigration < ActiveRecordError
@@ -511,39 +513,40 @@ module ActiveRecord
class Migrator#:nodoc:
class << self
- attr_writer :migrations_path
+ attr_writer :migrations_paths
+ alias :migrations_path= :migrations_paths=
- def migrate(migrations_path, target_version = nil)
+ def migrate(migrations_paths, target_version = nil)
case
when target_version.nil?
- up(migrations_path, target_version)
+ up(migrations_paths, target_version)
when current_version == 0 && target_version == 0
[]
when current_version > target_version
- down(migrations_path, target_version)
+ down(migrations_paths, target_version)
else
- up(migrations_path, target_version)
+ up(migrations_paths, target_version)
end
end
- def rollback(migrations_path, steps=1)
- move(:down, migrations_path, steps)
+ def rollback(migrations_paths, steps=1)
+ move(:down, migrations_paths, steps)
end
- def forward(migrations_path, steps=1)
- move(:up, migrations_path, steps)
+ def forward(migrations_paths, steps=1)
+ move(:up, migrations_paths, steps)
end
- def up(migrations_path, target_version = nil)
- self.new(:up, migrations_path, target_version).migrate
+ def up(migrations_paths, target_version = nil)
+ self.new(:up, migrations_paths, target_version).migrate
end
- def down(migrations_path, target_version = nil)
- self.new(:down, migrations_path, target_version).migrate
+ def down(migrations_paths, target_version = nil)
+ self.new(:down, migrations_paths, target_version).migrate
end
- def run(direction, migrations_path, target_version)
- self.new(direction, migrations_path, target_version).run
+ def run(direction, migrations_paths, target_version)
+ self.new(direction, migrations_paths, target_version).run
end
def schema_migrations_table_name
@@ -569,12 +572,20 @@ module ActiveRecord
name.table_name rescue "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}"
end
+ def migrations_paths
+ @migrations_paths ||= ['db/migrate']
+ # just to not break things if someone uses: migration_path = some_string
+ Array.wrap(@migrations_paths)
+ end
+
def migrations_path
- @migrations_path ||= 'db/migrate'
+ migrations_paths.first
end
- def migrations(path)
- files = Dir["#{path}/[0-9]*_*.rb"]
+ def migrations(paths)
+ paths = Array.wrap(paths)
+
+ files = Dir[*paths.map { |p| "#{p}/[0-9]*_*.rb" }]
seen = Hash.new false
@@ -598,22 +609,22 @@ module ActiveRecord
private
- def move(direction, migrations_path, steps)
- migrator = self.new(direction, migrations_path)
+ def move(direction, migrations_paths, steps)
+ migrator = self.new(direction, migrations_paths)
start_index = migrator.migrations.index(migrator.current_migration)
if start_index
finish = migrator.migrations[start_index + steps]
version = finish ? finish.version : 0
- send(direction, migrations_path, version)
+ send(direction, migrations_paths, version)
end
end
end
- def initialize(direction, migrations_path, target_version = nil)
+ def initialize(direction, migrations_paths, target_version = nil)
raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
Base.connection.initialize_schema_migrations_table
- @direction, @migrations_path, @target_version = direction, migrations_path, target_version
+ @direction, @migrations_paths, @target_version = direction, migrations_paths, target_version
end
def current_version
@@ -679,7 +690,7 @@ module ActiveRecord
def migrations
@migrations ||= begin
- migrations = self.class.migrations(@migrations_path)
+ migrations = self.class.migrations(@migrations_paths)
down? ? migrations.reverse : migrations
end
end
diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb
index 022cf109af..8b011ad9af 100644
--- a/activerecord/lib/active_record/observer.rb
+++ b/activerecord/lib/active_record/observer.rb
@@ -89,51 +89,25 @@ module ActiveRecord
# singletons and that call instantiates and registers them.
#
class Observer < ActiveModel::Observer
- class_attribute :observed_methods
- self.observed_methods = [].freeze
-
- def initialize
- super
- observed_descendants.each { |klass| add_observer!(klass) }
- end
-
- def self.method_added(method)
- method = method.to_sym
-
- if ActiveRecord::Callbacks::CALLBACKS.include?(method)
- self.observed_methods += [method]
- self.observed_methods.freeze
- end
- end
protected
- def observed_descendants
- observed_classes.sum([]) { |klass| klass.descendants }
- end
-
- def observe_callbacks?
- self.class.observed_methods.any?
+ def observed_classes
+ klasses = super
+ klasses + klasses.map { |klass| klass.descendants }.flatten
end
def add_observer!(klass)
super
- define_callbacks klass if observe_callbacks?
+ define_callbacks klass
end
def define_callbacks(klass)
- existing_methods = klass.instance_methods.map { |m| m.to_sym }
observer = self
- observer_name = observer.class.name.underscore.gsub('/', '__')
- self.class.observed_methods.each do |method|
- callback = :"_notify_#{observer_name}_for_#{method}"
- unless existing_methods.include? callback
- klass.send(:define_method, callback) do # def _notify_user_observer_for_before_save
- observer.update(method, self) # observer.update(:before_save, self)
- end # end
- klass.send(method, callback) # before_save :_notify_user_observer_for_before_save
- end
+ ActiveRecord::Callbacks::CALLBACKS.each do |callback|
+ next unless respond_to?(callback)
+ klass.send(callback){|record| observer.send(callback, record)}
end
end
end
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 1fbc8a1d32..a4fc18148e 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -1,8 +1,14 @@
-namespace :db do
+db_namespace = namespace :db do
task :load_config => :rails_env do
require 'active_record'
ActiveRecord::Base.configurations = Rails.application.config.database_configuration
- ActiveRecord::Migrator.migrations_path = Rails.application.paths["db/migrate"].first
+ ActiveRecord::Migrator.migrations_paths = Rails.application.paths["db/migrate"].to_a
+
+ if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH)
+ if engine.paths["db/migrate"].existent
+ ActiveRecord::Migrator.migrations_paths += engine.paths["db/migrate"].to_a
+ end
+ end
end
namespace :create do
@@ -138,21 +144,21 @@ namespace :db do
desc "Migrate the database (options: VERSION=x, VERBOSE=false)."
- task :migrate => :environment do
+ task :migrate => [:environment, :load_config] do
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
- ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_path, ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
- Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
+ ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
+ db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
end
namespace :migrate do
# desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
- task :redo => :environment do
+ task :redo => [:environment, :load_config] do
if ENV["VERSION"]
- Rake::Task["db:migrate:down"].invoke
- Rake::Task["db:migrate:up"].invoke
+ db_namespace["migrate:down"].invoke
+ db_namespace["migrate:up"].invoke
else
- Rake::Task["db:rollback"].invoke
- Rake::Task["db:migrate"].invoke
+ db_namespace["rollback"].invoke
+ db_namespace["migrate"].invoke
end
end
@@ -160,23 +166,23 @@ namespace :db do
task :reset => ["db:drop", "db:create", "db:migrate"]
# desc 'Runs the "up" for a given migration VERSION.'
- task :up => :environment do
+ task :up => [:environment, :load_config] do
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
raise "VERSION is required" unless version
- ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_path, version)
- Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
+ ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, version)
+ db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
end
# desc 'Runs the "down" for a given migration VERSION.'
- task :down => :environment do
+ task :down => [:environment, :load_config] do
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
raise "VERSION is required" unless version
- ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_path, version)
- Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
+ ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version)
+ db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
end
desc "Display status of migrations"
- task :status => :environment do
+ task :status => [:environment, :load_config] do
config = ActiveRecord::Base.configurations[Rails.env || 'development']
ActiveRecord::Base.establish_connection(config)
unless ActiveRecord::Base.connection.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name)
@@ -207,17 +213,17 @@ namespace :db do
end
desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
- task :rollback => :environment do
+ task :rollback => [:environment, :load_config] do
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
- ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_path, step)
- Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
+ ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
+ db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
end
# desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
- task :forward => :environment do
+ task :forward => [:environment, :load_config] do
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
- ActiveRecord::Migrator.forward(ActiveRecord::Migrator.migrations_path, step)
- Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
+ ActiveRecord::Migrator.forward(ActiveRecord::Migrator.migrations_paths, step)
+ db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
end
# desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
@@ -261,7 +267,7 @@ namespace :db do
# desc "Raises an error if there are pending migrations"
task :abort_if_pending_migrations => :environment do
if defined? ActiveRecord
- pending_migrations = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations_path).pending_migrations
+ pending_migrations = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations_paths).pending_migrations
if pending_migrations.any?
puts "You have #{pending_migrations.size} pending migrations:"
@@ -321,12 +327,12 @@ namespace :db do
namespace :schema do
desc "Create a db/schema.rb file that can be portably used against any DB supported by AR"
- task :dump => :environment do
+ task :dump => :load_config do
require 'active_record/schema_dumper'
File.open(ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb", "w") do |file|
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
end
- Rake::Task["db:schema:dump"].reenable
+ db_namespace["schema:dump"].reenable
end
desc "Load a schema.rb file into the database"
@@ -383,7 +389,7 @@ namespace :db do
task :load => 'db:test:purge' do
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
ActiveRecord::Schema.verbose = false
- Rake::Task["db:schema:load"].invoke
+ db_namespace["schema:load"].invoke
end
# desc "Recreate the test database from the current environment's database schema"
@@ -457,7 +463,7 @@ namespace :db do
# desc 'Check for pending migrations and load the test schema'
task :prepare => 'db:abort_if_pending_migrations' do
if defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
- Rake::Task[{ :sql => "db:test:clone_structure", :ruby => "db:test:load" }[ActiveRecord::Base.schema_format]].invoke
+ db_namespace[{ :sql => "test:clone_structure", :ruby => "test:load" }[ActiveRecord::Base.schema_format]].invoke
end
end
end
@@ -501,7 +507,7 @@ namespace :railties do
puts "Copied migration #{migration.basename} from #{name}"
end
- ActiveRecord::Migration.copy( ActiveRecord::Migrator.migrations_path, railties,
+ ActiveRecord::Migration.copy( ActiveRecord::Migrator.migrations_paths.first, railties,
:on_skip => on_skip, :on_copy => on_copy)
end
end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 6886c7538b..08b61c9752 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -163,25 +163,25 @@ module ActiveRecord
end
def build_arel
- arel = table
+ arel = table.from table
- arel = build_joins(arel, @joins_values) unless @joins_values.empty?
+ build_joins(arel, @joins_values) unless @joins_values.empty?
- arel = collapse_wheres(arel, (@where_values - ['']).uniq)
+ collapse_wheres(arel, (@where_values - ['']).uniq)
- arel = arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty?
+ arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty?
- arel = arel.take(@limit_value) if @limit_value
- arel = arel.skip(@offset_value) if @offset_value
+ arel.take(@limit_value) if @limit_value
+ arel.skip(@offset_value) if @offset_value
- arel = arel.group(*@group_values.uniq.reject{|g| g.blank?}) unless @group_values.empty?
+ arel.group(*@group_values.uniq.reject{|g| g.blank?}) unless @group_values.empty?
- arel = arel.order(*@order_values.uniq.reject{|o| o.blank?}) unless @order_values.empty?
+ arel.order(*@order_values.uniq.reject{|o| o.blank?}) unless @order_values.empty?
- arel = build_select(arel, @select_values.uniq)
+ build_select(arel, @select_values.uniq)
- arel = arel.from(@from_value) if @from_value
- arel = arel.lock(@lock_value) if @lock_value
+ arel.from(@from_value) if @from_value
+ arel.lock(@lock_value) if @lock_value
arel
end
@@ -247,7 +247,7 @@ module ActiveRecord
end
end
- def build_joins(relation, joins)
+ def build_joins(manager, joins)
joins = joins.map {|j| j.respond_to?(:strip) ? j.strip : j}.uniq
association_joins = joins.find_all do |join|
@@ -257,7 +257,7 @@ module ActiveRecord
stashed_association_joins = joins.grep(ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation)
non_association_joins = (joins - association_joins - stashed_association_joins)
- join_ast = custom_join_ast(relation, non_association_joins)
+ join_ast = custom_join_ast(manager.froms.first, non_association_joins)
join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, association_joins, join_ast)
@@ -267,21 +267,14 @@ module ActiveRecord
# FIXME: refactor this to build an AST
join_dependency.join_associations.each do |association|
- relation = association.join_to(relation)
+ manager = association.join_to(manager)
end
- if Arel::Table === relation
- relation.from(join_ast || relation)
- else
- if relation.froms.length > 0 && join_ast
- join_ast.left = relation.froms.first
- relation.from join_ast
- elsif relation.froms.length == 0 && join_ast
- relation.from(join_ast)
- else
- relation
- end
- end
+ return manager unless join_ast
+
+ join_ast.left = manager.froms.first
+ manager.from join_ast
+ manager
end
def build_select(arel, selects)
diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb
index c6bb5c1961..d815ab05ac 100644
--- a/activerecord/lib/active_record/schema.rb
+++ b/activerecord/lib/active_record/schema.rb
@@ -30,8 +30,8 @@ module ActiveRecord
# ActiveRecord::Schema is only supported by database adapters that also
# support migrations, the two features being very similar.
class Schema < Migration
- def migrations_path
- ActiveRecord::Migrator.migrations_path
+ def migrations_paths
+ ActiveRecord::Migrator.migrations_paths
end
# Eval the given block. All methods available to the current connection
@@ -51,7 +51,7 @@ module ActiveRecord
unless info[:version].blank?
initialize_schema_migrations_table
- assume_migrated_upto_version(info[:version], schema.migrations_path)
+ assume_migrated_upto_version(info[:version], schema.migrations_paths)
end
end
end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 1b0c00bd5a..1820f95261 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -486,4 +486,41 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
new_firm = accounts(:signals37).build_firm(:name => 'Apple')
assert_equal new_firm.name, "Apple"
end
+
+ def test_reassigning_the_parent_id_updates_the_object
+ original_parent = Firm.create! :name => "original"
+ updated_parent = Firm.create! :name => "updated"
+
+ client = Client.new("client_of" => original_parent.id)
+ assert_equal original_parent, client.firm
+ assert_equal original_parent, client.firm_with_condition
+ assert_equal original_parent, client.firm_with_other_name
+
+ client.client_of = updated_parent.id
+ assert_equal updated_parent, client.firm
+ assert_equal updated_parent, client.firm_with_condition
+ assert_equal updated_parent, client.firm_with_other_name
+ end
+
+ def test_polymorphic_reassignment_of_associated_id_updates_the_object
+ member1 = Member.create!
+ member2 = Member.create!
+
+ sponsor = Sponsor.new("sponsorable_type" => "Member", "sponsorable_id" => member1.id)
+ assert_equal member1, sponsor.sponsorable
+
+ sponsor.sponsorable_id = member2.id
+ assert_equal member2, sponsor.sponsorable
+ end
+
+ def test_polymorphic_reassignment_of_associated_type_updates_the_object
+ member1 = Member.create!
+
+ sponsor = Sponsor.new("sponsorable_type" => "Member", "sponsorable_id" => member1.id)
+ assert_equal member1, sponsor.sponsorable
+
+ sponsor.sponsorable_type = "Firm"
+ assert_not_equal member1, sponsor.sponsorable
+ end
+
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index ea86ac29d0..c96ca90750 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -24,6 +24,11 @@ class EagerAssociationTest < ActiveRecord::TestCase
:owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books,
:developers, :projects, :developers_projects
+ def setup
+ # preheat table existence caches
+ Comment.find_by_id(1)
+ end
+
def test_loading_with_one_association
posts = Post.find(:all, :include => :comments)
post = posts.find { |p| p.id == 1 }
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index c3ba1f0c35..86d4a90fc4 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -997,6 +997,22 @@ class BasicsTest < ActiveRecord::TestCase
Topic.serialize(:content)
end
+ def test_serialized_boolean_value_true
+ Topic.serialize(:content)
+ topic = Topic.new(:content => true)
+ assert topic.save
+ topic = topic.reload
+ assert_equal topic.content, true
+ end
+
+ def test_serialized_boolean_value_false
+ Topic.serialize(:content)
+ topic = Topic.new(:content => false)
+ assert topic.save
+ topic = topic.reload
+ assert_equal topic.content, false
+ end
+
def test_quote
author_name = "\\ \001 ' \n \\n \""
topic = Topic.create('author_name' => author_name)
diff --git a/activerecord/test/cases/lifecycle_test.rb b/activerecord/test/cases/lifecycle_test.rb
index 233338498f..b8c3ffb9cb 100644
--- a/activerecord/test/cases/lifecycle_test.rb
+++ b/activerecord/test/cases/lifecycle_test.rb
@@ -9,10 +9,19 @@ class SpecialDeveloper < Developer; end
class SalaryChecker < ActiveRecord::Observer
observe :special_developer
+ attr_accessor :last_saved
def before_save(developer)
return developer.salary > 80000
end
+
+ module Implementation
+ def after_save(developer)
+ self.last_saved = developer
+ end
+ end
+ include Implementation
+
end
class TopicaAuditor < ActiveRecord::Observer
@@ -179,4 +188,11 @@ class LifecycleTest < ActiveRecord::TestCase
developer = SpecialDeveloper.new :name => 'Rookie', :salary => 50000
assert !developer.save, "allowed to save a developer with too low salary"
end
+
+ test "able to call methods defined with included module" do # https://rails.lighthouseapp.com/projects/8994/tickets/6065-activerecordobserver-is-not-aware-of-method-added-by-including-modules
+ SalaryChecker.instance # activate
+ developer = SpecialDeveloper.create! :name => 'Roger', :salary => 100000
+ assert_equal developer, SalaryChecker.instance.last_saved
+ end
+
end
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 96da3be655..1a65045ded 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -1275,6 +1275,20 @@ if ActiveRecord::Base.connection.supports_migrations?
end
end
+ def test_finds_migrations_from_two_directories
+ directories = [MIGRATIONS_ROOT + '/valid_with_timestamps', MIGRATIONS_ROOT + '/to_copy_with_timestamps']
+ migrations = ActiveRecord::Migrator.new(:up, directories).migrations
+
+ [[20090101010101, "PeopleHaveHobbies"],
+ [20090101010202, "PeopleHaveDescriptions"],
+ [20100101010101, "ValidWithTimestampsPeopleHaveLastNames"],
+ [20100201010101, "ValidWithTimestampsWeNeedReminders"],
+ [20100301010101, "ValidWithTimestampsInnocentJointable"]].each_with_index do |pair, i|
+ assert_equal pair.first, migrations[i].version
+ assert_equal pair.last, migrations[i].name
+ end
+ end
+
def test_finds_pending_migrations
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_2", 1)
migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/interleaved/pass_2").pending_migrations
diff --git a/activerecord/test/cases/xml_serialization_test.rb b/activerecord/test/cases/xml_serialization_test.rb
index b11b340e94..2003e25e35 100644
--- a/activerecord/test/cases/xml_serialization_test.rb
+++ b/activerecord/test/cases/xml_serialization_test.rb
@@ -4,6 +4,7 @@ require 'models/post'
require 'models/author'
require 'models/comment'
require 'models/company_in_module'
+require 'models/toy'
class XmlSerializationTest < ActiveRecord::TestCase
def test_should_serialize_default_root
@@ -83,6 +84,26 @@ class DefaultXmlSerializationTest < ActiveRecord::TestCase
end
end
+class DefaultXmlSerializationTimezoneTest < ActiveRecord::TestCase
+ def test_should_serialize_datetime_with_timezone
+ timezone, Time.zone = Time.zone, "Pacific Time (US & Canada)"
+
+ toy = Toy.create(:name => 'Mickey', :updated_at => Time.utc(2006, 8, 1))
+ assert_match %r{<updated-at type=\"datetime\">2006-07-31T17:00:00-07:00</updated-at>}, toy.to_xml
+ ensure
+ Time.zone = timezone
+ end
+
+ def test_should_serialize_datetime_with_timezone_reloaded
+ timezone, Time.zone = Time.zone, "Pacific Time (US & Canada)"
+
+ toy = Toy.create(:name => 'Minnie', :updated_at => Time.utc(2006, 8, 1)).reload
+ assert_match %r{<updated-at type=\"datetime\">2006-07-31T17:00:00-07:00</updated-at>}, toy.to_xml
+ ensure
+ Time.zone = timezone
+ end
+end
+
class NilXmlSerializationTest < ActiveRecord::TestCase
def setup
@xml = Contact.new.to_xml(:root => 'xml_contact')
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 182068071d..b248bc737c 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -138,6 +138,10 @@ module Rails
protected
+ def default_asset_path
+ nil
+ end
+
def default_middleware_stack
ActionDispatch::MiddlewareStack.new.tap do |middleware|
rack_cache = config.action_controller.perform_caching && config.action_dispatch.rack_cache
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 3505388479..8cd496781b 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -4,12 +4,12 @@ require 'rails/engine/configuration'
module Rails
class Application
class Configuration < ::Rails::Engine::Configuration
- attr_accessor :allow_concurrency, :cache_classes, :cache_store,
+ attr_accessor :allow_concurrency, :asset_host, :cache_classes, :cache_store,
:encoding, :consider_all_requests_local, :dependency_loading,
- :filter_parameters, :log_level, :logger,
+ :filter_parameters, :helpers_paths, :log_level, :logger,
:preload_frameworks, :reload_plugins,
:secret_token, :serve_static_assets, :session_options,
- :time_zone, :whiny_nils, :helpers_paths
+ :time_zone, :whiny_nils
def initialize(*)
super
@@ -24,22 +24,9 @@ module Rails
@session_options = {}
@time_zone = "UTC"
@middleware = app_middleware
- @asset_path = '/'
@generators = app_generators
end
- def asset_path=(value)
- action_mailer.asset_path = value if respond_to?(:action_mailer) && action_mailer
- action_controller.asset_path = value if respond_to?(:action_controller) && action_controller
- super(value)
- end
-
- def asset_host=(value)
- action_mailer.asset_host = value if action_mailer
- action_controller.asset_host = value if action_controller
- super(value)
- end
-
def compiled_asset_path
"/"
end
diff --git a/railties/lib/rails/application/railties.rb b/railties/lib/rails/application/railties.rb
index c1d2de571f..4fc5e92837 100644
--- a/railties/lib/rails/application/railties.rb
+++ b/railties/lib/rails/application/railties.rb
@@ -8,14 +8,6 @@ module Rails
@all.each(&block) if block
@all
end
-
- def railties
- @railties ||= ::Rails::Railtie.subclasses.map(&:instance)
- end
-
- def engines
- @engines ||= ::Rails::Engine.subclasses.map(&:instance)
- end
end
end
end
diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb
index 338565247f..46363d7921 100644
--- a/railties/lib/rails/commands.rb
+++ b/railties/lib/rails/commands.rb
@@ -18,8 +18,7 @@ when 'generate', 'destroy', 'plugin'
require APP_PATH
Rails.application.require_environment!
- if defined?(ENGINE_PATH)
- engine = Rails.application.railties.engines.find { |r| r.root.to_s == ENGINE_PATH }
+ if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH)
Rails.application = engine
end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 85fa4424c4..cda0e0a135 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -371,6 +371,11 @@ module Rails
end
end
end
+
+ # Finds engine with given path
+ def find(path)
+ Rails::Engine::Railties.engines.find { |r| File.expand_path(r.root.to_s) == File.expand_path(path.to_s) }
+ end
end
delegate :middleware, :root, :paths, :to => :config
@@ -494,7 +499,7 @@ module Rails
end
initializer :append_asset_paths do
- config.asset_path ||= "/#{railtie_name}%s"
+ config.asset_path ||= default_asset_path
public_path = paths["public"].first
if config.compiled_asset_path && File.exist?(public_path)
@@ -548,6 +553,11 @@ module Rails
end
protected
+
+ def default_asset_path
+ "/#{railtie_name}%s"
+ end
+
def routes?
defined?(@routes)
end
diff --git a/railties/lib/rails/engine/railties.rb b/railties/lib/rails/engine/railties.rb
index e91bdbf1e5..d5ecd2e48d 100644
--- a/railties/lib/rails/engine/railties.rb
+++ b/railties/lib/rails/engine/railties.rb
@@ -18,6 +18,16 @@ module Rails
Plugin.all(plugin_names, @config.paths["vendor/plugins"].existent)
end
end
+
+ def self.railties
+ @railties ||= ::Rails::Railtie.subclasses.map(&:instance)
+ end
+
+ def self.engines
+ @engines ||= ::Rails::Engine.subclasses.map(&:instance)
+ end
+
+ delegate :railties, :engines, :to => "self.class"
end
end
end
diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile
index 12350309bf..25292f59ad 100755
--- a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile
@@ -14,3 +14,11 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_files.include('README.rdoc')
rdoc.rdoc_files.include('lib/**/*.rb')
end
+
+<% if full? && !options[:skip_active_record] -%>
+namespace :app do
+ ENGINE_PATH = File.expand_path("..", __FILE__)
+ load File.expand_path("../<%= dummy_path -%>/Rakefile", __FILE__)
+end
+<% end -%>
+
diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb
index d06fe7cbd0..dd4d2da4eb 100644
--- a/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb
@@ -1,7 +1,9 @@
require 'test_helper'
class NavigationTest < ActionDispatch::IntegrationTest
+<% unless options[:skip_active_record] -%>
fixtures :all
+<% end -%>
# Replace this with your real tests.
test "the truth" do
diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb
index 7b61047e77..791b901593 100644
--- a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb
@@ -6,10 +6,5 @@ require "rails/test_help"
Rails.backtrace_cleaner.remove_silencers!
-<% if full? && !options[:skip_active_record] -%>
-# Run any available migration from application
-ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
-<% end -%>
-
# Load support files
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index b8d0854286..c12c4a4660 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -95,6 +95,11 @@ module ApplicationTests
assert AppTemplate::Application.config.allow_concurrency
end
+ test "asset_path defaults to nil for application" do
+ require "#{app_path}/config/environment"
+ assert_equal nil, AppTemplate::Application.config.asset_path
+ end
+
test "the application can be marked as threadsafe when there are no frameworks" do
FileUtils.rm_rf("#{app_path}/config/environments")
add_to_config <<-RUBY
diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb
index 2105585272..0d24821ff6 100644
--- a/railties/test/generators/plugin_new_generator_test.rb
+++ b/railties/test/generators/plugin_new_generator_test.rb
@@ -114,7 +114,7 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase
end
def test_ensure_that_tests_works_in_full_mode
- run_generator [destination_root, "--full"]
+ run_generator [destination_root, "--full", "--skip_active_record"]
FileUtils.cd destination_root
`bundle install`
assert_match /2 tests, 2 assertions, 0 failures, 0 errors/, `bundle exec rake test`
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index 7548c6318e..05bd0c36cd 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -702,5 +702,24 @@ module RailtiesTest
assert_equal "foo", Bukkits.table_name_prefix
end
+
+ test "fetching engine by path" do
+ @plugin.write "lib/bukkits.rb", <<-RUBY
+ module Bukkits
+ class Engine < ::Rails::Engine
+ end
+ end
+ RUBY
+
+ boot_rails
+ require "#{rails_root}/config/environment"
+
+ assert_equal Bukkits::Engine.instance, Rails::Engine.find(@plugin.path)
+
+ # check expanding paths
+ engine_dir = @plugin.path.chomp("/").split("/").last
+ engine_path = File.join(@plugin.path, '..', engine_dir)
+ assert_equal Bukkits::Engine.instance, Rails::Engine.find(engine_path)
+ end
end
end