diff options
19 files changed, 159 insertions, 31 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/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 5a38158e9f..47de5848fa 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -327,7 +327,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/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..1856395f2d 100644 --- a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb +++ b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb @@ -151,7 +151,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/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/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/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/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/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 |