diff options
author | Jeremy Kemper <jeremy@bitsweat.net> | 2008-12-30 12:40:32 -0800 |
---|---|---|
committer | Jeremy Kemper <jeremy@bitsweat.net> | 2008-12-30 12:40:32 -0800 |
commit | d9615928866115015e9ec48ac88a90869ef85d9b (patch) | |
tree | e6783aeeb36f1b8263d97d2548a39a4e5ee58fa6 | |
parent | 276ec16007b03d0a527fb0b83a7ee0b81e460fa1 (diff) | |
parent | 82443ecfad5e756da922d6a166b0093c8a74d720 (diff) | |
download | rails-d9615928866115015e9ec48ac88a90869ef85d9b.tar.gz rails-d9615928866115015e9ec48ac88a90869ef85d9b.tar.bz2 rails-d9615928866115015e9ec48ac88a90869ef85d9b.zip |
Merge branch 'master' of git@github.com:rails/rails
21 files changed, 165 insertions, 149 deletions
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb index 4900f6fb35..a6126d6f7f 100644 --- a/actionmailer/test/abstract_unit.rb +++ b/actionmailer/test/abstract_unit.rb @@ -17,7 +17,6 @@ $:.unshift "#{File.dirname(__FILE__)}/fixtures/helpers" FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') ActionMailer::Base.template_root = FIXTURE_LOAD_PATH -ActionMailer::Base.template_root.load class MockSMTP def self.deliveries diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index da3d1f46ee..bc18dfaec8 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -869,7 +869,7 @@ module ActionController #:nodoc: validate_render_arguments(options, extra_options, block_given?) if options.nil? - options = { :template => default_template.filename, :layout => true } + options = { :template => default_template, :layout => true } elsif options == :update options = extra_options.merge({ :update => true }) elsif options.is_a?(String) || options.is_a?(Symbol) @@ -1125,7 +1125,7 @@ module ActionController #:nodoc: end # Sets the etag, last_modified, or both on the response and renders a - # "304 Not Modified" response if the request is already fresh. + # "304 Not Modified" response if the request is already fresh. # # Example: # @@ -1133,8 +1133,8 @@ module ActionController #:nodoc: # @article = Article.find(params[:id]) # fresh_when(:etag => @article, :last_modified => @article.created_at.utc) # end - # - # This will render the show template if the request isn't sending a matching etag or + # + # This will render the show template if the request isn't sending a matching etag or # If-Modified-Since header and just a "304 Not Modified" response if there's a match. def fresh_when(options) options.assert_valid_keys(:etag, :last_modified) @@ -1239,7 +1239,7 @@ module ActionController #:nodoc: log_processing_for_parameters end end - + def log_processing_for_request_id request_id = "\n\nProcessing #{self.class.name}\##{action_name} " request_id << "to #{params[:format]} " if params[:format] @@ -1251,7 +1251,7 @@ module ActionController #:nodoc: def log_processing_for_parameters parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup parameters = parameters.except!(:controller, :action, :format, :_method) - + logger.info " Parameters: #{parameters.inspect}" unless parameters.empty? end diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb index 3a5e5071bb..de35b53872 100644 --- a/actionpack/lib/action_controller/rescue.rb +++ b/actionpack/lib/action_controller/rescue.rb @@ -38,8 +38,8 @@ module ActionController #:nodoc: 'ActionView::TemplateError' => 'template_error' } - RESCUES_TEMPLATE_PATH = ActionView::PathSet::Path.new( - File.join(File.dirname(__FILE__), "templates"), true) + RESCUES_TEMPLATE_PATH = ActionView::Template::EagerPath.new( + File.join(File.dirname(__FILE__), "templates")) def self.included(base) #:nodoc: base.cattr_accessor :rescue_responses diff --git a/actionpack/lib/action_controller/url_encoded_pair_parser.rb b/actionpack/lib/action_controller/url_encoded_pair_parser.rb index bea96c711d..9883ad0d85 100644 --- a/actionpack/lib/action_controller/url_encoded_pair_parser.rb +++ b/actionpack/lib/action_controller/url_encoded_pair_parser.rb @@ -70,11 +70,12 @@ module ActionController top[-1][key] = value else top << {key => value}.with_indifferent_access - push top.last - value = top[key] end + push top.last + return top[key] else top << value + return value end elsif top.is_a? Hash key = CGI.unescape(key) @@ -84,12 +85,10 @@ module ActionController else raise ArgumentError, "Don't know what to do: top is #{top.inspect}" end - - return value end def type_conflict!(klass, value) raise TypeError, "Conflicting types for parameter containers. Expected an instance of #{klass} but found an instance of #{value.class}. This can be caused by colliding Array and Hash parameters like qs[]=value&qs[key]=value. (The parameters received were #{value.inspect}.)" end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 8958e61e9d..70a0ba91a7 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -225,7 +225,7 @@ module ActionView #:nodoc: end # Returns the result of a render that's dictated by the options hash. The primary options are: - # + # # * <tt>:partial</tt> - See ActionView::Partials. # * <tt>:update</tt> - Calls update_page with the block given. # * <tt>:file</tt> - Renders an explicit template file (this used to be the old default), add :locals to pass in those. diff --git a/actionpack/lib/action_view/inline_template.rb b/actionpack/lib/action_view/inline_template.rb index 5e00cef13f..54efa543c8 100644 --- a/actionpack/lib/action_view/inline_template.rb +++ b/actionpack/lib/action_view/inline_template.rb @@ -12,7 +12,7 @@ module ActionView #:nodoc: private # Always recompile inline templates - def recompile?(local_assigns) + def recompile? true end end diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb index b030156889..19207e7262 100644 --- a/actionpack/lib/action_view/paths.rb +++ b/actionpack/lib/action_view/paths.rb @@ -2,7 +2,7 @@ module ActionView #:nodoc: class PathSet < Array #:nodoc: def self.type_cast(obj) if obj.is_a?(String) - Path.new(obj) + Template::EagerPath.new(obj) else obj end @@ -32,111 +32,6 @@ module ActionView #:nodoc: super(*objs.map { |obj| self.class.type_cast(obj) }) end - class Path #:nodoc: - attr_reader :path, :paths - delegate :hash, :inspect, :to => :path - - def initialize(path, load = false) - raise ArgumentError, "path already is a Path class" if path.is_a?(Path) - @path = path.freeze - reload! if load - end - - def to_s - if defined?(RAILS_ROOT) - path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') - else - path.to_s - end - end - - def to_str - path.to_str - end - - def ==(path) - to_str == path.to_str - end - - def eql?(path) - to_str == path.to_str - end - - # Returns a ActionView::Template object for the given path string. The - # input path should be relative to the view path directory, - # +hello/index.html.erb+. This method also has a special exception to - # match partial file names without a handler extension. So - # +hello/index.html+ will match the first template it finds with a - # known template extension, +hello/index.html.erb+. Template extensions - # should not be confused with format extensions +html+, +js+, +xml+, - # etc. A format must be supplied to match a formated file. +hello/index+ - # will never match +hello/index.html.erb+. - # - # This method also has two different implementations, one that is "lazy" - # and makes file system calls every time and the other is cached, - # "eager" which looks up the template in an in memory index. The "lazy" - # version is designed for development where you want to automatically - # find new templates between requests. The "eager" version is designed - # for production mode and it is much faster but requires more time - # upfront to build the file index. - def [](path) - if loaded? - @paths[path] - else - Dir.glob("#{@path}/#{path}*").each do |file| - template = create_template(file) - if template.accessible_paths.include?(path) - return template - end - end - nil - end - end - - def loaded? - @loaded ? true : false - end - - def load - reload! unless loaded? - self - end - - # Rebuild load path directory cache - def reload! - @paths = {} - - templates_in_path do |template| - template.load! - template.accessible_paths.each do |path| - @paths[path] = template - end - end - - @paths.freeze - @loaded = true - end - - private - def templates_in_path - (Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file| - yield create_template(file) unless File.directory?(file) - end - end - - def create_template(file) - Template.new(file.split("#{self}/").last, self) - end - end - - def load - each { |path| path.load } - end - - def reload! - each { |path| path.reload! } - end - def find_template(original_template_path, format = nil) return original_template_path if original_template_path.respond_to?(:render) template_path = original_template_path.sub(/^\//, '') diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/renderable.rb index d8e72f1179..153e14f68b 100644 --- a/actionpack/lib/action_view/renderable.rb +++ b/actionpack/lib/action_view/renderable.rb @@ -60,7 +60,7 @@ module ActionView def compile(local_assigns) render_symbol = method_name(local_assigns) - if recompile?(render_symbol) + if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile? compile!(render_symbol, local_assigns) end end @@ -89,11 +89,8 @@ module ActionView end end - # Method to check whether template compilation is necessary. - # The template will be compiled if the file has not been compiled yet, or - # if local_assigns has a new key, which isn't supported by the compiled code yet. - def recompile?(symbol) - !Base::CompiledTemplates.method_defined?(symbol) || !loaded? + def recompile? + false end end end diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 5b384d0e4d..88ee07d95b 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -1,5 +1,83 @@ module ActionView #:nodoc: class Template + class Path + attr_reader :path, :paths + delegate :hash, :inspect, :to => :path + + def initialize(path) + raise ArgumentError, "path already is a Path class" if path.is_a?(Path) + @path = path.freeze + end + + def to_s + if defined?(RAILS_ROOT) + path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') + else + path.to_s + end + end + + def to_str + path.to_str + end + + def ==(path) + to_str == path.to_str + end + + def eql?(path) + to_str == path.to_str + end + + # Returns a ActionView::Template object for the given path string. The + # input path should be relative to the view path directory, + # +hello/index.html.erb+. This method also has a special exception to + # match partial file names without a handler extension. So + # +hello/index.html+ will match the first template it finds with a + # known template extension, +hello/index.html.erb+. Template extensions + # should not be confused with format extensions +html+, +js+, +xml+, + # etc. A format must be supplied to match a formated file. +hello/index+ + # will never match +hello/index.html.erb+. + def [](path) + templates_in_path do |template| + if template.accessible_paths.include?(path) + return template + end + end + nil + end + + private + def templates_in_path + (Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file| + yield create_template(file) unless File.directory?(file) + end + end + + def create_template(file) + Template.new(file.split("#{self}/").last, self) + end + end + + class EagerPath < Path + def initialize(path) + super + + @paths = {} + templates_in_path do |template| + template.load! + template.accessible_paths.each do |path| + @paths[path] = template + end + end + @paths.freeze + end + + def [](path) + @paths[path] + end + end + extend TemplateHandlers extend ActiveSupport::Memoizable include Renderable @@ -115,13 +193,12 @@ module ActionView #:nodoc: File.mtime(filename) > mtime end - def loaded? - @loaded + def recompile? + !@cached end def load! - @loaded = true - compile({}) + @cached = true freeze end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 2ba056e60f..30e2d863d0 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -34,7 +34,6 @@ ActionController::Base.session_store = nil FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') ActionController::Base.view_paths = FIXTURE_LOAD_PATH -ActionController::Base.view_paths.load def uses_mocha(test_name) yield diff --git a/actionpack/test/controller/request_test.rb b/actionpack/test/controller/request_test.rb index 349cea268f..c93d3152b8 100644 --- a/actionpack/test/controller/request_test.rb +++ b/actionpack/test/controller/request_test.rb @@ -441,6 +441,7 @@ class UrlEncodedRequestParameterParsingTest < ActiveSupport::TestCase def test_deep_query_string_with_array_of_hash assert_equal({'x' => {'y' => [{'z' => '10'}]}}, ActionController::RequestParser.parse_query_parameters('x[y][][z]=10')) assert_equal({'x' => {'y' => [{'z' => '10', 'w' => '10'}]}}, ActionController::RequestParser.parse_query_parameters('x[y][][z]=10&x[y][][w]=10')) + assert_equal({'x' => {'y' => [{'z' => '10', 'v' => {'w' => '10'}}]}}, ActionController::RequestParser.parse_query_parameters('x[y][][z]=10&x[y][][v][w]=10')) end def test_deep_query_string_with_array_of_hashes_with_one_pair diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb index a68b09bb45..caea1bd643 100644 --- a/actionpack/test/template/compiled_templates_test.rb +++ b/actionpack/test/template/compiled_templates_test.rb @@ -31,7 +31,7 @@ uses_mocha 'TestTemplateRecompilation' do end def test_compiled_template_will_always_be_recompiled_when_template_is_not_cached - ActionView::Template.any_instance.expects(:loaded?).times(3).returns(false) + ActionView::Template.any_instance.expects(:recompile?).times(3).returns(true) assert_equal 0, @compiled_templates.instance_methods.size assert_equal "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb") ActionView::Template.any_instance.expects(:compile!).times(3) @@ -62,13 +62,14 @@ uses_mocha 'TestTemplateRecompilation' do def render_with_cache(*args) view_paths = ActionController::Base.view_paths - assert view_paths.first.loaded? + assert_equal ActionView::Template::EagerPath, view_paths.first.class ActionView::Base.new(view_paths, {}).render(*args) end def render_without_cache(*args) - view_paths = ActionView::Base.process_view_paths(FIXTURE_LOAD_PATH) - assert !view_paths.first.loaded? + path = ActionView::Template::Path.new(FIXTURE_LOAD_PATH) + view_paths = ActionView::Base.process_view_paths(path) + assert_equal ActionView::Template::Path, view_paths.first.class ActionView::Base.new(view_paths, {}).render(*args) end diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 0387a11de2..4bd897efeb 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -197,7 +197,7 @@ class CachedViewRenderTest < Test::Unit::TestCase # Ensure view path cache is primed def setup view_paths = ActionController::Base.view_paths - assert view_paths.first.loaded? + assert_equal ActionView::Template::EagerPath, view_paths.first.class setup_view(view_paths) end end @@ -208,8 +208,9 @@ class LazyViewRenderTest < Test::Unit::TestCase # Test the same thing as above, but make sure the view path # is not eager loaded def setup - view_paths = ActionView::Base.process_view_paths(FIXTURE_LOAD_PATH) - assert !view_paths.first.loaded? + path = ActionView::Template::Path.new(FIXTURE_LOAD_PATH) + view_paths = ActionView::Base.process_view_paths(path) + assert_equal ActionView::Template::Path, view_paths.first.class setup_view(view_paths) end end diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 9d0bf3a308..e4ab69aa1b 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -195,7 +195,7 @@ module ActiveRecord def preload_has_one_association(records, reflection, preload_options={}) return if records.first.send("loaded_#{reflection.name}?") - id_to_record_map, ids = construct_id_map(records) + id_to_record_map, ids = construct_id_map(records, reflection.options[:primary_key]) options = reflection.options records.each {|record| record.send("set_#{reflection.name}_target", nil)} if options[:through] @@ -229,7 +229,7 @@ module ActiveRecord options = reflection.options primary_key_name = reflection.through_reflection_primary_key_name - id_to_record_map, ids = construct_id_map(records, primary_key_name) + id_to_record_map, ids = construct_id_map(records, primary_key_name || reflection.options[:primary_key]) records.each {|record| record.send(reflection.name).loaded} if options[:through] diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index c154a5087c..86616abf52 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -22,7 +22,7 @@ module ActiveRecord through_reflection = reflection.through_reflection source_reflection_names = reflection.source_reflection_names source_associations = reflection.through_reflection.klass.reflect_on_all_associations.collect { |a| a.name.inspect } - super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence :connector => 'or'} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence :connector => 'or'}?") + super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence :two_words_connector => ' or ', :last_word_connector => ', or '} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence :two_words_connector => ' or ', :last_word_connector => ', or '}?") end end @@ -2171,7 +2171,7 @@ module ActiveRecord aliased_table_name, foreign_key, parent.aliased_table_name, - parent.primary_key + reflection.options[:primary_key] || parent.primary_key ] end when :belongs_to diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index 59f1d3b867..676c4ace61 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -180,7 +180,10 @@ module ActiveRecord record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record? record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s else - record[@reflection.primary_key_name] = @owner.id unless @owner.new_record? + unless @owner.new_record? + primary_key = @reflection.options[:primary_key] || :id + record[@reflection.primary_key_name] = @owner.send(primary_key) + end end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index 84f8c0284e..9387cf8827 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -402,6 +402,10 @@ module ActiveRecord end def add_column(table_name, column_name, type, options = {}) #:nodoc: + if @connection.respond_to?(:transaction_active?) && @connection.transaction_active? + raise StatementInvalid, 'Cannot add columns to a SQLite database while inside a transaction' + end + alter_table(table_name) do |definition| definition.column(column_name, type, options) end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index afbd9fddf9..14099d4176 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -786,4 +786,37 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_equal Person.find(person.id).agents, person.agents end end + + def test_preload_has_many_using_primary_key + expected = Firm.find(:first).clients_using_primary_key.to_a + firm = Firm.find :first, :include => :clients_using_primary_key + assert_no_queries do + assert_equal expected, firm.clients_using_primary_key + end + end + + def test_include_has_many_using_primary_key + expected = Firm.find(1).clients_using_primary_key.sort_by &:name + firm = Firm.find 1, :include => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies.name' + assert_no_queries do + assert_equal expected, firm.clients_using_primary_key + end + end + + def test_preload_has_one_using_primary_key + expected = Firm.find(:first).account_using_primary_key + firm = Firm.find :first, :include => :account_using_primary_key + assert_no_queries do + assert_equal expected, firm.account_using_primary_key + end + end + + def test_include_has_one_using_primary_key + expected = Firm.find(1).account_using_primary_key + firm = Firm.find(:all, :include => :account_using_primary_key, :order => 'accounts.id').detect {|f| f.id == 1} + assert_no_queries do + assert_equal expected, firm.account_using_primary_key + end + end + end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 20b9acda44..a5ae5cd8ec 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -1115,5 +1115,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert !client_association.respond_to?(:private_method) assert client_association.respond_to?(:private_method, true) end + + def test_creating_using_primary_key + firm = Firm.find(:first) + client = firm.clients_using_primary_key.create!(:name => 'test') + assert_equal firm.name, client.firm_name + end end diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index b152f95a15..bab842cf66 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -254,7 +254,7 @@ class NamedScopeTest < ActiveRecord::TestCase end def test_should_use_where_in_query_for_named_scope - assert_equal Developer.find_all_by_name('Jamis'), Developer.find_all_by_id(Developer.jamises) + assert_equal Developer.find_all_by_name('Jamis').to_set, Developer.find_all_by_id(Developer.jamises).to_set end def test_size_should_use_count_when_results_are_not_loaded diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index 637fe74313..10c2490624 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -370,8 +370,9 @@ Run `rake gems:install` to install the missing gems. def load_view_paths if configuration.frameworks.include?(:action_view) if configuration.cache_classes - ActionController::Base.view_paths.load if configuration.frameworks.include?(:action_controller) - ActionMailer::Base.template_root.load if configuration.frameworks.include?(:action_mailer) + view_path = ActionView::Template::EagerPath.new(configuration.view_path) + ActionController::Base.view_paths = view_path if configuration.frameworks.include?(:action_controller) + ActionMailer::Base.template_root = view_path if configuration.frameworks.include?(:action_mailer) end end end @@ -473,7 +474,7 @@ Run `rake gems:install` to install the missing gems. # set to use Configuration#view_path. def initialize_framework_views if configuration.frameworks.include?(:action_view) - view_path = ActionView::PathSet::Path.new(configuration.view_path, false) + view_path = ActionView::Template::Path.new(configuration.view_path) ActionMailer::Base.template_root ||= view_path if configuration.frameworks.include?(:action_mailer) ActionController::Base.view_paths = view_path if configuration.frameworks.include?(:action_controller) && ActionController::Base.view_paths.empty? end |