diff options
606 files changed, 3609 insertions, 2290 deletions
diff --git a/.travis.yml b/.travis.yml index 5214b989af..012e795caa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ rvm: - 2.0.0 env: - "GEM=railties" - - "GEM=ap,am,amo,as" + - "GEM=ap,am,amo,as,av" - "GEM=ar:mysql" - "GEM=ar:mysql2" - "GEM=ar:sqlite3" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6d3cf072c1..19b7b638b6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,6 +4,8 @@ Ruby on Rails is a volunteer effort. We encourage you to pitch in. [Join the tea * If you want to submit a patch, please read the [Contributing to Ruby on Rails](http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html) guide. +* If you want to contribute to Rails documentation, please read the [Contributing to the Rails Documentation](http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#contributing-to-the-rails-documentation) section of the aforementioned guide. + *We only accept bug reports and pull requests in GitHub*. * If you have a question about how to use Ruby on Rails, please [ask the rubyonrails-talk mailing list](https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-talk). @@ -61,7 +61,6 @@ platforms :ruby do end platforms :jruby do - gem 'json' gem 'activerecord-jdbcsqlite3-adapter', '>= 1.2.7' group :db do @@ -8,7 +8,7 @@ require 'railties/lib/rails/api/task' desc "Build gem files for all projects" task :build => "all:build" -desc "Release all gems to gemcutter and create a tag" +desc "Release all gems to rubygems and create a tag" task :release => "all:release" PROJECTS = %w(activesupport activemodel actionpack actionmailer activerecord railties) diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile index 45c238d302..5d5539df1d 100644 --- a/actionmailer/Rakefile +++ b/actionmailer/Rakefile @@ -1,5 +1,4 @@ require 'rake/testtask' -require 'rake/packagetask' require 'rubygems/package_task' desc "Default Task" @@ -17,7 +16,7 @@ namespace :test do task :isolated do ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME')) Dir.glob("test/**/*_test.rb").all? do |file| - sh(ruby, '-Ilib:test', file) + sh(ruby, '-w', '-Ilib:test', file) end or raise "Failures" end end @@ -28,7 +27,7 @@ Gem::PackageTask.new(spec) do |p| p.gem_spec = spec end -desc "Release to gemcutter" +desc "Release to rubygems" task release: :package do require 'rake/gemcutter' Rake::Gemcutter::Tasks.new(spec).define diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 6f5027dc23..05495179c3 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,26 @@ -* Fix an issue where partials with a number in the filename weren't being digested for cache dependencies. +* Fix `Mime::Type.parse` when bad accepts header is looked up. Previously it + was setting `request.formats` with an array containing a `nil` value, which + raised an error when setting the controller formats. - *Bryan Ricker* + Fixes #10965 + + *Becker* + +* Merge `:action` from routing scope and assign endpoint if both `:controller` + and `:action` are present. The endpoint assignment only occurs if there is + no `:to` present in the options hash so should only affect routes using the + shorthand syntax (i.e. endpoint is inferred from the path). + + Fixes #9856 + + *Yves Senn*, *Andrew White* + +* ActionView extracted from ActionPack + + *Piotr Sarnacki*, *Łukasz Strzałkowski* + +* Fix removing trailing slash for mounted apps #3215 + + *Piotr Sarnacki* Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/actionpack/CHANGELOG.md) for previous changes. diff --git a/actionpack/Rakefile b/actionpack/Rakefile index ba7956c3ab..5433e584af 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -1,5 +1,4 @@ require 'rake/testtask' -require 'rake/packagetask' require 'rubygems/package_task' desc "Default Task" @@ -8,35 +7,26 @@ task :default => :test # Run the unit tests desc "Run all unit tests" -task :test => [:test_action_pack, :test_active_record_integration] +task :test => [:test_action_pack] Rake::TestTask.new(:test_action_pack) do |t| t.libs << 'test' # make sure we include the tests in alphabetical order as on some systems # this will not happen automatically and the tests (as a whole) will error - t.test_files = Dir.glob('test/{abstract,controller,dispatch,template,assertions,journey}/**/*_test.rb').sort + t.test_files = Dir.glob('test/{abstract,controller,dispatch,assertions,journey}/**/*_test.rb').sort t.warning = true t.verbose = true end namespace :test do - Rake::TestTask.new(:isolated) do |t| - t.libs << 'test' - t.pattern = 'test/ts_isolated.rb' + task :isolated do + ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME')) + Dir.glob("test/{abstract,controller,dispatch}/**/*_test.rb").all? do |file| + sh(ruby, '-w', '-Ilib:test', file) + end or raise "Failures" end - - Rake::TestTask.new(:template) do |t| - t.libs << 'test' - t.pattern = 'test/template/**/*.rb' - end -end - -desc 'ActiveRecord Integration Tests' -Rake::TestTask.new(:test_active_record_integration) do |t| - t.libs << 'test' - t.test_files = Dir.glob("test/activerecord/*_test.rb") end spec = eval(File.read('actionpack.gemspec')) @@ -45,7 +35,7 @@ Gem::PackageTask.new(spec) do |p| p.gem_spec = spec end -desc "Release to gemcutter" +desc "Release to rubygems" task :release => :package do require 'rake/gemcutter' Rake::Gemcutter::Tasks.new(spec).define diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index cc8351a489..e3aa84ba0f 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -20,10 +20,10 @@ Gem::Specification.new do |s| s.requirements << 'none' s.add_dependency 'activesupport', version - s.add_dependency 'builder', '~> 3.1.0' + s.add_dependency 'actionview', version + s.add_dependency 'rack', '~> 1.5.2' s.add_dependency 'rack-test', '~> 0.6.2' - s.add_dependency 'erubis', '~> 2.7.0' s.add_development_dependency 'activemodel', version s.add_development_dependency 'tzinfo', '~> 0.3.37' diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 9cacb3862b..9fdad63b45 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -46,10 +46,6 @@ module ActionController autoload :TestCase, 'action_controller/test_case' autoload :TemplateAssertions, 'action_controller/test_case' - eager_autoload do - autoload :RecordIdentifier - end - def self.eager_load! super ActionController::Caching.eager_load! diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 971c4189c8..d7b09b67c0 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -223,7 +223,6 @@ module ActionController ForceSSL, Streaming, DataStreaming, - RecordIdentifier, HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods, HttpAuthentication::Token::ControllerMethods, diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index 891819968b..fd5b661209 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -97,8 +97,12 @@ module ActionController #:nodoc: # # This will return status 201 if the task was saved successfully. If not, # it will simply ignore the given options and return status 422 and the - # resource errors. To customize the failure scenario, you can pass a - # a block to <code>respond_with</code>: + # resource errors. You can also override the location to redirect to: + # + # respond_with(@project, location: root_path) + # + # To customize the failure scenario, you can pass a block to + # <code>respond_with</code>: # # def create # @project = Project.find(params[:project_id]) diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb deleted file mode 100644 index d598bac467..0000000000 --- a/actionpack/lib/action_controller/record_identifier.rb +++ /dev/null @@ -1,31 +0,0 @@ -require 'action_view/record_identifier' - -module ActionController - module RecordIdentifier - MODULE_MESSAGE = 'Calling ActionController::RecordIdentifier.%s is deprecated and ' \ - 'will be removed in Rails 4.1, please call using ActionView::RecordIdentifier instead.' - INSTANCE_MESSAGE = '%s method will no longer be included by default in controllers ' \ - 'since Rails 4.1. If you would like to use it in controllers, please include ' \ - 'ActionView::RecordIdentifier module.' - - def dom_id(record, prefix = nil) - ActiveSupport::Deprecation.warn(INSTANCE_MESSAGE % 'dom_id') - ActionView::RecordIdentifier.dom_id(record, prefix) - end - - def dom_class(record, prefix = nil) - ActiveSupport::Deprecation.warn(INSTANCE_MESSAGE % 'dom_class') - ActionView::RecordIdentifier.dom_class(record, prefix) - end - - def self.dom_id(record, prefix = nil) - ActiveSupport::Deprecation.warn(MODULE_MESSAGE % 'dom_id') - ActionView::RecordIdentifier.dom_id(record, prefix) - end - - def self.dom_class(record, prefix = nil) - ActiveSupport::Deprecation.warn(MODULE_MESSAGE % 'dom_class') - ActionView::RecordIdentifier.dom_class(record, prefix) - end - end -end diff --git a/actionpack/lib/action_controller/vendor/html-scanner.rb b/actionpack/lib/action_controller/vendor/html-scanner.rb deleted file mode 100644 index 896208bc05..0000000000 --- a/actionpack/lib/action_controller/vendor/html-scanner.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'action_view/vendor/html-scanner' -require 'active_support/deprecation' - -ActiveSupport::Deprecation.warn 'Vendored html-scanner was moved to action_view, please require "action_view/vendor/html-scanner" instead. ' + - 'This file will be removed in Rails 4.1' diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index f29ad359ac..ef144c3c76 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -53,10 +53,6 @@ module Mime @@html_types = Set.new [:html, :all] cattr_reader :html_types - # These are the content types which browsers can generate without using ajax, flash, etc - # i.e. following a link, getting an image or posting a form. CSRF protection - # only needs to protect against these types. - @@browser_generated_types = Set.new [:html, :url_encoded_form, :multipart_form, :text] attr_reader :symbol @register_callbacks = [] @@ -179,7 +175,7 @@ module Mime def parse(accept_header) if accept_header !~ /,/ accept_header = accept_header.split(PARAMETER_SEPARATOR_REGEXP).first - parse_trailing_star(accept_header) || [Mime::Type.lookup(accept_header)] + parse_trailing_star(accept_header) || [Mime::Type.lookup(accept_header)].compact else list, index = AcceptList.new, 0 accept_header.split(',').each do |header| @@ -272,18 +268,6 @@ module Mime end end - # Returns true if Action Pack should check requests using this Mime Type for possible request forgery. See - # ActionController::RequestForgeryProtection. - def verify_request? - ActiveSupport::Deprecation.warn "Mime::Type#verify_request? is deprecated and will be removed in Rails 4.1" - @@browser_generated_types.include?(to_sym) - end - - def self.browser_generated_types - ActiveSupport::Deprecation.warn "Mime::Type.browser_generated_types is deprecated and will be removed in Rails 4.1" - @@browser_generated_types - end - def html? @@html_types.include?(to_sym) || @string =~ /html/ end diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index 20c24ddd85..8e992070f1 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -64,17 +64,13 @@ module ActionDispatch end new_hash = {} - params.each do |k, v| - new_key = k.is_a?(String) ? k.dup.force_encoding(Encoding::UTF_8).encode! : k - new_hash[new_key] = - case v - when Hash - normalize_encode_params(v) - when Array - v.map! {|el| normalize_encode_params(el) } - else - normalize_encode_params(v) - end + params.each do |key, val| + new_key = key.is_a?(String) ? key.dup.force_encoding(Encoding::UTF_8).encode! : key + new_hash[new_key] = if val.is_a?(Array) + val.map! { |el| normalize_encode_params(el) } + else + normalize_encode_params(val) + end end new_hash.with_indifferent_access end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index ebd87c40b5..4ca1d35489 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -22,6 +22,7 @@ module ActionDispatch include ActionDispatch::Http::URL autoload :Session, 'action_dispatch/request/session' + autoload :Utils, 'action_dispatch/request/utils' LOCALHOST = Regexp.union [/^127\.0\.0\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/] @@ -299,26 +300,10 @@ module ActionDispatch LOCALHOST =~ remote_addr && LOCALHOST =~ remote_ip end - # Remove nils from the params hash - def deep_munge(hash) - hash.each do |k, v| - case v - when Array - v.grep(Hash) { |x| deep_munge(x) } - v.compact! - hash[k] = nil if v.empty? - when Hash - deep_munge(v) - end - end - - hash - end - protected def parse_query(qs) - deep_munge(super) + Utils.deep_munge(super) end private diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 60a2cccdc5..5697282791 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -31,10 +31,17 @@ module ActionDispatch # :nodoc: # end # end class Response - attr_accessor :request, :header + # The request that the response is responding to. + attr_accessor :request + + # The HTTP status code. attr_reader :status + attr_writer :sending_file + # Get and set headers for this response. + attr_accessor :header + alias_method :headers=, :header= alias_method :headers, :header @@ -49,9 +56,12 @@ module ActionDispatch # :nodoc: # If a character set has been defined for this response (see charset=) then # the character set information will also be included in the content type # information. - attr_accessor :charset attr_reader :content_type + # The charset of the response. HTML wants to know the encoding of the + # content you're giving them, so we need to send that along. + attr_accessor :charset + CONTENT_TYPE = "Content-Type".freeze SET_COOKIE = "Set-Cookie".freeze LOCATION = "Location".freeze @@ -93,6 +103,7 @@ module ActionDispatch # :nodoc: end end + # The underlying body, as a streamable object. attr_reader :stream def initialize(status = 200, header = {}, body = []) @@ -142,6 +153,7 @@ module ActionDispatch # :nodoc: @status = Rack::Utils.status_code(status) end + # Sets the HTTP content type. def content_type=(content_type) @content_type = content_type.to_s end @@ -216,11 +228,13 @@ module ActionDispatch # :nodoc: ::Rack::Utils.delete_cookie_header!(header, key, value) end + # The location header we'll be responding with. def location headers[LOCATION] end alias_method :redirect_url, :location + # Sets the location header we'll be responding with. def location=(url) headers[LOCATION] = url end @@ -229,11 +243,13 @@ module ActionDispatch # :nodoc: stream.close if stream.respond_to?(:close) end + # Turns the Response into a Rack-compatible array of the status, headers, + # and body. def to_a rack_response @status, @header.to_hash end alias prepare! to_a - alias to_ary to_a # For implicit splat on 1.9.2 + alias to_ary to_a # Returns the response cookies, converted to a Hash of (name => value) pairs # diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb index 419e665d12..da32f1bfe7 100644 --- a/actionpack/lib/action_dispatch/journey/router.rb +++ b/actionpack/lib/action_dispatch/journey/router.rb @@ -54,7 +54,7 @@ module ActionDispatch end def call(env) - env['PATH_INFO'] = Utils.normalize_path(env['PATH_INFO']) + env['PATH_INFO'] = normalize_path(env['PATH_INFO']) find_routes(env).each do |match, parameters, route| script_name, path_info, set_params = env.values_at('SCRIPT_NAME', @@ -103,6 +103,12 @@ module ActionDispatch private + def normalize_path(path) + path = "/#{path}" + path.squeeze!('/') + path + end + def partitioned_routes routes.partitioned_routes end diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 5b914f293d..d055acb296 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -77,7 +77,7 @@ module ActionDispatch # domain and subdomains. # # * <tt>:expires</tt> - The time at which this cookie expires, as a \Time object. - # * <tt>:secure</tt> - Whether this cookie is a only transmitted to HTTPS servers. + # * <tt>:secure</tt> - Whether this cookie is only transmitted to HTTPS servers. # Default is +false+. # * <tt>:httponly</tt> - Whether this cookie is accessible via scripting or # only HTTP. Defaults to +false+. diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index 0fa1e9b859..fb70b60ef6 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -43,7 +43,7 @@ module ActionDispatch when :json data = ActiveSupport::JSON.decode(request.body) data = {:_json => data} unless data.is_a?(Hash) - request.deep_munge(data).with_indifferent_access + Request::Utils.deep_munge(data).with_indifferent_access else false end diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb index 9e03cbf2b7..8d5ab19f60 100644 --- a/actionpack/lib/action_dispatch/middleware/ssl.rb +++ b/actionpack/lib/action_dispatch/middleware/ssl.rb @@ -36,8 +36,7 @@ module ActionDispatch url.scheme = "https" url.host = @host if @host url.port = @port if @port - headers = hsts_headers.merge('Content-Type' => 'text/html', - 'Location' => url.to_s) + headers = { 'Content-Type' => 'text/html', 'Location' => url.to_s } [301, headers, []] end @@ -58,7 +57,7 @@ module ActionDispatch cookies = cookies.split("\n") headers['Set-Cookie'] = cookies.map { |cookie| - if cookie !~ /;\s+secure(;|$)/ + if cookie !~ /;\s+secure(;|$)/i "#{cookie}; secure" else cookie diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index edf37bb9a5..2dfaab3587 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -20,8 +20,7 @@ module ActionDispatch config.action_dispatch.default_headers = { 'X-Frame-Options' => 'SAMEORIGIN', 'X-XSS-Protection' => '1; mode=block', - 'X-Content-Type-Options' => 'nosniff', - 'X-UA-Compatible' => 'chrome=1' + 'X-Content-Type-Options' => 'nosniff' } config.eager_load_namespaces << ActionDispatch diff --git a/actionpack/lib/action_dispatch/request/utils.rb b/actionpack/lib/action_dispatch/request/utils.rb new file mode 100644 index 0000000000..8b43cdada8 --- /dev/null +++ b/actionpack/lib/action_dispatch/request/utils.rb @@ -0,0 +1,24 @@ +module ActionDispatch + class Request < Rack::Request + class Utils # :nodoc: + class << self + # Remove nils from the params hash + def deep_munge(hash) + hash.each do |k, v| + case v + when Array + v.grep(Hash) { |x| deep_munge(x) } + v.compact! + hash[k] = nil if v.empty? + when Hash + deep_munge(v) + end + end + + hash + end + end + end + end +end + diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb index 550c7d0e7b..a9ac2bce1d 100644 --- a/actionpack/lib/action_dispatch/routing.rb +++ b/actionpack/lib/action_dispatch/routing.rb @@ -246,11 +246,13 @@ module ActionDispatch # Target specific controllers by prefixing the command with <tt>CONTROLLER=x</tt>. # module Routing - autoload :Mapper, 'action_dispatch/routing/mapper' - autoload :RouteSet, 'action_dispatch/routing/route_set' - autoload :RoutesProxy, 'action_dispatch/routing/routes_proxy' - autoload :UrlFor, 'action_dispatch/routing/url_for' - autoload :PolymorphicRoutes, 'action_dispatch/routing/polymorphic_routes' + extend ActiveSupport::Autoload + + autoload :Mapper + autoload :RouteSet + autoload :RoutesProxy + autoload :UrlFor + autoload :PolymorphicRoutes SEPARATORS = %w( / . ? ) #:nodoc: HTTP_METHODS = [:get, :head, :post, :patch, :put, :delete, :options] #:nodoc: diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb index d251de33df..cffb814e1e 100644 --- a/actionpack/lib/action_dispatch/routing/inspector.rb +++ b/actionpack/lib/action_dispatch/routing/inspector.rb @@ -69,7 +69,7 @@ module ActionDispatch end def internal? - controller =~ %r{\Arails/(info|welcome)} || path =~ %r{\A#{Rails.application.config.assets.prefix}} + controller.to_s =~ %r{\Arails/(info|welcome)} || path =~ %r{\A#{Rails.application.config.assets.prefix}} end def engine? diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 3c58a2cfc3..288ce3e867 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -11,8 +11,8 @@ module ActionDispatch class Mapper URL_OPTIONS = [:protocol, :subdomain, :domain, :host, :port] SCOPE_OPTIONS = [:path, :shallow_path, :as, :shallow_prefix, :module, - :controller, :path_names, :constraints, :defaults, - :shallow, :blocks, :options] + :controller, :action, :path_names, :constraints, + :shallow, :blocks, :defaults, :options] class Constraints #:nodoc: def self.new(app, constraints, request = Rack::Request) @@ -874,6 +874,10 @@ module ActionDispatch child end + def merge_action_scope(parent, child) #:nodoc: + child + end + def merge_path_names_scope(parent, child) #:nodoc: merge_options_scope(parent, child) end @@ -1383,6 +1387,10 @@ module ActionDispatch raise ArgumentError, "Unknown scope #{on.inspect} given to :on" end + if @scope[:controller] && @scope[:action] + options[:to] ||= "#{@scope[:controller]}##{@scope[:action]}" + end + paths.each do |_path| route_options = options.dup route_options[:path] ||= _path if _path.is_a?(String) diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb deleted file mode 100644 index edff98ddaa..0000000000 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ /dev/null @@ -1,117 +0,0 @@ -require 'action_view/helpers/tag_helper' - -module ActionView - module Helpers - module JavaScriptHelper - JS_ESCAPE_MAP = { - '\\' => '\\\\', - '</' => '<\/', - "\r\n" => '\n', - "\n" => '\n', - "\r" => '\n', - '"' => '\\"', - "'" => "\\'" - } - - JS_ESCAPE_MAP["\342\200\250".force_encoding(Encoding::UTF_8).encode!] = '
' - JS_ESCAPE_MAP["\342\200\251".force_encoding(Encoding::UTF_8).encode!] = '
' - - # Escapes carriage returns and single and double quotes for JavaScript segments. - # - # Also available through the alias j(). This is particularly helpful in JavaScript - # responses, like: - # - # $('some_element').replaceWith('<%=j render 'some/element_template' %>'); - def escape_javascript(javascript) - if javascript - result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] } - javascript.html_safe? ? result.html_safe : result - else - '' - end - end - - alias_method :j, :escape_javascript - - # Returns a JavaScript tag with the +content+ inside. Example: - # javascript_tag "alert('All is good')" - # - # Returns: - # <script> - # //<![CDATA[ - # alert('All is good') - # //]]> - # </script> - # - # +html_options+ may be a hash of attributes for the <tt>\<script></tt> - # tag. - # - # javascript_tag "alert('All is good')", defer: 'defer' - # # => <script defer="defer">alert('All is good')</script> - # - # Instead of passing the content as an argument, you can also use a block - # in which case, you pass your +html_options+ as the first parameter. - # - # <%= javascript_tag defer: 'defer' do -%> - # alert('All is good') - # <% end -%> - def javascript_tag(content_or_options_with_block = nil, html_options = {}, &block) - content = - if block_given? - html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) - capture(&block) - else - content_or_options_with_block - end - - content_tag(:script, javascript_cdata_section(content), html_options) - end - - def javascript_cdata_section(content) #:nodoc: - "\n//#{cdata_section("\n#{content}\n//")}\n".html_safe - end - - # Returns a button whose +onclick+ handler triggers the passed JavaScript. - # - # The helper receives a name, JavaScript code, and an optional hash of HTML options. The - # name is used as button label and the JavaScript code goes into its +onclick+ attribute. - # If +html_options+ has an <tt>:onclick</tt>, that one is put before +function+. - # - # button_to_function "Greeting", "alert('Hello world!')", class: "ok" - # # => <input class="ok" onclick="alert('Hello world!');" type="button" value="Greeting" /> - # - def button_to_function(name, function=nil, html_options={}) - message = "button_to_function is deprecated and will be removed from Rails 4.1. We recommend using Unobtrusive JavaScript instead. " + - "See http://guides.rubyonrails.org/working_with_javascript_in_rails.html#unobtrusive-javascript" - ActiveSupport::Deprecation.warn message - - onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};" - - tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick)) - end - - # Returns a link whose +onclick+ handler triggers the passed JavaScript. - # - # The helper receives a name, JavaScript code, and an optional hash of HTML options. The - # name is used as the link text and the JavaScript code goes into the +onclick+ attribute. - # If +html_options+ has an <tt>:onclick</tt>, that one is put before +function+. Once all - # the JavaScript is set, the helper appends "; return false;". - # - # The +href+ attribute of the tag is set to "#" unless +html_options+ has one. - # - # link_to_function "Greeting", "alert('Hello world!')", class: "nav_link" - # # => <a class="nav_link" href="#" onclick="alert('Hello world!'); return false;">Greeting</a> - # - def link_to_function(name, function, html_options={}) - message = "link_to_function is deprecated and will be removed from Rails 4.1. We recommend using Unobtrusive JavaScript instead. " + - "See http://guides.rubyonrails.org/working_with_javascript_in_rails.html#unobtrusive-javascript" - ActiveSupport::Deprecation.warn message - - onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;" - href = html_options[:href] || '#' - - content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick)) - end - end - end -end diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index d4f18d55a6..b2bfdae174 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -61,10 +61,7 @@ class UrlOptionsController < ActionController::Base end end -class RecordIdentifierController < ActionController::Base -end - -class RecordIdentifierWithoutDeprecationController < ActionController::Base +class RecordIdentifierIncludedController < ActionController::Base include ActionView::RecordIdentifier end @@ -88,43 +85,20 @@ class ControllerClassTests < ActiveSupport::TestCase assert_equal 'contained_empty', Submodule::ContainedEmptyController.controller_name end - def test_record_identifier - assert_respond_to RecordIdentifierController.new, :dom_id - assert_respond_to RecordIdentifierController.new, :dom_class - end - - def test_record_identifier_is_deprecated - record = Comment.new - record.save - - dom_id = nil - assert_deprecated 'dom_id method will no longer' do - dom_id = RecordIdentifierController.new.dom_id(record) - end - - assert_equal 'comment_1', dom_id - - dom_class = nil - assert_deprecated 'dom_class method will no longer' do - dom_class = RecordIdentifierController.new.dom_class(record) - end - assert_equal 'comment', dom_class - end - def test_no_deprecation_when_action_view_record_identifier_is_included record = Comment.new record.save dom_id = nil assert_not_deprecated do - dom_id = RecordIdentifierWithoutDeprecationController.new.dom_id(record) + dom_id = RecordIdentifierIncludedController.new.dom_id(record) end assert_equal 'comment_1', dom_id dom_class = nil assert_not_deprecated do - dom_class = RecordIdentifierWithoutDeprecationController.new.dom_class(record) + dom_class = RecordIdentifierIncludedController.new.dom_class(record) end assert_equal 'comment', dom_class end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index ca86837a2c..e521c6ce96 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -1,6 +1,5 @@ require 'fileutils' require 'abstract_unit' -require 'active_record_unit' CACHE_DIR = 'test_cache' # Don't change '/../temp/' cavalierly or you might hose something you don't want hosed diff --git a/actionpack/test/controller/record_identifier_test.rb b/actionpack/test/controller/record_identifier_test.rb deleted file mode 100644 index ff5d7fd3bd..0000000000 --- a/actionpack/test/controller/record_identifier_test.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'abstract_unit' -require 'controller/fake_models' - -class ControllerRecordIdentifierTest < ActiveSupport::TestCase - include ActionController::RecordIdentifier - - def setup - @record = Comment.new - end - - def test_dom_id_deprecation - assert_deprecated(/dom_id method will no longer be included by default in controllers/) do - dom_id(@record) - end - end - - def test_dom_class_deprecation - assert_deprecated(/dom_class method will no longer be included by default in controllers/) do - dom_class(@record) - end - end - - def test_dom_id_from_module_deprecation - assert_deprecated(/Calling ActionController::RecordIdentifier.dom_id is deprecated/) do - ActionController::RecordIdentifier.dom_id(@record) - end - end - - def test_dom_class_from_module_deprecation - assert_deprecated(/Calling ActionController::RecordIdentifier.dom_class is deprecated/) do - ActionController::RecordIdentifier.dom_class(@record) - end - end -end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 72411ec900..fd835795c0 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1089,6 +1089,12 @@ class RenderTest < ActionController::TestCase assert_equal '<test>passed formatted html erb</test>', @response.body end + def test_should_render_formatted_html_erb_template_with_bad_accepts_header + @request.env["HTTP_ACCEPT"] = "; a=dsf" + get :formatted_xml_erb + assert_equal '<test>passed formatted html erb</test>', @response.body + end + def test_should_render_formatted_html_erb_template_with_faulty_accepts_header @request.accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, appliction/x-shockwave-flash, */*" get :formatted_xml_erb diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 6a2eb7da9f..8a19129695 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -185,11 +185,6 @@ class MimeTypeTest < ActiveSupport::TestCase all_types.uniq! # Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE all_types.delete_if { |type| !Mime.const_defined?(type.upcase) } - assert_deprecated do - verified, unverified = all_types.partition { |type| Mime::Type.browser_generated_types.include? type } - assert verified.each { |type| assert Mime.const_get(type.upcase).verify_request?, "Verifiable Mime Type is not verified: #{type.inspect}" } - assert unverified.each { |type| assert !Mime.const_get(type.upcase).verify_request?, "Nonverifiable Mime Type is verified: #{type.inspect}" } - end end test "references gives preference to symbols before strings" do diff --git a/actionpack/test/dispatch/mount_test.rb b/actionpack/test/dispatch/mount_test.rb index e5e28c28be..30e95a0b75 100644 --- a/actionpack/test/dispatch/mount_test.rb +++ b/actionpack/test/dispatch/mount_test.rb @@ -33,6 +33,11 @@ class TestRoutingMount < ActionDispatch::IntegrationTest Router end + def test_trailing_slash_is_not_removed_from_path_info + get "/sprockets/omg/" + assert_equal "/sprockets -- /omg/", response.body + end + def test_mounting_sets_script_name get "/sprockets/omg" assert_equal "/sprockets -- /omg", response.body diff --git a/actionpack/test/dispatch/rack_test.rb b/actionpack/test/dispatch/rack_test.rb index 6d239d0a0c..42067854ee 100644 --- a/actionpack/test/dispatch/rack_test.rb +++ b/actionpack/test/dispatch/rack_test.rb @@ -174,22 +174,6 @@ class RackRequestParamsParsingTest < BaseRackTest end end -class RackRequestContentTypeTest < BaseRackTest - test "html content type verification" do - assert_deprecated do - @request.env['CONTENT_TYPE'] = Mime::HTML.to_s - assert @request.content_mime_type.verify_request? - end - end - - test "xml content type verification" do - assert_deprecated do - @request.env['CONTENT_TYPE'] = Mime::XML.to_s - assert !@request.content_mime_type.verify_request? - end - end -end - class RackRequestNeedsRewoundTest < BaseRackTest test "body should be rewound" do data = 'foo' diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb index 74f5253c11..2fbe7358f9 100644 --- a/actionpack/test/dispatch/response_test.rb +++ b/actionpack/test/dispatch/response_test.rb @@ -182,8 +182,7 @@ class ResponseTest < ActiveSupport::TestCase ActionDispatch::Response.default_headers = { 'X-Frame-Options' => 'DENY', 'X-Content-Type-Options' => 'nosniff', - 'X-XSS-Protection' => '1;', - 'X-UA-Compatible' => 'chrome=1' + 'X-XSS-Protection' => '1;' } resp = ActionDispatch::Response.new.tap { |response| response.body = 'Hello' @@ -193,7 +192,6 @@ class ResponseTest < ActiveSupport::TestCase assert_equal('DENY', resp.headers['X-Frame-Options']) assert_equal('nosniff', resp.headers['X-Content-Type-Options']) assert_equal('1;', resp.headers['X-XSS-Protection']) - assert_equal('chrome=1', resp.headers['X-UA-Compatible']) ensure ActionDispatch::Response.default_headers = nil end diff --git a/actionpack/test/dispatch/routing/inspector_test.rb b/actionpack/test/dispatch/routing/inspector_test.rb index 234ae5764f..4f97d28d2b 100644 --- a/actionpack/test/dispatch/routing/inspector_test.rb +++ b/actionpack/test/dispatch/routing/inspector_test.rb @@ -234,6 +234,15 @@ module ActionDispatch " PUT /posts/:id(.:format) posts#update", " DELETE /posts/:id(.:format) posts#destroy"], output end + + def test_regression_route_with_controller_regexp + output = draw do + get ':controller(/:action)', controller: /api\/[^\/]+/, format: false + end + + assert_equal ["Prefix Verb URI Pattern Controller#Action", + " GET /:controller(/:action) (?-mix:api\\/[^\\/]+)#:action"], output + end end end end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 16ba746b9c..8e4339aa0c 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -1253,6 +1253,19 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal 'api/v3/products#list', @response.body end + def test_controller_option_with_nesting_and_leading_slash + draw do + scope '/job', controller: 'job' do + scope ':id', action: 'manage_applicant' do + get "/active" + end + end + end + + get '/job/5/active' + assert_equal 'job#manage_applicant', @response.body + end + def test_dynamically_generated_helpers_on_collection_do_not_clobber_resources_url_helper draw do resources :replies do diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb index a9bea7ea73..61b55f3d82 100644 --- a/actionpack/test/dispatch/ssl_test.rb +++ b/actionpack/test/dispatch/ssl_test.rb @@ -37,6 +37,11 @@ class SSLTest < ActionDispatch::IntegrationTest response.headers['Strict-Transport-Security'] end + def test_no_hsts_with_insecure_connection + get "http://example.org/" + assert_not response.headers['Strict-Transport-Security'] + end + def test_hsts_header self.app = ActionDispatch::SSL.new(default_app, :hsts => true) get "https://example.org/" @@ -119,6 +124,20 @@ class SSLTest < ActionDispatch::IntegrationTest response.headers['Set-Cookie'].split("\n") end + def test_flag_cookies_as_secure_with_ignore_case + self.app = ActionDispatch::SSL.new(lambda { |env| + headers = { + 'Content-Type' => "text/html", + 'Set-Cookie' => "problem=def; path=/; Secure; HttpOnly" + } + [200, headers, ["OK"]] + }) + + get "https://example.org/" + assert_equal ["problem=def; path=/; Secure; HttpOnly"], + response.headers['Set-Cookie'].split("\n") + end + def test_no_cookies self.app = ActionDispatch::SSL.new(lambda { |env| [200, {'Content-Type' => "text/html"}, ["OK"]] diff --git a/actionpack/test/template/dependency_tracker_test.rb b/actionpack/test/template/dependency_tracker_test.rb deleted file mode 100644 index 9c68afbdbd..0000000000 --- a/actionpack/test/template/dependency_tracker_test.rb +++ /dev/null @@ -1,46 +0,0 @@ -require 'abstract_unit' -require 'action_view/dependency_tracker' - -class DependencyTrackerTest < ActionView::TestCase - Neckbeard = lambda {|template| template.source } - Bowtie = lambda {|template| template.source } - - class NeckbeardTracker - def self.call(name, template) - ["foo/#{name}"] - end - end - - class FakeTemplate - attr_reader :source, :handler - - def initialize(source, handler = Neckbeard) - @source, @handler = source, handler - end - end - - def tracker - ActionView::DependencyTracker - end - - def setup - ActionView::Template.register_template_handler :neckbeard, Neckbeard - tracker.register_tracker(:neckbeard, NeckbeardTracker) - end - - def teardown - tracker.remove_tracker(:neckbeard) - end - - def test_finds_tracker_by_template_handler - template = FakeTemplate.new("boo/hoo") - dependencies = tracker.find_dependencies("boo/hoo", template) - assert_equal ["foo/boo/hoo"], dependencies - end - - def test_returns_empty_array_if_no_tracker_is_found - template = FakeTemplate.new("boo/hoo", Bowtie) - dependencies = tracker.find_dependencies("boo/hoo", template) - assert_equal [], dependencies - end -end diff --git a/actionpack/test/ts_isolated.rb b/actionpack/test/ts_isolated.rb deleted file mode 100644 index 55620abe84..0000000000 --- a/actionpack/test/ts_isolated.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'active_support/testing/autorun' -require 'rbconfig' -require 'abstract_unit' - -class TestIsolated < ActiveSupport::TestCase - ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME')) - - Dir["#{File.dirname(__FILE__)}/{abstract,controller,dispatch,template}/**/*_test.rb"].each do |file| - define_method("test #{file}") do - command = "#{ruby} -Ilib:test #{file}" - result = silence_stderr { `#{command}` } - assert $?.to_i.zero?, "#{command}\n#{result}" - end - end -end diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md new file mode 100644 index 0000000000..31e123d916 --- /dev/null +++ b/actionview/CHANGELOG.md @@ -0,0 +1,56 @@ +* Always escape the result of `link_to_unless` method. + + Before: + + link_to_unless(true, '<b>Showing</b>', 'github.com') + # => "<b>Showing</b>" + + After: + + link_to_unless(true, '<b>Showing</b>', 'github.com') + # => "<b>Showing</b>" + + *dtaniwaki* + +* Use a case insensitive URI Regexp for #asset_path. + + This fix a problem where the same asset path using different case are generating + different URIs. + + Before: + + image_tag("HTTP://google.com") + # => "<img alt=\"Google\" src=\"/assets/HTTP://google.com\" />" + image_tag("http://google.com") + # => "<img alt=\"Google\" src=\"http://google.com\" />" + + After: + + image_tag("HTTP://google.com") + # => "<img alt=\"Google\" src=\"HTTP://google.com\" />" + image_tag("http://google.com") + # => "<img alt=\"Google\" src=\"http://google.com\" />" + + *David Celis* + +* Element of the `collection_check_boxes` and `collection_radio_buttons` can + optionally contain html attributes as the last element of the array. + + *Vasiliy Ermolovich* + +* Update the HTML `BOOLEAN_ATTRIBUTES` in `ActionView::Helpers::TagHelper` + to conform to the latest HTML 5.1 spec. Add attributes `allowfullscreen`, + `default`, `inert`, `sortable`, `truespeed`, `typemustmatch`. Fix attribute + `seamless` (previously misspelled `seemless`). + + *Alex Peattie* + +* Fix an issue where partials with a number in the filename weren't being digested for cache dependencies. + + *Bryan Ricker* + +* First release, ActionView extracted from ActionPack + + *Piotr Sarnacki*, *Łukasz Strzałkowski* + +Please check [4-0-stable (ActionPack's CHANGELOG)](https://github.com/rails/rails/blob/4-0-stable/actionpack/CHANGELOG.md) for previous changes. diff --git a/actionview/MIT-LICENSE b/actionview/MIT-LICENSE new file mode 100644 index 0000000000..810daf856c --- /dev/null +++ b/actionview/MIT-LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2004-2012 David Heinemeier Hansson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/actionview/README.rdoc b/actionview/README.rdoc new file mode 100644 index 0000000000..09bbfdae0b --- /dev/null +++ b/actionview/README.rdoc @@ -0,0 +1,31 @@ += Action View + + + +== Download and installation + +The latest version of Action View can be installed with RubyGems: + + % [sudo] gem install actionview + +Source code can be downloaded as part of the Rails project on GitHub + +* https://github.com/rails/rails/tree/master/actionview + + +== License + +Action View is released under the MIT license: + +* http://www.opensource.org/licenses/MIT + + +== Support + +API documentation is at + +* http://api.rubyonrails.org + +Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here: + +* https://github.com/rails/rails/issues diff --git a/actionview/RUNNING_UNIT_TESTS b/actionview/RUNNING_UNIT_TESTS new file mode 100644 index 0000000000..a0c35e1810 --- /dev/null +++ b/actionview/RUNNING_UNIT_TESTS @@ -0,0 +1,27 @@ +== Running with Rake + +The easiest way to run the unit tests is through Rake. The default task runs +the entire test suite for all classes. For more information, checkout the +full array of rake tasks with "rake -T" + +Rake can be found at http://rake.rubyforge.org + +== Running by hand + +To run a single test suite + + rake test TEST=path/to/test.rb + +which can be further narrowed down to one test: + + rake test TEST=path/to/test.rb TESTOPTS="--name=test_something" + +== Dependency on Active Record and database setup + +Test cases in the test/active_record/ directory depend on having +activerecord and sqlite installed. If Active Record is not in +actionview/../activerecord directory, or the sqlite rubygem is not installed, +these tests are skipped. + +Other tests are runnable from a fresh copy of actionview without any configuration. + diff --git a/actionview/Rakefile b/actionview/Rakefile new file mode 100644 index 0000000000..ee670b5cc0 --- /dev/null +++ b/actionview/Rakefile @@ -0,0 +1,81 @@ +require 'rake/testtask' +require 'rake/packagetask' +require 'rubygems/package_task' + +desc "Default Task" +task :default => :test + +# Run the unit tests + +desc "Run all unit tests" +task :test => [:test_action_view, :test_active_record_integration] + +Rake::TestTask.new(:test_action_view) do |t| + t.libs << 'test' + + # make sure we include the tests in alphabetical order as on some systems + # this will not happen automatically and the tests (as a whole) will error + t.test_files = Dir.glob('test/template/**/*_test.rb').sort + + t.warning = true + t.verbose = true +end + +namespace :test do + task :isolated do + ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME')) + Dir.glob("test/{active_record,template}/**/*_test.rb").all? do |file| + sh(ruby, '-w', '-Ilib:test', file) + end or raise "Failures" + end + + Rake::TestTask.new(:template) do |t| + t.libs << 'test' + t.pattern = 'test/template/**/*.rb' + end +end + +desc 'ActiveRecord Integration Tests' +Rake::TestTask.new(:test_active_record_integration) do |t| + t.libs << 'test' + t.test_files = Dir.glob("test/activerecord/*_test.rb") + t.warning = true + t.verbose = true +end + +spec = eval(File.read('actionview.gemspec')) + +Gem::PackageTask.new(spec) do |p| + p.gem_spec = spec +end + +desc "Release to rubygems" +task :release => :package do + require 'rake/gemcutter' + Rake::Gemcutter::Tasks.new(spec).define + Rake::Task['gem:push'].invoke +end + +task :lines do + lines, codelines, total_lines, total_codelines = 0, 0, 0, 0 + + FileList["lib/**/*.rb"].each do |file_name| + next if file_name =~ /vendor/ + File.open(file_name, 'r') do |f| + while line = f.gets + lines += 1 + next if line =~ /^\s*$/ + next if line =~ /^\s*#/ + codelines += 1 + end + end + puts "L: #{sprintf("%4d", lines)}, LOC #{sprintf("%4d", codelines)} | #{file_name}" + + total_lines += lines + total_codelines += codelines + + lines, codelines = 0, 0 + end + + puts "Total: Lines #{total_lines}, LOC #{total_codelines}" +end diff --git a/actionview/actionview.gemspec b/actionview/actionview.gemspec new file mode 100644 index 0000000000..87cb568300 --- /dev/null +++ b/actionview/actionview.gemspec @@ -0,0 +1,29 @@ +version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip + +Gem::Specification.new do |s| + s.platform = Gem::Platform::RUBY + s.name = 'actionview' + s.version = version + s.summary = 'Rendering framework putting the V in MVC (part of Rails).' + s.description = '' + + s.required_ruby_version = '>= 1.9.3' + + s.license = 'MIT' + + s.author = 'David Heinemeier Hansson' + s.email = 'david@loudthinking.com' + s.homepage = 'http://www.rubyonrails.org' + + s.files = Dir['CHANGELOG.md', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*'] + s.require_path = 'lib' + s.requirements << 'none' + + s.add_dependency 'activesupport', version + s.add_dependency 'activemodel', version + + s.add_dependency 'builder', '~> 3.1.0' + s.add_dependency 'erubis', '~> 2.7.0' + + s.add_development_dependency 'actionpack', version +end diff --git a/actionpack/lib/action_view.rb b/actionview/lib/action_view.rb index 4aafbcb655..8def4ba7c5 100644 --- a/actionpack/lib/action_view.rb +++ b/actionview/lib/action_view.rb @@ -23,7 +23,6 @@ require 'active_support' require 'active_support/rails' -require 'action_pack' module ActionView extend ActiveSupport::Autoload diff --git a/actionpack/lib/action_view/base.rb b/actionview/lib/action_view/base.rb index 08253de3f4..08253de3f4 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionview/lib/action_view/base.rb diff --git a/actionpack/lib/action_view/buffers.rb b/actionview/lib/action_view/buffers.rb index 361a0dccbe..361a0dccbe 100644 --- a/actionpack/lib/action_view/buffers.rb +++ b/actionview/lib/action_view/buffers.rb diff --git a/actionpack/lib/action_view/context.rb b/actionview/lib/action_view/context.rb index ee263df484..ee263df484 100644 --- a/actionpack/lib/action_view/context.rb +++ b/actionview/lib/action_view/context.rb diff --git a/actionpack/lib/action_view/dependency_tracker.rb b/actionview/lib/action_view/dependency_tracker.rb index 45d17be605..b2e8334077 100644 --- a/actionpack/lib/action_view/dependency_tracker.rb +++ b/actionview/lib/action_view/dependency_tracker.rb @@ -74,7 +74,7 @@ module ActionView # render(@topic) => render("topics/topic") # render(topics) => render("topics/topic") # render(message.topics) => render("topics/topic") - collect { |name| name.sub(/\A@?([a-z]+\.)*([a-z_]+)\z/) { "#{$2.pluralize}/#{$2.singularize}" } }. + collect { |name| name.sub(/\A@?([a-z_]+\.)*([a-z_]+)\z/) { "#{$2.pluralize}/#{$2.singularize}" } }. # render("headline") => render("message/headline") collect { |name| name.include?("/") ? name : "#{directory}/#{name}" }. diff --git a/actionpack/lib/action_view/digestor.rb b/actionview/lib/action_view/digestor.rb index 9324a1ac50..9324a1ac50 100644 --- a/actionpack/lib/action_view/digestor.rb +++ b/actionview/lib/action_view/digestor.rb diff --git a/actionpack/lib/action_view/flows.rb b/actionview/lib/action_view/flows.rb index c0e458cd41..ba24510e56 100644 --- a/actionpack/lib/action_view/flows.rb +++ b/actionview/lib/action_view/flows.rb @@ -36,7 +36,7 @@ module ActionView @root = Fiber.current.object_id end - # Try to get an stored content. If the content + # Try to get stored content. If the content # is not available and we are inside the layout # fiber, we set that we are waiting for the given # key and yield. @@ -73,4 +73,4 @@ module ActionView Fiber.current.object_id != @root end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_view/helpers.rb b/actionview/lib/action_view/helpers.rb index 8a78685ae1..8a78685ae1 100644 --- a/actionpack/lib/action_view/helpers.rb +++ b/actionview/lib/action_view/helpers.rb diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionview/lib/action_view/helpers/active_model_helper.rb index 901f433c70..901f433c70 100644 --- a/actionpack/lib/action_view/helpers/active_model_helper.rb +++ b/actionview/lib/action_view/helpers/active_model_helper.rb diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionview/lib/action_view/helpers/asset_tag_helper.rb index 3a6f449eb8..2b3a3c6a29 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionview/lib/action_view/helpers/asset_tag_helper.rb @@ -127,11 +127,7 @@ module ActionView # # => <link rel="alternate" type="application/rss+xml" title="Example RSS" href="http://www.example.com/feed" /> def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {}) if !(type == :rss || type == :atom) && tag_options[:type].blank? - message = "You have passed type other than :rss or :atom to auto_discovery_link_tag and haven't supplied " + - "the :type option key. This behavior is deprecated and will be remove in Rails 4.1. You should pass " + - ":type option explicitly if you want to use other types, for example: " + - "auto_discovery_link_tag(:xml, '/feed.xml', :type => 'application/xml')" - ActiveSupport::Deprecation.warn message + raise ArgumentError.new("You should pass :type tag_option key explicitly, because you have passed #{type} type other than :rss or :atom.") end tag( diff --git a/actionpack/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb index b5f2df76ab..0b957adb91 100644 --- a/actionpack/lib/action_view/helpers/asset_url_helper.rb +++ b/actionview/lib/action_view/helpers/asset_url_helper.rb @@ -105,7 +105,7 @@ module ActionView # ) # module AssetUrlHelper - URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//} + URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}i # Computes the path to asset in public directory. If :type # options is set, a file extension will be appended and scoped diff --git a/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/actionview/lib/action_view/helpers/atom_feed_helper.rb index 42b1dd8933..42b1dd8933 100644 --- a/actionpack/lib/action_view/helpers/atom_feed_helper.rb +++ b/actionview/lib/action_view/helpers/atom_feed_helper.rb diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb index 8fc78ea7fb..2a38e5c446 100644 --- a/actionpack/lib/action_view/helpers/cache_helper.rb +++ b/actionview/lib/action_view/helpers/cache_helper.rb @@ -176,20 +176,24 @@ module ActionView # TODO: Create an object that has caching read/write on it def fragment_for(name = {}, options = nil, &block) #:nodoc: - if fragment = controller.read_fragment(name, options) - fragment - else - # VIEW TODO: Make #capture usable outside of ERB - # This dance is needed because Builder can't use capture - pos = output_buffer.length - yield - output_safe = output_buffer.html_safe? - fragment = output_buffer.slice!(pos..-1) - if output_safe - self.output_buffer = output_buffer.class.new(output_buffer) - end - controller.write_fragment(name, fragment, options) + read_fragment_for(name, options) || write_fragment_for(name, options, &block) + end + + def read_fragment_for(name, options) #:nodoc: + controller.read_fragment(name, options) + end + + def write_fragment_for(name, options) #:nodoc: + # VIEW TODO: Make #capture usable outside of ERB + # This dance is needed because Builder can't use capture + pos = output_buffer.length + yield + output_safe = output_buffer.html_safe? + fragment = output_buffer.slice!(pos..-1) + if output_safe + self.output_buffer = output_buffer.class.new(output_buffer) end + controller.write_fragment(name, fragment, options) end end end diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionview/lib/action_view/helpers/capture_helper.rb index 5afe435459..5afe435459 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionview/lib/action_view/helpers/capture_helper.rb diff --git a/actionpack/lib/action_view/helpers/controller_helper.rb b/actionview/lib/action_view/helpers/controller_helper.rb index 74ef25f7c1..74ef25f7c1 100644 --- a/actionpack/lib/action_view/helpers/controller_helper.rb +++ b/actionview/lib/action_view/helpers/controller_helper.rb diff --git a/actionpack/lib/action_view/helpers/csrf_helper.rb b/actionview/lib/action_view/helpers/csrf_helper.rb index eeb0ed94b9..eeb0ed94b9 100644 --- a/actionpack/lib/action_view/helpers/csrf_helper.rb +++ b/actionview/lib/action_view/helpers/csrf_helper.rb diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb index 8fb5eb1548..8fb5eb1548 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionview/lib/action_view/helpers/date_helper.rb diff --git a/actionpack/lib/action_view/helpers/debug_helper.rb b/actionview/lib/action_view/helpers/debug_helper.rb index c29c1b1eea..c29c1b1eea 100644 --- a/actionpack/lib/action_view/helpers/debug_helper.rb +++ b/actionview/lib/action_view/helpers/debug_helper.rb diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb index 36dedf0676..f64c0ca30b 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionview/lib/action_view/helpers/form_helper.rb @@ -692,7 +692,7 @@ module ActionView # # Note that fields_for will automatically generate a hidden field # to store the ID of the record. There are circumstances where this - # hidden field is not needed and you can pass <tt>hidden_field_id: false</tt> + # hidden field is not needed and you can pass <tt>include_id: false</tt> # to prevent fields_for from rendering it automatically. def fields_for(record_name, record_object = nil, options = {}, &block) builder = instantiate_builder(record_name, record_object, options) @@ -1507,7 +1507,7 @@ module ActionView # # Note that fields_for will automatically generate a hidden field # to store the ID of the record. There are circumstances where this - # hidden field is not needed and you can pass <tt>hidden_field_id: false</tt> + # hidden field is not needed and you can pass <tt>include_id: false</tt> # to prevent fields_for from rendering it automatically. def fields_for(record_name, record_object = nil, fields_options = {}, &block) fields_options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options? diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionview/lib/action_view/helpers/form_options_helper.rb index ad26505086..21f892f443 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionview/lib/action_view/helpers/form_options_helper.rb @@ -653,7 +653,7 @@ module ActionView # # Example object structure for use with this method: # class Post < ActiveRecord::Base - # has_and_belongs_to_many :author + # has_and_belongs_to_many :authors # end # class Author < ActiveRecord::Base # has_and_belongs_to_many :posts diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb index c10566a87d..3fa7696b83 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionview/lib/action_view/helpers/form_tag_helper.rb @@ -426,22 +426,6 @@ module ActionView def submit_tag(value = "Save changes", options = {}) options = options.stringify_keys - if disable_with = options.delete("disable_with") - message = ":disable_with option is deprecated and will be removed from Rails 4.1. " \ - "Use 'data: { disable_with: \'Text\' }' instead." - ActiveSupport::Deprecation.warn message - - options["data-disable-with"] = disable_with - end - - if confirm = options.delete("confirm") - message = ":confirm option is deprecated and will be removed from Rails 4.1. " \ - "Use 'data: { confirm: \'Text\' }' instead'." - ActiveSupport::Deprecation.warn message - - options["data-confirm"] = confirm - end - tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options) end @@ -488,22 +472,6 @@ module ActionView options ||= {} options = options.stringify_keys - if disable_with = options.delete("disable_with") - message = ":disable_with option is deprecated and will be removed from Rails 4.1. " \ - "Use 'data: { disable_with: \'Text\' }' instead." - ActiveSupport::Deprecation.warn message - - options["data-disable-with"] = disable_with - end - - if confirm = options.delete("confirm") - message = ":confirm option is deprecated and will be removed from Rails 4.1. " \ - "Use 'data: { confirm: \'Text\' }' instead'." - ActiveSupport::Deprecation.warn message - - options["data-confirm"] = confirm - end - options.reverse_merge! 'name' => 'button', 'type' => 'submit' content_tag :button, content_or_options || 'Button', options, &block @@ -541,15 +509,6 @@ module ActionView # # => <input alt="Save" src="/images/save.png" data-confirm="Are you sure?" type="image" /> def image_submit_tag(source, options = {}) options = options.stringify_keys - - if confirm = options.delete("confirm") - message = ":confirm option is deprecated and will be removed from Rails 4.1. " \ - "Use 'data: { confirm: \'Text\' }' instead'." - ActiveSupport::Deprecation.warn message - - options["data-confirm"] = confirm - end - tag :input, { "alt" => image_alt(source), "type" => "image", "src" => path_to_image(source) }.update(options) end diff --git a/actionview/lib/action_view/helpers/javascript_helper.rb b/actionview/lib/action_view/helpers/javascript_helper.rb new file mode 100644 index 0000000000..e475d5b018 --- /dev/null +++ b/actionview/lib/action_view/helpers/javascript_helper.rb @@ -0,0 +1,75 @@ +require 'action_view/helpers/tag_helper' + +module ActionView + module Helpers + module JavaScriptHelper + JS_ESCAPE_MAP = { + '\\' => '\\\\', + '</' => '<\/', + "\r\n" => '\n', + "\n" => '\n', + "\r" => '\n', + '"' => '\\"', + "'" => "\\'" + } + + JS_ESCAPE_MAP["\342\200\250".force_encoding(Encoding::UTF_8).encode!] = '
' + JS_ESCAPE_MAP["\342\200\251".force_encoding(Encoding::UTF_8).encode!] = '
' + + # Escapes carriage returns and single and double quotes for JavaScript segments. + # + # Also available through the alias j(). This is particularly helpful in JavaScript + # responses, like: + # + # $('some_element').replaceWith('<%=j render 'some/element_template' %>'); + def escape_javascript(javascript) + if javascript + result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] } + javascript.html_safe? ? result.html_safe : result + else + '' + end + end + + alias_method :j, :escape_javascript + + # Returns a JavaScript tag with the +content+ inside. Example: + # javascript_tag "alert('All is good')" + # + # Returns: + # <script> + # //<![CDATA[ + # alert('All is good') + # //]]> + # </script> + # + # +html_options+ may be a hash of attributes for the <tt>\<script></tt> + # tag. + # + # javascript_tag "alert('All is good')", defer: 'defer' + # # => <script defer="defer">alert('All is good')</script> + # + # Instead of passing the content as an argument, you can also use a block + # in which case, you pass your +html_options+ as the first parameter. + # + # <%= javascript_tag defer: 'defer' do -%> + # alert('All is good') + # <% end -%> + def javascript_tag(content_or_options_with_block = nil, html_options = {}, &block) + content = + if block_given? + html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) + capture(&block) + else + content_or_options_with_block + end + + content_tag(:script, javascript_cdata_section(content), html_options) + end + + def javascript_cdata_section(content) #:nodoc: + "\n//#{cdata_section("\n#{content}\n//")}\n".html_safe + end + end + end +end diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionview/lib/action_view/helpers/number_helper.rb index fda7038a5d..fda7038a5d 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionview/lib/action_view/helpers/number_helper.rb diff --git a/actionpack/lib/action_view/helpers/output_safety_helper.rb b/actionview/lib/action_view/helpers/output_safety_helper.rb index 60a4478c26..60a4478c26 100644 --- a/actionpack/lib/action_view/helpers/output_safety_helper.rb +++ b/actionview/lib/action_view/helpers/output_safety_helper.rb diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionview/lib/action_view/helpers/record_tag_helper.rb index f767957fa9..f767957fa9 100644 --- a/actionpack/lib/action_view/helpers/record_tag_helper.rb +++ b/actionview/lib/action_view/helpers/record_tag_helper.rb diff --git a/actionpack/lib/action_view/helpers/rendering_helper.rb b/actionview/lib/action_view/helpers/rendering_helper.rb index 458086de96..458086de96 100644 --- a/actionpack/lib/action_view/helpers/rendering_helper.rb +++ b/actionview/lib/action_view/helpers/rendering_helper.rb diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionview/lib/action_view/helpers/sanitize_helper.rb index e5cb843670..e5cb843670 100644 --- a/actionpack/lib/action_view/helpers/sanitize_helper.rb +++ b/actionview/lib/action_view/helpers/sanitize_helper.rb diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionview/lib/action_view/helpers/tag_helper.rb index 3939e4737b..732f35643a 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionview/lib/action_view/helpers/tag_helper.rb @@ -12,8 +12,11 @@ module ActionView BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked autobuffer autoplay controls loop selected hidden scoped async - defer reversed ismap seemless muted required - autofocus novalidate formnovalidate open pubdate itemscope).to_set + defer reversed ismap seamless muted required + autofocus novalidate formnovalidate open pubdate + itemscope allowfullscreen default inert sortable + truespeed typemustmatch).to_set + BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map {|attribute| attribute.to_sym }) PRE_CONTENT_STRINGS = { diff --git a/actionpack/lib/action_view/helpers/tags.rb b/actionview/lib/action_view/helpers/tags.rb index a05e16979a..a05e16979a 100644 --- a/actionpack/lib/action_view/helpers/tags.rb +++ b/actionview/lib/action_view/helpers/tags.rb diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionview/lib/action_view/helpers/tags/base.rb index 3fe3f4e9df..3fe3f4e9df 100644 --- a/actionpack/lib/action_view/helpers/tags/base.rb +++ b/actionview/lib/action_view/helpers/tags/base.rb diff --git a/actionpack/lib/action_view/helpers/tags/check_box.rb b/actionview/lib/action_view/helpers/tags/check_box.rb index 6d51f2629a..6d51f2629a 100644 --- a/actionpack/lib/action_view/helpers/tags/check_box.rb +++ b/actionview/lib/action_view/helpers/tags/check_box.rb diff --git a/actionpack/lib/action_view/helpers/tags/checkable.rb b/actionview/lib/action_view/helpers/tags/checkable.rb index 052e9df662..052e9df662 100644 --- a/actionpack/lib/action_view/helpers/tags/checkable.rb +++ b/actionview/lib/action_view/helpers/tags/checkable.rb diff --git a/actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb b/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb index 52006d856b..52006d856b 100644 --- a/actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb +++ b/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb diff --git a/actionpack/lib/action_view/helpers/tags/collection_helpers.rb b/actionview/lib/action_view/helpers/tags/collection_helpers.rb index cd12ddaf65..388dcf1f13 100644 --- a/actionpack/lib/action_view/helpers/tags/collection_helpers.rb +++ b/actionview/lib/action_view/helpers/tags/collection_helpers.rb @@ -73,8 +73,9 @@ module ActionView value = value_for_collection(item, @value_method) text = value_for_collection(item, @text_method) default_html_options = default_html_options_for_collection(item, value) + additional_html_options = option_html_attributes(item) - yield item, value, text, default_html_options + yield item, value, text, default_html_options.merge(additional_html_options) end.join.html_safe end end diff --git a/actionpack/lib/action_view/helpers/tags/collection_radio_buttons.rb b/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb index 20be34c1f2..20be34c1f2 100644 --- a/actionpack/lib/action_view/helpers/tags/collection_radio_buttons.rb +++ b/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb diff --git a/actionpack/lib/action_view/helpers/tags/collection_select.rb b/actionview/lib/action_view/helpers/tags/collection_select.rb index 6cb2b2e0d3..6cb2b2e0d3 100644 --- a/actionpack/lib/action_view/helpers/tags/collection_select.rb +++ b/actionview/lib/action_view/helpers/tags/collection_select.rb diff --git a/actionpack/lib/action_view/helpers/tags/color_field.rb b/actionview/lib/action_view/helpers/tags/color_field.rb index d8fc797035..d8fc797035 100644 --- a/actionpack/lib/action_view/helpers/tags/color_field.rb +++ b/actionview/lib/action_view/helpers/tags/color_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/date_field.rb b/actionview/lib/action_view/helpers/tags/date_field.rb index c22be0db29..c22be0db29 100644 --- a/actionpack/lib/action_view/helpers/tags/date_field.rb +++ b/actionview/lib/action_view/helpers/tags/date_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/date_select.rb b/actionview/lib/action_view/helpers/tags/date_select.rb index 0c4ac40070..0c4ac40070 100644 --- a/actionpack/lib/action_view/helpers/tags/date_select.rb +++ b/actionview/lib/action_view/helpers/tags/date_select.rb diff --git a/actionpack/lib/action_view/helpers/tags/datetime_field.rb b/actionview/lib/action_view/helpers/tags/datetime_field.rb index 9a2279c611..9a2279c611 100644 --- a/actionpack/lib/action_view/helpers/tags/datetime_field.rb +++ b/actionview/lib/action_view/helpers/tags/datetime_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb b/actionview/lib/action_view/helpers/tags/datetime_local_field.rb index b4a74185d1..b4a74185d1 100644 --- a/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb +++ b/actionview/lib/action_view/helpers/tags/datetime_local_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/datetime_select.rb b/actionview/lib/action_view/helpers/tags/datetime_select.rb index 563de1840e..563de1840e 100644 --- a/actionpack/lib/action_view/helpers/tags/datetime_select.rb +++ b/actionview/lib/action_view/helpers/tags/datetime_select.rb diff --git a/actionpack/lib/action_view/helpers/tags/email_field.rb b/actionview/lib/action_view/helpers/tags/email_field.rb index 7ce3ccb9bf..7ce3ccb9bf 100644 --- a/actionpack/lib/action_view/helpers/tags/email_field.rb +++ b/actionview/lib/action_view/helpers/tags/email_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/file_field.rb b/actionview/lib/action_view/helpers/tags/file_field.rb index 476b820d84..476b820d84 100644 --- a/actionpack/lib/action_view/helpers/tags/file_field.rb +++ b/actionview/lib/action_view/helpers/tags/file_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/grouped_collection_select.rb b/actionview/lib/action_view/helpers/tags/grouped_collection_select.rb index 2ed4712dac..2ed4712dac 100644 --- a/actionpack/lib/action_view/helpers/tags/grouped_collection_select.rb +++ b/actionview/lib/action_view/helpers/tags/grouped_collection_select.rb diff --git a/actionpack/lib/action_view/helpers/tags/hidden_field.rb b/actionview/lib/action_view/helpers/tags/hidden_field.rb index c3757c2461..c3757c2461 100644 --- a/actionpack/lib/action_view/helpers/tags/hidden_field.rb +++ b/actionview/lib/action_view/helpers/tags/hidden_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/label.rb b/actionview/lib/action_view/helpers/tags/label.rb index 35d3ba8434..35d3ba8434 100644 --- a/actionpack/lib/action_view/helpers/tags/label.rb +++ b/actionview/lib/action_view/helpers/tags/label.rb diff --git a/actionpack/lib/action_view/helpers/tags/month_field.rb b/actionview/lib/action_view/helpers/tags/month_field.rb index 4c0fb846ee..4c0fb846ee 100644 --- a/actionpack/lib/action_view/helpers/tags/month_field.rb +++ b/actionview/lib/action_view/helpers/tags/month_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/number_field.rb b/actionview/lib/action_view/helpers/tags/number_field.rb index 4f95b1b4de..4f95b1b4de 100644 --- a/actionpack/lib/action_view/helpers/tags/number_field.rb +++ b/actionview/lib/action_view/helpers/tags/number_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/password_field.rb b/actionview/lib/action_view/helpers/tags/password_field.rb index 6099fa6f19..6099fa6f19 100644 --- a/actionpack/lib/action_view/helpers/tags/password_field.rb +++ b/actionview/lib/action_view/helpers/tags/password_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/radio_button.rb b/actionview/lib/action_view/helpers/tags/radio_button.rb index 4849c537a5..4849c537a5 100644 --- a/actionpack/lib/action_view/helpers/tags/radio_button.rb +++ b/actionview/lib/action_view/helpers/tags/radio_button.rb diff --git a/actionpack/lib/action_view/helpers/tags/range_field.rb b/actionview/lib/action_view/helpers/tags/range_field.rb index f98ae88043..f98ae88043 100644 --- a/actionpack/lib/action_view/helpers/tags/range_field.rb +++ b/actionview/lib/action_view/helpers/tags/range_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/search_field.rb b/actionview/lib/action_view/helpers/tags/search_field.rb index c09e2f1be7..c09e2f1be7 100644 --- a/actionpack/lib/action_view/helpers/tags/search_field.rb +++ b/actionview/lib/action_view/helpers/tags/search_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/select.rb b/actionview/lib/action_view/helpers/tags/select.rb index d64e2f68ef..d64e2f68ef 100644 --- a/actionpack/lib/action_view/helpers/tags/select.rb +++ b/actionview/lib/action_view/helpers/tags/select.rb diff --git a/actionpack/lib/action_view/helpers/tags/tel_field.rb b/actionview/lib/action_view/helpers/tags/tel_field.rb index 987bb9e67a..987bb9e67a 100644 --- a/actionpack/lib/action_view/helpers/tags/tel_field.rb +++ b/actionview/lib/action_view/helpers/tags/tel_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/text_area.rb b/actionview/lib/action_view/helpers/tags/text_area.rb index c81156c0c8..c81156c0c8 100644 --- a/actionpack/lib/action_view/helpers/tags/text_area.rb +++ b/actionview/lib/action_view/helpers/tags/text_area.rb diff --git a/actionpack/lib/action_view/helpers/tags/text_field.rb b/actionview/lib/action_view/helpers/tags/text_field.rb index baa5ff768e..baa5ff768e 100644 --- a/actionpack/lib/action_view/helpers/tags/text_field.rb +++ b/actionview/lib/action_view/helpers/tags/text_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/time_field.rb b/actionview/lib/action_view/helpers/tags/time_field.rb index 0e90a3aed7..0e90a3aed7 100644 --- a/actionpack/lib/action_view/helpers/tags/time_field.rb +++ b/actionview/lib/action_view/helpers/tags/time_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/time_select.rb b/actionview/lib/action_view/helpers/tags/time_select.rb index 0b06311d25..0b06311d25 100644 --- a/actionpack/lib/action_view/helpers/tags/time_select.rb +++ b/actionview/lib/action_view/helpers/tags/time_select.rb diff --git a/actionpack/lib/action_view/helpers/tags/time_zone_select.rb b/actionview/lib/action_view/helpers/tags/time_zone_select.rb index 80d165ec7e..80d165ec7e 100644 --- a/actionpack/lib/action_view/helpers/tags/time_zone_select.rb +++ b/actionview/lib/action_view/helpers/tags/time_zone_select.rb diff --git a/actionpack/lib/action_view/helpers/tags/url_field.rb b/actionview/lib/action_view/helpers/tags/url_field.rb index d76340178d..d76340178d 100644 --- a/actionpack/lib/action_view/helpers/tags/url_field.rb +++ b/actionview/lib/action_view/helpers/tags/url_field.rb diff --git a/actionpack/lib/action_view/helpers/tags/week_field.rb b/actionview/lib/action_view/helpers/tags/week_field.rb index 5b3d0494e9..5b3d0494e9 100644 --- a/actionpack/lib/action_view/helpers/tags/week_field.rb +++ b/actionview/lib/action_view/helpers/tags/week_field.rb diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionview/lib/action_view/helpers/text_helper.rb index 147f9fd8ed..147f9fd8ed 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionview/lib/action_view/helpers/text_helper.rb diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionview/lib/action_view/helpers/translation_helper.rb index ad8eb47f1f..ad8eb47f1f 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionview/lib/action_view/helpers/translation_helper.rb diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb index 22059a0170..19e5941971 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionview/lib/action_view/helpers/url_helper.rb @@ -380,7 +380,7 @@ module ActionView if block_given? block.arity <= 1 ? capture(name, &block) : capture(name, options, html_options, &block) else - name + ERB::Util.html_escape(name) end else link_to(name, options, html_options) @@ -548,28 +548,10 @@ module ActionView html_options = html_options.stringify_keys html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options) - disable_with = html_options.delete("disable_with") - confirm = html_options.delete('confirm') method = html_options.delete('method') - if confirm - message = ":confirm option is deprecated and will be removed from Rails 4.1. " \ - "Use 'data: { confirm: \'Text\' }' instead." - ActiveSupport::Deprecation.warn message - - html_options["data-confirm"] = confirm - end - add_method_to_attributes!(html_options, method) if method - if disable_with - message = ":disable_with option is deprecated and will be removed from Rails 4.1. " \ - "Use 'data: { disable_with: \'Text\' }' instead." - ActiveSupport::Deprecation.warn message - - html_options["data-disable-with"] = disable_with - end - html_options else link_to_remote_options?(options) ? {'data-remote' => 'true'} : {} diff --git a/actionpack/lib/action_view/locale/en.yml b/actionview/lib/action_view/locale/en.yml index 8a56f147b8..8a56f147b8 100644 --- a/actionpack/lib/action_view/locale/en.yml +++ b/actionview/lib/action_view/locale/en.yml diff --git a/actionpack/lib/action_view/log_subscriber.rb b/actionview/lib/action_view/log_subscriber.rb index fd9a543e0a..fd9a543e0a 100644 --- a/actionpack/lib/action_view/log_subscriber.rb +++ b/actionview/lib/action_view/log_subscriber.rb diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionview/lib/action_view/lookup_context.rb index f9d5b97fe3..f9d5b97fe3 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionview/lib/action_view/lookup_context.rb diff --git a/actionpack/lib/action_view/model_naming.rb b/actionview/lib/action_view/model_naming.rb index e09ebd60df..e09ebd60df 100644 --- a/actionpack/lib/action_view/model_naming.rb +++ b/actionview/lib/action_view/model_naming.rb diff --git a/actionpack/lib/action_view/path_set.rb b/actionview/lib/action_view/path_set.rb index 91ee2ea8f5..91ee2ea8f5 100644 --- a/actionpack/lib/action_view/path_set.rb +++ b/actionview/lib/action_view/path_set.rb diff --git a/actionpack/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index e80e0ed9b0..e80e0ed9b0 100644 --- a/actionpack/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb diff --git a/actionpack/lib/action_view/record_identifier.rb b/actionview/lib/action_view/record_identifier.rb index 63f645431a..63f645431a 100644 --- a/actionpack/lib/action_view/record_identifier.rb +++ b/actionview/lib/action_view/record_identifier.rb diff --git a/actionpack/lib/action_view/renderer/abstract_renderer.rb b/actionview/lib/action_view/renderer/abstract_renderer.rb index 73c19a0ae2..73c19a0ae2 100644 --- a/actionpack/lib/action_view/renderer/abstract_renderer.rb +++ b/actionview/lib/action_view/renderer/abstract_renderer.rb diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb index 821026268a..821026268a 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionview/lib/action_view/renderer/partial_renderer.rb diff --git a/actionpack/lib/action_view/renderer/renderer.rb b/actionview/lib/action_view/renderer/renderer.rb index 964b18337e..964b18337e 100644 --- a/actionpack/lib/action_view/renderer/renderer.rb +++ b/actionview/lib/action_view/renderer/renderer.rb diff --git a/actionpack/lib/action_view/renderer/streaming_template_renderer.rb b/actionview/lib/action_view/renderer/streaming_template_renderer.rb index 9cf6eb0c65..9cf6eb0c65 100644 --- a/actionpack/lib/action_view/renderer/streaming_template_renderer.rb +++ b/actionview/lib/action_view/renderer/streaming_template_renderer.rb diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb index 4d5c5db80c..4d5c5db80c 100644 --- a/actionpack/lib/action_view/renderer/template_renderer.rb +++ b/actionview/lib/action_view/renderer/template_renderer.rb diff --git a/actionpack/lib/action_view/routing_url_for.rb b/actionview/lib/action_view/routing_url_for.rb index f10e7e88ba..f10e7e88ba 100644 --- a/actionpack/lib/action_view/routing_url_for.rb +++ b/actionview/lib/action_view/routing_url_for.rb diff --git a/actionpack/lib/action_view/template.rb b/actionview/lib/action_view/template.rb index ebbc1c79d6..e2c50fec47 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionview/lib/action_view/template.rb @@ -146,12 +146,6 @@ module ActionView handle_render_error(view, e) end - def mime_type - message = 'Template#mime_type is deprecated and will be removed in Rails 4.1. Please use type method instead.' - ActiveSupport::Deprecation.warn message - @mime_type ||= Mime::Type.lookup_by_extension(@formats.first.to_s) if @formats.first - end - def type @type ||= Types[@formats.first] if @formats.first end @@ -273,7 +267,7 @@ module ActionView method_name = self.method_name code = @handler.call(self) - # Make sure that the resulting String to be evalled is in the + # Make sure that the resulting String to be eval'd is in the # encoding of the code source = <<-end_src def #{method_name}(local_assigns, output_buffer) diff --git a/actionpack/lib/action_view/template/error.rb b/actionview/lib/action_view/template/error.rb index a89d51221e..a89d51221e 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionview/lib/action_view/template/error.rb diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionview/lib/action_view/template/handlers.rb index d9cddc0040..d9cddc0040 100644 --- a/actionpack/lib/action_view/template/handlers.rb +++ b/actionview/lib/action_view/template/handlers.rb diff --git a/actionpack/lib/action_view/template/handlers/builder.rb b/actionview/lib/action_view/template/handlers/builder.rb index d90b0c6378..d90b0c6378 100644 --- a/actionpack/lib/action_view/template/handlers/builder.rb +++ b/actionview/lib/action_view/template/handlers/builder.rb diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionview/lib/action_view/template/handlers/erb.rb index 7d7a7af51d..c8a0059596 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionview/lib/action_view/template/handlers/erb.rb @@ -1,4 +1,3 @@ -require 'action_dispatch/http/mime_type' require 'erubis' module ActionView diff --git a/actionpack/lib/action_view/template/handlers/raw.rb b/actionview/lib/action_view/template/handlers/raw.rb index 0c0d1fffcb..0c0d1fffcb 100644 --- a/actionpack/lib/action_view/template/handlers/raw.rb +++ b/actionview/lib/action_view/template/handlers/raw.rb diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb index 3304605c1a..3304605c1a 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionview/lib/action_view/template/resolver.rb diff --git a/actionpack/lib/action_view/template/text.rb b/actionview/lib/action_view/template/text.rb index 859c7bc3ce..859c7bc3ce 100644 --- a/actionpack/lib/action_view/template/text.rb +++ b/actionview/lib/action_view/template/text.rb diff --git a/actionpack/lib/action_view/template/types.rb b/actionview/lib/action_view/template/types.rb index db77cb5d19..db77cb5d19 100644 --- a/actionpack/lib/action_view/template/types.rb +++ b/actionview/lib/action_view/template/types.rb diff --git a/actionpack/lib/action_view/test_case.rb b/actionview/lib/action_view/test_case.rb index 3145446114..3145446114 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionview/lib/action_view/test_case.rb diff --git a/actionpack/lib/action_view/testing/resolvers.rb b/actionview/lib/action_view/testing/resolvers.rb index 7afa2fa613..7afa2fa613 100644 --- a/actionpack/lib/action_view/testing/resolvers.rb +++ b/actionview/lib/action_view/testing/resolvers.rb diff --git a/actionpack/lib/action_view/vendor/html-scanner.rb b/actionview/lib/action_view/vendor/html-scanner.rb index 775b827529..775b827529 100644 --- a/actionpack/lib/action_view/vendor/html-scanner.rb +++ b/actionview/lib/action_view/vendor/html-scanner.rb diff --git a/actionpack/lib/action_view/vendor/html-scanner/html/document.rb b/actionview/lib/action_view/vendor/html-scanner/html/document.rb index 386820300a..386820300a 100644 --- a/actionpack/lib/action_view/vendor/html-scanner/html/document.rb +++ b/actionview/lib/action_view/vendor/html-scanner/html/document.rb diff --git a/actionpack/lib/action_view/vendor/html-scanner/html/node.rb b/actionview/lib/action_view/vendor/html-scanner/html/node.rb index 7e7cd4f7b6..7e7cd4f7b6 100644 --- a/actionpack/lib/action_view/vendor/html-scanner/html/node.rb +++ b/actionview/lib/action_view/vendor/html-scanner/html/node.rb diff --git a/actionpack/lib/action_view/vendor/html-scanner/html/sanitizer.rb b/actionview/lib/action_view/vendor/html-scanner/html/sanitizer.rb index 30b6b8b141..30b6b8b141 100644 --- a/actionpack/lib/action_view/vendor/html-scanner/html/sanitizer.rb +++ b/actionview/lib/action_view/vendor/html-scanner/html/sanitizer.rb diff --git a/actionpack/lib/action_view/vendor/html-scanner/html/selector.rb b/actionview/lib/action_view/vendor/html-scanner/html/selector.rb index 7f8609c408..7f8609c408 100644 --- a/actionpack/lib/action_view/vendor/html-scanner/html/selector.rb +++ b/actionview/lib/action_view/vendor/html-scanner/html/selector.rb diff --git a/actionpack/lib/action_view/vendor/html-scanner/html/tokenizer.rb b/actionview/lib/action_view/vendor/html-scanner/html/tokenizer.rb index 8ac8d34430..8ac8d34430 100644 --- a/actionpack/lib/action_view/vendor/html-scanner/html/tokenizer.rb +++ b/actionview/lib/action_view/vendor/html-scanner/html/tokenizer.rb diff --git a/actionpack/lib/action_view/vendor/html-scanner/html/version.rb b/actionview/lib/action_view/vendor/html-scanner/html/version.rb index 6d645c3e14..6d645c3e14 100644 --- a/actionpack/lib/action_view/vendor/html-scanner/html/version.rb +++ b/actionview/lib/action_view/vendor/html-scanner/html/version.rb diff --git a/actionview/lib/action_view/version.rb b/actionview/lib/action_view/version.rb new file mode 100644 index 0000000000..094dd474df --- /dev/null +++ b/actionview/lib/action_view/version.rb @@ -0,0 +1,11 @@ +module ActionView + # Returns the version of the currently loaded ActionView as a Gem::Version + def self.version + Gem::Version.new "4.1.0.beta" + end + + module VERSION #:nodoc: + MAJOR, MINOR, TINY, PRE = ActionView.version.segments + STRING = ActionView.version.to_s + end +end diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb new file mode 100644 index 0000000000..8213997f4e --- /dev/null +++ b/actionview/test/abstract_unit.rb @@ -0,0 +1,382 @@ +require File.expand_path('../../../load_paths', __FILE__) + +$:.unshift(File.dirname(__FILE__) + '/lib') +$:.unshift(File.dirname(__FILE__) + '/fixtures/helpers') +$:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers') + +ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp') + +require 'active_support/core_ext/kernel/reporting' + +# These are the normal settings that will be set up by Railties +# TODO: Have these tests support other combinations of these values +silence_warnings do + Encoding.default_internal = "UTF-8" + Encoding.default_external = "UTF-8" +end + +require 'active_support/testing/autorun' +require 'abstract_controller' +require 'action_controller' +require 'action_view' +require 'action_view/testing/resolvers' +require 'action_dispatch' +require 'active_support/dependencies' +require 'active_model' +require 'active_record' +require 'action_controller/caching' + +require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late + +module Rails + class << self + def env + @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "test") + end + end +end + +ActiveSupport::Dependencies.hook! + +Thread.abort_on_exception = true + +# Show backtraces for deprecated behavior for quicker cleanup. +ActiveSupport::Deprecation.debug = true + +# Register danish language for testing +I18n.backend.store_translations 'da', {} +I18n.backend.store_translations 'pt-BR', {} +ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort + +FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') +FIXTURES = Pathname.new(FIXTURE_LOAD_PATH) + +module RackTestUtils + def body_to_string(body) + if body.respond_to?(:each) + str = "" + body.each {|s| str << s } + str + else + body + end + end + extend self +end + +module RenderERBUtils + def view + @view ||= begin + path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH) + view_paths = ActionView::PathSet.new([path]) + ActionView::Base.new(view_paths) + end + end + + def render_erb(string) + @virtual_path = nil + + template = ActionView::Template.new( + string.strip, + "test template", + ActionView::Template::Handlers::ERB, + {}) + + template.render(self, {}).strip + end +end + +SharedTestRoutes = ActionDispatch::Routing::RouteSet.new + +module ActionDispatch + module SharedRoutes + def before_setup + @routes = SharedTestRoutes + super + end + end + + # Hold off drawing routes until all the possible controller classes + # have been loaded. + module DrawOnce + class << self + attr_accessor :drew + end + self.drew = false + + def before_setup + super + return if DrawOnce.drew + + SharedTestRoutes.draw do + get ':controller(/:action)' + end + + ActionDispatch::IntegrationTest.app.routes.draw do + get ':controller(/:action)' + end + + DrawOnce.drew = true + end + end +end + +module ActiveSupport + class TestCase + include ActionDispatch::DrawOnce + end +end + +class RoutedRackApp + attr_reader :routes + + def initialize(routes, &blk) + @routes = routes + @stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes) + end + + def call(env) + @stack.call(env) + end +end + +class BasicController + attr_accessor :request + + def config + @config ||= ActiveSupport::InheritableOptions.new(ActionController::Base.config).tap do |config| + # VIEW TODO: View tests should not require a controller + public_dir = File.expand_path("../fixtures/public", __FILE__) + config.assets_dir = public_dir + config.javascripts_dir = "#{public_dir}/javascripts" + config.stylesheets_dir = "#{public_dir}/stylesheets" + config.assets = ActiveSupport::InheritableOptions.new({ :prefix => "assets" }) + config + end + end +end + +class ActionDispatch::IntegrationTest < ActiveSupport::TestCase + include ActionDispatch::SharedRoutes + + def self.build_app(routes = nil) + RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware| + middleware.use "ActionDispatch::ShowExceptions", ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public") + middleware.use "ActionDispatch::DebugExceptions" + middleware.use "ActionDispatch::Callbacks" + middleware.use "ActionDispatch::ParamsParser" + middleware.use "ActionDispatch::Cookies" + middleware.use "ActionDispatch::Flash" + middleware.use "Rack::Head" + yield(middleware) if block_given? + end + end + + self.app = build_app + + # Stub Rails dispatcher so it does not get controller references and + # simply return the controller#action as Rack::Body. + class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher + protected + def controller_reference(controller_param) + controller_param + end + + def dispatch(controller, action, env) + [200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]] + end + end + + def self.stub_controllers + old_dispatcher = ActionDispatch::Routing::RouteSet::Dispatcher + ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher } + ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, StubDispatcher } + yield ActionDispatch::Routing::RouteSet.new + ensure + ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher } + ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, old_dispatcher } + end + + def with_routing(&block) + temporary_routes = ActionDispatch::Routing::RouteSet.new + old_app, self.class.app = self.class.app, self.class.build_app(temporary_routes) + old_routes = SharedTestRoutes + silence_warnings { Object.const_set(:SharedTestRoutes, temporary_routes) } + + yield temporary_routes + ensure + self.class.app = old_app + silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) } + end + + def with_autoload_path(path) + path = File.join(File.dirname(__FILE__), "fixtures", path) + if ActiveSupport::Dependencies.autoload_paths.include?(path) + yield + else + begin + ActiveSupport::Dependencies.autoload_paths << path + yield + ensure + ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path} + ActiveSupport::Dependencies.clear + end + end + end +end + +# Temporary base class +class Rack::TestCase < ActionDispatch::IntegrationTest + def self.testing(klass = nil) + if klass + @testing = "/#{klass.name.underscore}".sub!(/_controller$/, '') + else + @testing + end + end + + def get(thing, *args) + if thing.is_a?(Symbol) + super("#{self.class.testing}/#{thing}", *args) + else + super + end + end + + def assert_body(body) + assert_equal body, Array(response.body).join + end + + def assert_status(code) + assert_equal code, response.status + end + + def assert_response(body, status = 200, headers = {}) + assert_body body + assert_status status + headers.each do |header, value| + assert_header header, value + end + end + + def assert_content_type(type) + assert_equal type, response.headers["Content-Type"] + end + + def assert_header(name, value) + assert_equal value, response.headers[name] + end +end + +module ActionController + class Base + include ActionController::Testing + # This stub emulates the Railtie including the URL helpers from a Rails application + include SharedTestRoutes.url_helpers + include SharedTestRoutes.mounted_helpers + + self.view_paths = FIXTURE_LOAD_PATH + + def self.test_routes(&block) + routes = ActionDispatch::Routing::RouteSet.new + routes.draw(&block) + include routes.url_helpers + end + end + + class TestCase + include ActionDispatch::TestProcess + include ActionDispatch::SharedRoutes + end +end + +class ::ApplicationController < ActionController::Base +end + +module ActionView + class TestCase + # Must repeat the setup because AV::TestCase is a duplication + # of AC::TestCase + include ActionDispatch::SharedRoutes + end +end + +class Workshop + extend ActiveModel::Naming + include ActiveModel::Conversion + attr_accessor :id + + def initialize(id) + @id = id + end + + def persisted? + id.present? + end + + def to_s + id.to_s + end +end + +module ActionDispatch + class DebugExceptions + private + remove_method :stderr_logger + # Silence logger + def stderr_logger + nil + end + end +end + +module ActionDispatch + module RoutingVerbs + def get(uri_or_host, path = nil) + host = uri_or_host.host unless path + path ||= uri_or_host.path + + params = {'PATH_INFO' => path, + 'REQUEST_METHOD' => 'GET', + 'HTTP_HOST' => host} + + routes.call(params)[2].join + end + end +end + +module RoutingTestHelpers + def url_for(set, options, recall = nil) + set.send(:url_for, options.merge(:only_path => true, :_recall => recall)) + end +end + +class ResourcesController < ActionController::Base + def index() render :nothing => true end + alias_method :show, :index +end + +class ThreadsController < ResourcesController; end +class MessagesController < ResourcesController; end +class CommentsController < ResourcesController; end +class ReviewsController < ResourcesController; end +class AuthorsController < ResourcesController; end +class LogosController < ResourcesController; end + +class AccountsController < ResourcesController; end +class AdminController < ResourcesController; end +class ProductsController < ResourcesController; end +class ImagesController < ResourcesController; end +class PreferencesController < ResourcesController; end + +module Backoffice + class ProductsController < ResourcesController; end + class TagsController < ResourcesController; end + class ManufacturersController < ResourcesController; end + class ImagesController < ResourcesController; end + + module Admin + class ProductsController < ResourcesController; end + class ImagesController < ResourcesController; end + end +end diff --git a/actionview/test/active_record_unit.rb b/actionview/test/active_record_unit.rb new file mode 100644 index 0000000000..95fbb112c0 --- /dev/null +++ b/actionview/test/active_record_unit.rb @@ -0,0 +1,91 @@ +require 'abstract_unit' + +# Define the essentials +class ActiveRecordTestConnector + cattr_accessor :able_to_connect + cattr_accessor :connected + + # Set our defaults + self.connected = false + self.able_to_connect = true +end + +# Try to grab AR +unless defined?(ActiveRecord) && defined?(FixtureSet) + begin + PATH_TO_AR = "#{File.dirname(__FILE__)}/../../activerecord/lib" + raise LoadError, "#{PATH_TO_AR} doesn't exist" unless File.directory?(PATH_TO_AR) + $LOAD_PATH.unshift PATH_TO_AR + require 'active_record' + rescue LoadError => e + $stderr.print "Failed to load Active Record. Skipping Active Record assertion tests: #{e}" + ActiveRecordTestConnector.able_to_connect = false + end +end +$stderr.flush + + +# Define the rest of the connector +class ActiveRecordTestConnector + class << self + def setup + unless self.connected || !self.able_to_connect + setup_connection + load_schema + require_fixture_models + self.connected = true + end + rescue Exception => e # errors from ActiveRecord setup + $stderr.puts "\nSkipping ActiveRecord assertion tests: #{e}" + #$stderr.puts " #{e.backtrace.join("\n ")}\n" + self.able_to_connect = false + end + + private + def setup_connection + if Object.const_defined?(:ActiveRecord) + defaults = { :database => ':memory:' } + adapter = defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3' + options = defaults.merge :adapter => adapter, :timeout => 500 + ActiveRecord::Base.establish_connection(options) + ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options } + ActiveRecord::Base.connection + + Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE) + else + raise "Can't setup connection since ActiveRecord isn't loaded." + end + end + + # Load actionpack sqlite tables + def load_schema + File.read(File.dirname(__FILE__) + "/fixtures/db_definitions/sqlite.sql").split(';').each do |sql| + ActiveRecord::Base.connection.execute(sql) unless sql.blank? + end + end + + def require_fixture_models + Dir.glob(File.dirname(__FILE__) + "/fixtures/*.rb").each {|f| require f} + end + end +end + +class ActiveRecordTestCase < ActionController::TestCase + include ActiveRecord::TestFixtures + + # Set our fixture path + if ActiveRecordTestConnector.able_to_connect + self.fixture_path = [FIXTURE_LOAD_PATH] + self.use_transactional_fixtures = false + end + + def self.fixtures(*args) + super if ActiveRecordTestConnector.connected + end + + def run(*args) + super if ActiveRecordTestConnector.connected + end +end + +ActiveRecordTestConnector.setup diff --git a/actionpack/test/activerecord/controller_runtime_test.rb b/actionview/test/activerecord/controller_runtime_test.rb index 368bec1c70..368bec1c70 100644 --- a/actionpack/test/activerecord/controller_runtime_test.rb +++ b/actionview/test/activerecord/controller_runtime_test.rb diff --git a/actionpack/test/activerecord/form_helper_activerecord_test.rb b/actionview/test/activerecord/form_helper_activerecord_test.rb index 2e302c65a7..2e302c65a7 100644 --- a/actionpack/test/activerecord/form_helper_activerecord_test.rb +++ b/actionview/test/activerecord/form_helper_activerecord_test.rb diff --git a/actionpack/test/activerecord/polymorphic_routes_test.rb b/actionview/test/activerecord/polymorphic_routes_test.rb index afb714484b..afb714484b 100644 --- a/actionpack/test/activerecord/polymorphic_routes_test.rb +++ b/actionview/test/activerecord/polymorphic_routes_test.rb diff --git a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb b/actionview/test/activerecord/render_partial_with_record_identification_test.rb index 409370104d..409370104d 100644 --- a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb +++ b/actionview/test/activerecord/render_partial_with_record_identification_test.rb diff --git a/actionpack/test/fixtures/_top_level_partial.html.erb b/actionview/test/fixtures/_top_level_partial.html.erb index 0b1c2e46e0..0b1c2e46e0 100644 --- a/actionpack/test/fixtures/_top_level_partial.html.erb +++ b/actionview/test/fixtures/_top_level_partial.html.erb diff --git a/actionview/test/fixtures/_top_level_partial_only.erb b/actionview/test/fixtures/_top_level_partial_only.erb new file mode 100644 index 0000000000..44f25b61d0 --- /dev/null +++ b/actionview/test/fixtures/_top_level_partial_only.erb @@ -0,0 +1 @@ +top level partial
\ No newline at end of file diff --git a/actionpack/test/fixtures/blog_public/.gitignore b/actionview/test/fixtures/blog_public/.gitignore index 312e635ee6..312e635ee6 100644 --- a/actionpack/test/fixtures/blog_public/.gitignore +++ b/actionview/test/fixtures/blog_public/.gitignore diff --git a/actionpack/test/fixtures/blog_public/blog.html b/actionview/test/fixtures/blog_public/blog.html index 79ad44c010..79ad44c010 100644 --- a/actionpack/test/fixtures/blog_public/blog.html +++ b/actionview/test/fixtures/blog_public/blog.html diff --git a/actionpack/test/fixtures/blog_public/index.html b/actionview/test/fixtures/blog_public/index.html index 2de3825481..2de3825481 100644 --- a/actionpack/test/fixtures/blog_public/index.html +++ b/actionview/test/fixtures/blog_public/index.html diff --git a/actionpack/test/fixtures/blog_public/subdir/index.html b/actionview/test/fixtures/blog_public/subdir/index.html index 517bded335..517bded335 100644 --- a/actionpack/test/fixtures/blog_public/subdir/index.html +++ b/actionview/test/fixtures/blog_public/subdir/index.html diff --git a/actionpack/test/fixtures/comments/empty.de.html.erb b/actionview/test/fixtures/comments/empty.de.html.erb index cffd90dd26..cffd90dd26 100644 --- a/actionpack/test/fixtures/comments/empty.de.html.erb +++ b/actionview/test/fixtures/comments/empty.de.html.erb diff --git a/actionpack/test/fixtures/comments/empty.html.builder b/actionview/test/fixtures/comments/empty.html.builder index 2b0c7207a3..2b0c7207a3 100644 --- a/actionpack/test/fixtures/comments/empty.html.builder +++ b/actionview/test/fixtures/comments/empty.html.builder diff --git a/actionpack/test/fixtures/comments/empty.html.erb b/actionview/test/fixtures/comments/empty.html.erb index 827f3861de..827f3861de 100644 --- a/actionpack/test/fixtures/comments/empty.html.erb +++ b/actionview/test/fixtures/comments/empty.html.erb diff --git a/actionpack/test/fixtures/comments/empty.xml.erb b/actionview/test/fixtures/comments/empty.xml.erb index db1027cd7d..db1027cd7d 100644 --- a/actionpack/test/fixtures/comments/empty.xml.erb +++ b/actionview/test/fixtures/comments/empty.xml.erb diff --git a/actionpack/test/fixtures/companies.yml b/actionview/test/fixtures/companies.yml index ed2992e0b1..ed2992e0b1 100644 --- a/actionpack/test/fixtures/companies.yml +++ b/actionview/test/fixtures/companies.yml diff --git a/actionview/test/fixtures/company.rb b/actionview/test/fixtures/company.rb new file mode 100644 index 0000000000..f3ac3642fa --- /dev/null +++ b/actionview/test/fixtures/company.rb @@ -0,0 +1,9 @@ +class Company < ActiveRecord::Base + has_one :mascot + self.sequence_name = :companies_nonstd_seq + + validates_presence_of :name + def validate + errors.add('rating', 'rating should not be 2') if rating == 2 + end +end diff --git a/actionpack/test/fixtures/custom_pattern/another.html.erb b/actionview/test/fixtures/custom_pattern/another.html.erb index 6d7f3bafbb..6d7f3bafbb 100644 --- a/actionpack/test/fixtures/custom_pattern/another.html.erb +++ b/actionview/test/fixtures/custom_pattern/another.html.erb diff --git a/actionpack/test/fixtures/custom_pattern/html/another.erb b/actionview/test/fixtures/custom_pattern/html/another.erb index dbd7e96ab6..dbd7e96ab6 100644 --- a/actionpack/test/fixtures/custom_pattern/html/another.erb +++ b/actionview/test/fixtures/custom_pattern/html/another.erb diff --git a/actionpack/test/fixtures/custom_pattern/html/path.erb b/actionview/test/fixtures/custom_pattern/html/path.erb index 6d7f3bafbb..6d7f3bafbb 100644 --- a/actionpack/test/fixtures/custom_pattern/html/path.erb +++ b/actionview/test/fixtures/custom_pattern/html/path.erb diff --git a/actionview/test/fixtures/customers/_customer.html.erb b/actionview/test/fixtures/customers/_customer.html.erb new file mode 100644 index 0000000000..483571e22a --- /dev/null +++ b/actionview/test/fixtures/customers/_customer.html.erb @@ -0,0 +1 @@ +<%= greeting %>: <%= customer.name %>
\ No newline at end of file diff --git a/actionpack/test/fixtures/db_definitions/sqlite.sql b/actionview/test/fixtures/db_definitions/sqlite.sql index 99df4b3e61..99df4b3e61 100644 --- a/actionpack/test/fixtures/db_definitions/sqlite.sql +++ b/actionview/test/fixtures/db_definitions/sqlite.sql diff --git a/actionpack/test/fixtures/developer.rb b/actionview/test/fixtures/developer.rb index 4941463015..4941463015 100644 --- a/actionpack/test/fixtures/developer.rb +++ b/actionview/test/fixtures/developer.rb diff --git a/actionpack/test/fixtures/developers.yml b/actionview/test/fixtures/developers.yml index 3656564f63..3656564f63 100644 --- a/actionpack/test/fixtures/developers.yml +++ b/actionview/test/fixtures/developers.yml diff --git a/actionpack/test/fixtures/developers/_developer.erb b/actionview/test/fixtures/developers/_developer.erb index 904a3137e7..904a3137e7 100644 --- a/actionpack/test/fixtures/developers/_developer.erb +++ b/actionview/test/fixtures/developers/_developer.erb diff --git a/actionpack/test/fixtures/developers_projects.yml b/actionview/test/fixtures/developers_projects.yml index cee359c7cf..cee359c7cf 100644 --- a/actionpack/test/fixtures/developers_projects.yml +++ b/actionview/test/fixtures/developers_projects.yml diff --git a/actionpack/test/fixtures/digestor/comments/_comment.html.erb b/actionview/test/fixtures/digestor/comments/_comment.html.erb index f172e749da..f172e749da 100644 --- a/actionpack/test/fixtures/digestor/comments/_comment.html.erb +++ b/actionview/test/fixtures/digestor/comments/_comment.html.erb diff --git a/actionpack/test/fixtures/digestor/comments/_comments.html.erb b/actionview/test/fixtures/digestor/comments/_comments.html.erb index c28646a283..c28646a283 100644 --- a/actionpack/test/fixtures/digestor/comments/_comments.html.erb +++ b/actionview/test/fixtures/digestor/comments/_comments.html.erb diff --git a/actionpack/test/fixtures/digestor/events/_event.html.erb b/actionview/test/fixtures/digestor/events/_event.html.erb index e69de29bb2..e69de29bb2 100644 --- a/actionpack/test/fixtures/digestor/events/_event.html.erb +++ b/actionview/test/fixtures/digestor/events/_event.html.erb diff --git a/actionpack/test/fixtures/digestor/level/below/_header.html.erb b/actionview/test/fixtures/digestor/level/below/_header.html.erb index e69de29bb2..e69de29bb2 100644 --- a/actionpack/test/fixtures/digestor/level/below/_header.html.erb +++ b/actionview/test/fixtures/digestor/level/below/_header.html.erb diff --git a/actionpack/test/fixtures/digestor/level/below/index.html.erb b/actionview/test/fixtures/digestor/level/below/index.html.erb index b92f49a8f8..b92f49a8f8 100644 --- a/actionpack/test/fixtures/digestor/level/below/index.html.erb +++ b/actionview/test/fixtures/digestor/level/below/index.html.erb diff --git a/actionpack/test/fixtures/digestor/messages/_form.html.erb b/actionview/test/fixtures/digestor/messages/_form.html.erb index e69de29bb2..e69de29bb2 100644 --- a/actionpack/test/fixtures/digestor/messages/_form.html.erb +++ b/actionview/test/fixtures/digestor/messages/_form.html.erb diff --git a/actionpack/test/fixtures/digestor/messages/_header.html.erb b/actionview/test/fixtures/digestor/messages/_header.html.erb index e69de29bb2..e69de29bb2 100644 --- a/actionpack/test/fixtures/digestor/messages/_header.html.erb +++ b/actionview/test/fixtures/digestor/messages/_header.html.erb diff --git a/actionpack/test/fixtures/digestor/messages/_message.html.erb b/actionview/test/fixtures/digestor/messages/_message.html.erb index 406a0fb848..406a0fb848 100644 --- a/actionpack/test/fixtures/digestor/messages/_message.html.erb +++ b/actionview/test/fixtures/digestor/messages/_message.html.erb diff --git a/actionpack/test/fixtures/digestor/messages/actions/_move.html.erb b/actionview/test/fixtures/digestor/messages/actions/_move.html.erb index e69de29bb2..e69de29bb2 100644 --- a/actionpack/test/fixtures/digestor/messages/actions/_move.html.erb +++ b/actionview/test/fixtures/digestor/messages/actions/_move.html.erb diff --git a/actionpack/test/fixtures/digestor/messages/edit.html.erb b/actionview/test/fixtures/digestor/messages/edit.html.erb index a9e0a88e32..a9e0a88e32 100644 --- a/actionpack/test/fixtures/digestor/messages/edit.html.erb +++ b/actionview/test/fixtures/digestor/messages/edit.html.erb diff --git a/actionpack/test/fixtures/digestor/messages/index.html.erb b/actionview/test/fixtures/digestor/messages/index.html.erb index 1937b652e4..1937b652e4 100644 --- a/actionpack/test/fixtures/digestor/messages/index.html.erb +++ b/actionview/test/fixtures/digestor/messages/index.html.erb diff --git a/actionpack/test/fixtures/digestor/messages/show.html.erb b/actionview/test/fixtures/digestor/messages/show.html.erb index 130e67109e..42aa2363dd 100644 --- a/actionpack/test/fixtures/digestor/messages/show.html.erb +++ b/actionview/test/fixtures/digestor/messages/show.html.erb @@ -6,9 +6,9 @@ <%= render @message.history.events %> -<%# render "something_missing" %> -<%# render "something_missing_1" %> +<%# render "something_missing" %> +<%# render "something_missing_1" %> <% # Template Dependency: messages/form -%> +%>
\ No newline at end of file diff --git a/actionpack/test/fixtures/fun/games/_game.erb b/actionview/test/fixtures/fun/games/_game.erb index f0f542ff92..f0f542ff92 100644 --- a/actionpack/test/fixtures/fun/games/_game.erb +++ b/actionview/test/fixtures/fun/games/_game.erb diff --git a/actionview/test/fixtures/fun/games/hello_world.erb b/actionview/test/fixtures/fun/games/hello_world.erb new file mode 100644 index 0000000000..1ebfbe2539 --- /dev/null +++ b/actionview/test/fixtures/fun/games/hello_world.erb @@ -0,0 +1 @@ +Living in a nested world
\ No newline at end of file diff --git a/actionpack/test/fixtures/fun/serious/games/_game.erb b/actionview/test/fixtures/fun/serious/games/_game.erb index 523bc55bd7..523bc55bd7 100644 --- a/actionpack/test/fixtures/fun/serious/games/_game.erb +++ b/actionview/test/fixtures/fun/serious/games/_game.erb diff --git a/actionview/test/fixtures/functional_caching/fragment_cached_without_digest.html.erb b/actionview/test/fixtures/functional_caching/fragment_cached_without_digest.html.erb new file mode 100644 index 0000000000..3125583a28 --- /dev/null +++ b/actionview/test/fixtures/functional_caching/fragment_cached_without_digest.html.erb @@ -0,0 +1,3 @@ +<body> +<%= cache 'nodigest', skip_digest: true do %><p>ERB</p><% end %> +</body> diff --git a/actionpack/test/fixtures/games/_game.erb b/actionview/test/fixtures/games/_game.erb index 1aeb81fcba..1aeb81fcba 100644 --- a/actionpack/test/fixtures/games/_game.erb +++ b/actionview/test/fixtures/games/_game.erb diff --git a/actionview/test/fixtures/good_customers/_good_customer.html.erb b/actionview/test/fixtures/good_customers/_good_customer.html.erb new file mode 100644 index 0000000000..a2d97ebc6d --- /dev/null +++ b/actionview/test/fixtures/good_customers/_good_customer.html.erb @@ -0,0 +1 @@ +<%= greeting %> good customer: <%= good_customer.name %><%= good_customer_counter %>
\ No newline at end of file diff --git a/actionpack/test/fixtures/happy_path/render_action/hello_world.erb b/actionview/test/fixtures/happy_path/render_action/hello_world.erb index 6769dd60bd..6769dd60bd 100644 --- a/actionpack/test/fixtures/happy_path/render_action/hello_world.erb +++ b/actionview/test/fixtures/happy_path/render_action/hello_world.erb diff --git a/actionpack/test/fixtures/layout_tests/alt/hello.erb b/actionview/test/fixtures/layout_tests/alt/hello.erb index 1055c36659..1055c36659 100644 --- a/actionpack/test/fixtures/layout_tests/alt/hello.erb +++ b/actionview/test/fixtures/layout_tests/alt/hello.erb diff --git a/actionpack/test/fixtures/layouts/_column.html.erb b/actionview/test/fixtures/layouts/_column.html.erb index 96db002b8a..96db002b8a 100644 --- a/actionpack/test/fixtures/layouts/_column.html.erb +++ b/actionview/test/fixtures/layouts/_column.html.erb diff --git a/actionview/test/fixtures/layouts/_customers.erb b/actionview/test/fixtures/layouts/_customers.erb new file mode 100644 index 0000000000..ae63f13cd3 --- /dev/null +++ b/actionview/test/fixtures/layouts/_customers.erb @@ -0,0 +1 @@ +<title><%= yield Struct.new(:name).new("David") %></title>
\ No newline at end of file diff --git a/actionpack/test/fixtures/layouts/_partial_and_yield.erb b/actionview/test/fixtures/layouts/_partial_and_yield.erb index 74cc428ffa..74cc428ffa 100644 --- a/actionpack/test/fixtures/layouts/_partial_and_yield.erb +++ b/actionview/test/fixtures/layouts/_partial_and_yield.erb diff --git a/actionpack/test/fixtures/layouts/_yield_only.erb b/actionview/test/fixtures/layouts/_yield_only.erb index 37f0bddbd7..37f0bddbd7 100644 --- a/actionpack/test/fixtures/layouts/_yield_only.erb +++ b/actionview/test/fixtures/layouts/_yield_only.erb diff --git a/actionpack/test/fixtures/layouts/_yield_with_params.erb b/actionview/test/fixtures/layouts/_yield_with_params.erb index 68e6557fb8..68e6557fb8 100644 --- a/actionpack/test/fixtures/layouts/_yield_with_params.erb +++ b/actionview/test/fixtures/layouts/_yield_with_params.erb diff --git a/actionpack/test/fixtures/layouts/streaming.erb b/actionview/test/fixtures/layouts/streaming.erb index d3f896a6ca..d3f896a6ca 100644 --- a/actionpack/test/fixtures/layouts/streaming.erb +++ b/actionview/test/fixtures/layouts/streaming.erb diff --git a/actionview/test/fixtures/layouts/yield.erb b/actionview/test/fixtures/layouts/yield.erb new file mode 100644 index 0000000000..482dc9022e --- /dev/null +++ b/actionview/test/fixtures/layouts/yield.erb @@ -0,0 +1,2 @@ +<title><%= yield :title %></title> +<%= yield %> diff --git a/actionpack/test/fixtures/layouts/yield_with_render_inline_inside.erb b/actionview/test/fixtures/layouts/yield_with_render_inline_inside.erb index 7298d79690..7298d79690 100644 --- a/actionpack/test/fixtures/layouts/yield_with_render_inline_inside.erb +++ b/actionview/test/fixtures/layouts/yield_with_render_inline_inside.erb diff --git a/actionpack/test/fixtures/layouts/yield_with_render_partial_inside.erb b/actionview/test/fixtures/layouts/yield_with_render_partial_inside.erb index 74cc428ffa..74cc428ffa 100644 --- a/actionpack/test/fixtures/layouts/yield_with_render_partial_inside.erb +++ b/actionview/test/fixtures/layouts/yield_with_render_partial_inside.erb diff --git a/actionpack/test/fixtures/mascot.rb b/actionview/test/fixtures/mascot.rb index f9f1448b8f..f9f1448b8f 100644 --- a/actionpack/test/fixtures/mascot.rb +++ b/actionview/test/fixtures/mascot.rb diff --git a/actionpack/test/fixtures/mascots.yml b/actionview/test/fixtures/mascots.yml index 17b7dff454..17b7dff454 100644 --- a/actionpack/test/fixtures/mascots.yml +++ b/actionview/test/fixtures/mascots.yml diff --git a/actionpack/test/fixtures/mascots/_mascot.html.erb b/actionview/test/fixtures/mascots/_mascot.html.erb index 432773a1da..432773a1da 100644 --- a/actionpack/test/fixtures/mascots/_mascot.html.erb +++ b/actionview/test/fixtures/mascots/_mascot.html.erb diff --git a/actionview/test/fixtures/multipart/bracketed_utf8_param b/actionview/test/fixtures/multipart/bracketed_utf8_param new file mode 100644 index 0000000000..df9cecea08 --- /dev/null +++ b/actionview/test/fixtures/multipart/bracketed_utf8_param @@ -0,0 +1,5 @@ +--AaB03x +Content-Disposition: form-data; name="Iñtërnâtiônàlizætiøn_name[Iñtërnâtiônàlizætiøn_nested_name]" + +Iñtërnâtiônàlizætiøn_value +--AaB03x-- diff --git a/actionview/test/fixtures/multipart/single_utf8_param b/actionview/test/fixtures/multipart/single_utf8_param new file mode 100644 index 0000000000..1d9fae7b17 --- /dev/null +++ b/actionview/test/fixtures/multipart/single_utf8_param @@ -0,0 +1,5 @@ +--AaB03x +Content-Disposition: form-data; name="Iñtërnâtiônàlizætiøn_name" + +Iñtërnâtiônàlizætiøn_value +--AaB03x-- diff --git a/actionpack/test/fixtures/plain_text.raw b/actionview/test/fixtures/plain_text.raw index b13985337f..b13985337f 100644 --- a/actionpack/test/fixtures/plain_text.raw +++ b/actionview/test/fixtures/plain_text.raw diff --git a/actionpack/test/fixtures/plain_text_with_characters.raw b/actionview/test/fixtures/plain_text_with_characters.raw index 1e86e44fb4..1e86e44fb4 100644 --- a/actionpack/test/fixtures/plain_text_with_characters.raw +++ b/actionview/test/fixtures/plain_text_with_characters.raw diff --git a/actionpack/test/fixtures/project.rb b/actionview/test/fixtures/project.rb index c124a9e605..c124a9e605 100644 --- a/actionpack/test/fixtures/project.rb +++ b/actionview/test/fixtures/project.rb diff --git a/actionpack/test/fixtures/projects.yml b/actionview/test/fixtures/projects.yml index 02800c7824..02800c7824 100644 --- a/actionpack/test/fixtures/projects.yml +++ b/actionview/test/fixtures/projects.yml diff --git a/actionpack/test/fixtures/projects/_project.erb b/actionview/test/fixtures/projects/_project.erb index 480c4c2af3..480c4c2af3 100644 --- a/actionpack/test/fixtures/projects/_project.erb +++ b/actionview/test/fixtures/projects/_project.erb diff --git a/actionpack/test/fixtures/public/.gitignore b/actionview/test/fixtures/public/.gitignore index 312e635ee6..312e635ee6 100644 --- a/actionpack/test/fixtures/public/.gitignore +++ b/actionview/test/fixtures/public/.gitignore diff --git a/actionpack/test/fixtures/public/elsewhere/cools.js b/actionview/test/fixtures/public/elsewhere/cools.js index 6e12fe29c4..6e12fe29c4 100644 --- a/actionpack/test/fixtures/public/elsewhere/cools.js +++ b/actionview/test/fixtures/public/elsewhere/cools.js diff --git a/actionpack/test/fixtures/public/elsewhere/file.css b/actionview/test/fixtures/public/elsewhere/file.css index 6aea0733b1..6aea0733b1 100644 --- a/actionpack/test/fixtures/public/elsewhere/file.css +++ b/actionview/test/fixtures/public/elsewhere/file.css diff --git a/actionview/test/fixtures/public/foo/baz.css b/actionview/test/fixtures/public/foo/baz.css new file mode 100644 index 0000000000..b5173fbef2 --- /dev/null +++ b/actionview/test/fixtures/public/foo/baz.css @@ -0,0 +1,3 @@ +body { +background: #000; +} diff --git a/actionpack/test/fixtures/public/javascripts/application.js b/actionview/test/fixtures/public/javascripts/application.js index 9702692980..9702692980 100644 --- a/actionpack/test/fixtures/public/javascripts/application.js +++ b/actionview/test/fixtures/public/javascripts/application.js diff --git a/actionpack/test/fixtures/public/javascripts/bank.js b/actionview/test/fixtures/public/javascripts/bank.js index 4a1bee7182..4a1bee7182 100644 --- a/actionpack/test/fixtures/public/javascripts/bank.js +++ b/actionview/test/fixtures/public/javascripts/bank.js diff --git a/actionpack/test/fixtures/public/javascripts/common.javascript b/actionview/test/fixtures/public/javascripts/common.javascript index 2ae1929056..2ae1929056 100644 --- a/actionpack/test/fixtures/public/javascripts/common.javascript +++ b/actionview/test/fixtures/public/javascripts/common.javascript diff --git a/actionpack/test/fixtures/public/javascripts/controls.js b/actionview/test/fixtures/public/javascripts/controls.js index 88168d9f13..88168d9f13 100644 --- a/actionpack/test/fixtures/public/javascripts/controls.js +++ b/actionview/test/fixtures/public/javascripts/controls.js diff --git a/actionpack/test/fixtures/public/javascripts/dragdrop.js b/actionview/test/fixtures/public/javascripts/dragdrop.js index c07061ac0c..c07061ac0c 100644 --- a/actionpack/test/fixtures/public/javascripts/dragdrop.js +++ b/actionview/test/fixtures/public/javascripts/dragdrop.js diff --git a/actionpack/test/fixtures/public/javascripts/effects.js b/actionview/test/fixtures/public/javascripts/effects.js index b555d63034..b555d63034 100644 --- a/actionpack/test/fixtures/public/javascripts/effects.js +++ b/actionview/test/fixtures/public/javascripts/effects.js diff --git a/actionpack/test/fixtures/public/javascripts/prototype.js b/actionview/test/fixtures/public/javascripts/prototype.js index 9780064a0e..9780064a0e 100644 --- a/actionpack/test/fixtures/public/javascripts/prototype.js +++ b/actionview/test/fixtures/public/javascripts/prototype.js diff --git a/actionpack/test/fixtures/public/javascripts/robber.js b/actionview/test/fixtures/public/javascripts/robber.js index eb82fcbdf4..eb82fcbdf4 100644 --- a/actionpack/test/fixtures/public/javascripts/robber.js +++ b/actionview/test/fixtures/public/javascripts/robber.js diff --git a/actionpack/test/fixtures/public/javascripts/subdir/subdir.js b/actionview/test/fixtures/public/javascripts/subdir/subdir.js index 9d23a67aa1..9d23a67aa1 100644 --- a/actionpack/test/fixtures/public/javascripts/subdir/subdir.js +++ b/actionview/test/fixtures/public/javascripts/subdir/subdir.js diff --git a/actionpack/test/fixtures/public/javascripts/version.1.0.js b/actionview/test/fixtures/public/javascripts/version.1.0.js index cfd5fce70e..cfd5fce70e 100644 --- a/actionpack/test/fixtures/public/javascripts/version.1.0.js +++ b/actionview/test/fixtures/public/javascripts/version.1.0.js diff --git a/actionpack/test/fixtures/public/stylesheets/bank.css b/actionview/test/fixtures/public/stylesheets/bank.css index ea161b12b2..ea161b12b2 100644 --- a/actionpack/test/fixtures/public/stylesheets/bank.css +++ b/actionview/test/fixtures/public/stylesheets/bank.css diff --git a/actionpack/test/fixtures/public/stylesheets/random.styles b/actionview/test/fixtures/public/stylesheets/random.styles index d4eeead95c..d4eeead95c 100644 --- a/actionpack/test/fixtures/public/stylesheets/random.styles +++ b/actionview/test/fixtures/public/stylesheets/random.styles diff --git a/actionpack/test/fixtures/public/stylesheets/robber.css b/actionview/test/fixtures/public/stylesheets/robber.css index 0fdd00a6a5..0fdd00a6a5 100644 --- a/actionpack/test/fixtures/public/stylesheets/robber.css +++ b/actionview/test/fixtures/public/stylesheets/robber.css diff --git a/actionpack/test/fixtures/public/stylesheets/subdir/subdir.css b/actionview/test/fixtures/public/stylesheets/subdir/subdir.css index 241152a905..241152a905 100644 --- a/actionpack/test/fixtures/public/stylesheets/subdir/subdir.css +++ b/actionview/test/fixtures/public/stylesheets/subdir/subdir.css diff --git a/actionpack/test/fixtures/public/stylesheets/version.1.0.css b/actionview/test/fixtures/public/stylesheets/version.1.0.css index 30f5f9ba6e..30f5f9ba6e 100644 --- a/actionpack/test/fixtures/public/stylesheets/version.1.0.css +++ b/actionview/test/fixtures/public/stylesheets/version.1.0.css diff --git a/actionpack/test/fixtures/replies.yml b/actionview/test/fixtures/replies.yml index 2a3454b8bf..2a3454b8bf 100644 --- a/actionpack/test/fixtures/replies.yml +++ b/actionview/test/fixtures/replies.yml diff --git a/actionpack/test/fixtures/replies/_reply.erb b/actionview/test/fixtures/replies/_reply.erb index 68baf548d8..68baf548d8 100644 --- a/actionpack/test/fixtures/replies/_reply.erb +++ b/actionview/test/fixtures/replies/_reply.erb diff --git a/actionpack/test/fixtures/reply.rb b/actionview/test/fixtures/reply.rb index 047522c55b..047522c55b 100644 --- a/actionpack/test/fixtures/reply.rb +++ b/actionview/test/fixtures/reply.rb diff --git a/actionview/test/fixtures/respond_to/using_defaults_with_all.html.erb b/actionview/test/fixtures/respond_to/using_defaults_with_all.html.erb new file mode 100644 index 0000000000..9f1f855269 --- /dev/null +++ b/actionview/test/fixtures/respond_to/using_defaults_with_all.html.erb @@ -0,0 +1 @@ +HTML! diff --git a/actionview/test/fixtures/ruby_template.ruby b/actionview/test/fixtures/ruby_template.ruby new file mode 100644 index 0000000000..5097bce47c --- /dev/null +++ b/actionview/test/fixtures/ruby_template.ruby @@ -0,0 +1,2 @@ +body = "" +body << ["Hello", "from", "Ruby", "code"].join(" ") diff --git a/actionpack/test/fixtures/scope/test/modgreet.erb b/actionview/test/fixtures/scope/test/modgreet.erb index 8947726e89..8947726e89 100644 --- a/actionpack/test/fixtures/scope/test/modgreet.erb +++ b/actionview/test/fixtures/scope/test/modgreet.erb diff --git a/actionview/test/fixtures/shared.html.erb b/actionview/test/fixtures/shared.html.erb new file mode 100644 index 0000000000..af262fc9f8 --- /dev/null +++ b/actionview/test/fixtures/shared.html.erb @@ -0,0 +1 @@ +Elastica
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_200.html.erb b/actionview/test/fixtures/test/_200.html.erb index c9f45675dc..c9f45675dc 100644 --- a/actionpack/test/fixtures/test/_200.html.erb +++ b/actionview/test/fixtures/test/_200.html.erb diff --git a/actionpack/test/fixtures/test/_b_layout_for_partial.html.erb b/actionview/test/fixtures/test/_b_layout_for_partial.html.erb index e918ba8f83..e918ba8f83 100644 --- a/actionpack/test/fixtures/test/_b_layout_for_partial.html.erb +++ b/actionview/test/fixtures/test/_b_layout_for_partial.html.erb diff --git a/actionpack/test/fixtures/test/_b_layout_for_partial_with_object.html.erb b/actionview/test/fixtures/test/_b_layout_for_partial_with_object.html.erb index bdd53014cd..bdd53014cd 100644 --- a/actionpack/test/fixtures/test/_b_layout_for_partial_with_object.html.erb +++ b/actionview/test/fixtures/test/_b_layout_for_partial_with_object.html.erb diff --git a/actionpack/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb b/actionview/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb index 44d6121297..44d6121297 100644 --- a/actionpack/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb +++ b/actionview/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb diff --git a/actionview/test/fixtures/test/_changing_priority.html.erb b/actionview/test/fixtures/test/_changing_priority.html.erb new file mode 100644 index 0000000000..3225efc49a --- /dev/null +++ b/actionview/test/fixtures/test/_changing_priority.html.erb @@ -0,0 +1 @@ +HTML
\ No newline at end of file diff --git a/actionview/test/fixtures/test/_changing_priority.json.erb b/actionview/test/fixtures/test/_changing_priority.json.erb new file mode 100644 index 0000000000..7fa41dce66 --- /dev/null +++ b/actionview/test/fixtures/test/_changing_priority.json.erb @@ -0,0 +1 @@ +JSON
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_content_tag_nested_in_content_tag.erb b/actionview/test/fixtures/test/_content_tag_nested_in_content_tag.erb index 2f21a75dd9..2f21a75dd9 100644 --- a/actionpack/test/fixtures/test/_content_tag_nested_in_content_tag.erb +++ b/actionview/test/fixtures/test/_content_tag_nested_in_content_tag.erb diff --git a/actionview/test/fixtures/test/_counter.html.erb b/actionview/test/fixtures/test/_counter.html.erb new file mode 100644 index 0000000000..fd245bfc70 --- /dev/null +++ b/actionview/test/fixtures/test/_counter.html.erb @@ -0,0 +1 @@ +<%= counter_counter %>
\ No newline at end of file diff --git a/actionview/test/fixtures/test/_customer.erb b/actionview/test/fixtures/test/_customer.erb new file mode 100644 index 0000000000..d8220afeda --- /dev/null +++ b/actionview/test/fixtures/test/_customer.erb @@ -0,0 +1 @@ +Hello: <%= customer.name rescue "Anonymous" %>
\ No newline at end of file diff --git a/actionview/test/fixtures/test/_customer_greeting.erb b/actionview/test/fixtures/test/_customer_greeting.erb new file mode 100644 index 0000000000..6acbcb20c4 --- /dev/null +++ b/actionview/test/fixtures/test/_customer_greeting.erb @@ -0,0 +1 @@ +<%= greeting %>: <%= customer_greeting.name %>
\ No newline at end of file diff --git a/actionview/test/fixtures/test/_customer_with_var.erb b/actionview/test/fixtures/test/_customer_with_var.erb new file mode 100644 index 0000000000..00047dd20e --- /dev/null +++ b/actionview/test/fixtures/test/_customer_with_var.erb @@ -0,0 +1 @@ +<%= customer.name %> <%= customer.name %> <%= customer.name %>
\ No newline at end of file diff --git a/actionview/test/fixtures/test/_directory/_partial_with_locales.html.erb b/actionview/test/fixtures/test/_directory/_partial_with_locales.html.erb new file mode 100644 index 0000000000..1cc8d41475 --- /dev/null +++ b/actionview/test/fixtures/test/_directory/_partial_with_locales.html.erb @@ -0,0 +1 @@ +Hello <%= name %> diff --git a/actionview/test/fixtures/test/_first_json_partial.json.erb b/actionview/test/fixtures/test/_first_json_partial.json.erb new file mode 100644 index 0000000000..790ee896db --- /dev/null +++ b/actionview/test/fixtures/test/_first_json_partial.json.erb @@ -0,0 +1 @@ +<%= render :partial => "test/second_json_partial" %>
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_from_helper.erb b/actionview/test/fixtures/test/_from_helper.erb index 16de7c0f8a..16de7c0f8a 100644 --- a/actionpack/test/fixtures/test/_from_helper.erb +++ b/actionview/test/fixtures/test/_from_helper.erb diff --git a/actionview/test/fixtures/test/_json_change_priority.json.erb b/actionview/test/fixtures/test/_json_change_priority.json.erb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/actionview/test/fixtures/test/_json_change_priority.json.erb diff --git a/actionpack/test/fixtures/test/_label_with_block.erb b/actionview/test/fixtures/test/_label_with_block.erb index 40117e594e..40117e594e 100644 --- a/actionpack/test/fixtures/test/_label_with_block.erb +++ b/actionview/test/fixtures/test/_label_with_block.erb diff --git a/actionpack/test/fixtures/test/_layout_for_block_with_args.html.erb b/actionview/test/fixtures/test/_layout_for_block_with_args.html.erb index 307533208d..307533208d 100644 --- a/actionpack/test/fixtures/test/_layout_for_block_with_args.html.erb +++ b/actionview/test/fixtures/test/_layout_for_block_with_args.html.erb diff --git a/actionview/test/fixtures/test/_layout_for_partial.html.erb b/actionview/test/fixtures/test/_layout_for_partial.html.erb new file mode 100644 index 0000000000..666efadbb6 --- /dev/null +++ b/actionview/test/fixtures/test/_layout_for_partial.html.erb @@ -0,0 +1,3 @@ +Before (<%= name %>) +<%= yield %> +After
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_layout_with_partial_and_yield.html.erb b/actionview/test/fixtures/test/_layout_with_partial_and_yield.html.erb index 820e7db789..820e7db789 100644 --- a/actionpack/test/fixtures/test/_layout_with_partial_and_yield.html.erb +++ b/actionview/test/fixtures/test/_layout_with_partial_and_yield.html.erb diff --git a/actionpack/test/fixtures/test/_local_inspector.html.erb b/actionview/test/fixtures/test/_local_inspector.html.erb index e6765c0882..e6765c0882 100644 --- a/actionpack/test/fixtures/test/_local_inspector.html.erb +++ b/actionview/test/fixtures/test/_local_inspector.html.erb diff --git a/actionpack/test/fixtures/test/_object_inspector.erb b/actionview/test/fixtures/test/_object_inspector.erb index 53af593821..53af593821 100644 --- a/actionpack/test/fixtures/test/_object_inspector.erb +++ b/actionview/test/fixtures/test/_object_inspector.erb diff --git a/actionpack/test/fixtures/test/_one.html.erb b/actionview/test/fixtures/test/_one.html.erb index f796291cb4..f796291cb4 100644 --- a/actionpack/test/fixtures/test/_one.html.erb +++ b/actionview/test/fixtures/test/_one.html.erb diff --git a/actionview/test/fixtures/test/_partial.erb b/actionview/test/fixtures/test/_partial.erb new file mode 100644 index 0000000000..e466dcbd8e --- /dev/null +++ b/actionview/test/fixtures/test/_partial.erb @@ -0,0 +1 @@ +invalid
\ No newline at end of file diff --git a/actionview/test/fixtures/test/_partial.html.erb b/actionview/test/fixtures/test/_partial.html.erb new file mode 100644 index 0000000000..e39f6c9827 --- /dev/null +++ b/actionview/test/fixtures/test/_partial.html.erb @@ -0,0 +1 @@ +partial html
\ No newline at end of file diff --git a/actionview/test/fixtures/test/_partial.js.erb b/actionview/test/fixtures/test/_partial.js.erb new file mode 100644 index 0000000000..b350cdd7ef --- /dev/null +++ b/actionview/test/fixtures/test/_partial.js.erb @@ -0,0 +1 @@ +partial js
\ No newline at end of file diff --git a/actionview/test/fixtures/test/_partial_for_use_in_layout.html.erb b/actionview/test/fixtures/test/_partial_for_use_in_layout.html.erb new file mode 100644 index 0000000000..3a03a64e31 --- /dev/null +++ b/actionview/test/fixtures/test/_partial_for_use_in_layout.html.erb @@ -0,0 +1 @@ +Inside from partial (<%= name %>)
\ No newline at end of file diff --git a/actionview/test/fixtures/test/_partial_name_local_variable.erb b/actionview/test/fixtures/test/_partial_name_local_variable.erb new file mode 100644 index 0000000000..cc3a91c89f --- /dev/null +++ b/actionview/test/fixtures/test/_partial_name_local_variable.erb @@ -0,0 +1 @@ +<%= partial_name_local_variable %> diff --git a/actionview/test/fixtures/test/_partial_only.erb b/actionview/test/fixtures/test/_partial_only.erb new file mode 100644 index 0000000000..a44b3eed40 --- /dev/null +++ b/actionview/test/fixtures/test/_partial_only.erb @@ -0,0 +1 @@ +only partial
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_partial_with_layout.erb b/actionview/test/fixtures/test/_partial_with_layout.erb index 2a50c834fe..2a50c834fe 100644 --- a/actionpack/test/fixtures/test/_partial_with_layout.erb +++ b/actionview/test/fixtures/test/_partial_with_layout.erb diff --git a/actionpack/test/fixtures/test/_partial_with_layout_block_content.erb b/actionview/test/fixtures/test/_partial_with_layout_block_content.erb index 65dafd93a8..65dafd93a8 100644 --- a/actionpack/test/fixtures/test/_partial_with_layout_block_content.erb +++ b/actionview/test/fixtures/test/_partial_with_layout_block_content.erb diff --git a/actionpack/test/fixtures/test/_partial_with_layout_block_partial.erb b/actionview/test/fixtures/test/_partial_with_layout_block_partial.erb index 444197a7d0..444197a7d0 100644 --- a/actionpack/test/fixtures/test/_partial_with_layout_block_partial.erb +++ b/actionview/test/fixtures/test/_partial_with_layout_block_partial.erb diff --git a/actionpack/test/fixtures/test/_partial_with_only_html_version.html.erb b/actionview/test/fixtures/test/_partial_with_only_html_version.html.erb index 00e6b6d6da..00e6b6d6da 100644 --- a/actionpack/test/fixtures/test/_partial_with_only_html_version.html.erb +++ b/actionview/test/fixtures/test/_partial_with_only_html_version.html.erb diff --git a/actionview/test/fixtures/test/_partial_with_partial.erb b/actionview/test/fixtures/test/_partial_with_partial.erb new file mode 100644 index 0000000000..ee0d5037b6 --- /dev/null +++ b/actionview/test/fixtures/test/_partial_with_partial.erb @@ -0,0 +1,2 @@ +<%= render 'test/partial' %> +partial with partial diff --git a/actionpack/test/fixtures/test/_raise.html.erb b/actionview/test/fixtures/test/_raise.html.erb index 68b08181d3..68b08181d3 100644 --- a/actionpack/test/fixtures/test/_raise.html.erb +++ b/actionview/test/fixtures/test/_raise.html.erb diff --git a/actionview/test/fixtures/test/_raise_indentation.html.erb b/actionview/test/fixtures/test/_raise_indentation.html.erb new file mode 100644 index 0000000000..f9a93728fe --- /dev/null +++ b/actionview/test/fixtures/test/_raise_indentation.html.erb @@ -0,0 +1,13 @@ +<p>First paragraph</p> +<p>Second paragraph</p> +<p>Third paragraph</p> +<p>Fourth paragraph</p> +<p>Fifth paragraph</p> +<p>Sixth paragraph</p> +<p>Seventh paragraph</p> +<p>Eight paragraph</p> +<p>Ninth paragraph</p> +<p>Tenth paragraph</p> +<%= raise "error here!" %> +<p>Eleventh paragraph</p> +<p>Twelfth paragraph</p>
\ No newline at end of file diff --git a/actionview/test/fixtures/test/_second_json_partial.json.erb b/actionview/test/fixtures/test/_second_json_partial.json.erb new file mode 100644 index 0000000000..5ebb7f1afd --- /dev/null +++ b/actionview/test/fixtures/test/_second_json_partial.json.erb @@ -0,0 +1 @@ +Third level
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_two.html.erb b/actionview/test/fixtures/test/_two.html.erb index 5ab2f8a432..5ab2f8a432 100644 --- a/actionpack/test/fixtures/test/_two.html.erb +++ b/actionview/test/fixtures/test/_two.html.erb diff --git a/actionpack/test/fixtures/test/_utf8_partial.html.erb b/actionview/test/fixtures/test/_utf8_partial.html.erb index 8d717fd427..8d717fd427 100644 --- a/actionpack/test/fixtures/test/_utf8_partial.html.erb +++ b/actionview/test/fixtures/test/_utf8_partial.html.erb diff --git a/actionpack/test/fixtures/test/_utf8_partial_magic.html.erb b/actionview/test/fixtures/test/_utf8_partial_magic.html.erb index 4e2224610a..4e2224610a 100644 --- a/actionpack/test/fixtures/test/_utf8_partial_magic.html.erb +++ b/actionview/test/fixtures/test/_utf8_partial_magic.html.erb diff --git a/actionpack/test/fixtures/test/basic.html.erb b/actionview/test/fixtures/test/basic.html.erb index ea696d7e01..ea696d7e01 100644 --- a/actionpack/test/fixtures/test/basic.html.erb +++ b/actionview/test/fixtures/test/basic.html.erb diff --git a/actionview/test/fixtures/test/calling_partial_with_layout.html.erb b/actionview/test/fixtures/test/calling_partial_with_layout.html.erb new file mode 100644 index 0000000000..ac44bc0d81 --- /dev/null +++ b/actionview/test/fixtures/test/calling_partial_with_layout.html.erb @@ -0,0 +1 @@ +<%= render(:layout => "layout_for_partial", :partial => "partial_for_use_in_layout", :locals => { :name => "David" }) %>
\ No newline at end of file diff --git a/actionview/test/fixtures/test/change_priority.html.erb b/actionview/test/fixtures/test/change_priority.html.erb new file mode 100644 index 0000000000..5618977d05 --- /dev/null +++ b/actionview/test/fixtures/test/change_priority.html.erb @@ -0,0 +1,2 @@ +<%= render :partial => "test/json_change_priority", formats: :json %> +HTML Template, but <%= render :partial => "test/changing_priority" %> partial
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/dont_pick_me b/actionview/test/fixtures/test/dont_pick_me index 0157c9e503..0157c9e503 100644 --- a/actionpack/test/fixtures/test/dont_pick_me +++ b/actionview/test/fixtures/test/dont_pick_me diff --git a/actionview/test/fixtures/test/dot.directory/render_file_with_ivar.erb b/actionview/test/fixtures/test/dot.directory/render_file_with_ivar.erb new file mode 100644 index 0000000000..8b8a449236 --- /dev/null +++ b/actionview/test/fixtures/test/dot.directory/render_file_with_ivar.erb @@ -0,0 +1 @@ +The secret is <%= @secret %> diff --git a/actionview/test/fixtures/test/greeting.xml.erb b/actionview/test/fixtures/test/greeting.xml.erb new file mode 100644 index 0000000000..62fb0293f0 --- /dev/null +++ b/actionview/test/fixtures/test/greeting.xml.erb @@ -0,0 +1 @@ +<p>This is grand!</p> diff --git a/actionview/test/fixtures/test/hello.builder b/actionview/test/fixtures/test/hello.builder new file mode 100644 index 0000000000..a471553941 --- /dev/null +++ b/actionview/test/fixtures/test/hello.builder @@ -0,0 +1,4 @@ +xml.html do + xml.p "Hello #{@name}" + xml << render(:file => "test/greeting") +end
\ No newline at end of file diff --git a/actionview/test/fixtures/test/hello/hello.erb b/actionview/test/fixtures/test/hello/hello.erb new file mode 100644 index 0000000000..6769dd60bd --- /dev/null +++ b/actionview/test/fixtures/test/hello/hello.erb @@ -0,0 +1 @@ +Hello world!
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/hello_world.da.html.erb b/actionview/test/fixtures/test/hello_world.da.html.erb index 10ec443291..10ec443291 100644 --- a/actionpack/test/fixtures/test/hello_world.da.html.erb +++ b/actionview/test/fixtures/test/hello_world.da.html.erb diff --git a/actionview/test/fixtures/test/hello_world.erb b/actionview/test/fixtures/test/hello_world.erb new file mode 100644 index 0000000000..6769dd60bd --- /dev/null +++ b/actionview/test/fixtures/test/hello_world.erb @@ -0,0 +1 @@ +Hello world!
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/hello_world.erb~ b/actionview/test/fixtures/test/hello_world.erb~ index 21934a1c95..21934a1c95 100644 --- a/actionpack/test/fixtures/test/hello_world.erb~ +++ b/actionview/test/fixtures/test/hello_world.erb~ diff --git a/actionpack/test/fixtures/test/hello_world.pt-BR.html.erb b/actionview/test/fixtures/test/hello_world.pt-BR.html.erb index 773b3c8c6e..773b3c8c6e 100644 --- a/actionpack/test/fixtures/test/hello_world.pt-BR.html.erb +++ b/actionview/test/fixtures/test/hello_world.pt-BR.html.erb diff --git a/actionview/test/fixtures/test/hello_world_with_partial.html.erb b/actionview/test/fixtures/test/hello_world_with_partial.html.erb new file mode 100644 index 0000000000..ec31545356 --- /dev/null +++ b/actionview/test/fixtures/test/hello_world_with_partial.html.erb @@ -0,0 +1,2 @@ +Hello world! +<%= render '/test/partial' %> diff --git a/actionview/test/fixtures/test/html_template.html.erb b/actionview/test/fixtures/test/html_template.html.erb new file mode 100644 index 0000000000..1bbc2b7f09 --- /dev/null +++ b/actionview/test/fixtures/test/html_template.html.erb @@ -0,0 +1 @@ +<%= render :partial => "test/first_json_partial", formats: :json %>
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/layout_render_file.erb b/actionview/test/fixtures/test/layout_render_file.erb index 2f8e921c5f..2f8e921c5f 100644 --- a/actionpack/test/fixtures/test/layout_render_file.erb +++ b/actionview/test/fixtures/test/layout_render_file.erb diff --git a/actionpack/test/fixtures/test/layout_render_object.erb b/actionview/test/fixtures/test/layout_render_object.erb index acc4453c08..acc4453c08 100644 --- a/actionpack/test/fixtures/test/layout_render_object.erb +++ b/actionview/test/fixtures/test/layout_render_object.erb diff --git a/actionview/test/fixtures/test/list.erb b/actionview/test/fixtures/test/list.erb new file mode 100644 index 0000000000..0a4bda58ee --- /dev/null +++ b/actionview/test/fixtures/test/list.erb @@ -0,0 +1 @@ +<%= @test_unchanged = 'goodbye' %><%= render :partial => 'customer', :collection => @customers %><%= @test_unchanged %> diff --git a/actionpack/test/fixtures/test/malformed/malformed.en.html.erb~ b/actionview/test/fixtures/test/malformed/malformed.en.html.erb~ index d009950384..d009950384 100644 --- a/actionpack/test/fixtures/test/malformed/malformed.en.html.erb~ +++ b/actionview/test/fixtures/test/malformed/malformed.en.html.erb~ diff --git a/actionpack/test/fixtures/test/malformed/malformed.erb~ b/actionview/test/fixtures/test/malformed/malformed.erb~ index d009950384..d009950384 100644 --- a/actionpack/test/fixtures/test/malformed/malformed.erb~ +++ b/actionview/test/fixtures/test/malformed/malformed.erb~ diff --git a/actionpack/test/fixtures/test/malformed/malformed.html.erb~ b/actionview/test/fixtures/test/malformed/malformed.html.erb~ index d009950384..d009950384 100644 --- a/actionpack/test/fixtures/test/malformed/malformed.html.erb~ +++ b/actionview/test/fixtures/test/malformed/malformed.html.erb~ diff --git a/actionview/test/fixtures/test/malformed/malformed~ b/actionview/test/fixtures/test/malformed/malformed~ new file mode 100644 index 0000000000..d009950384 --- /dev/null +++ b/actionview/test/fixtures/test/malformed/malformed~ @@ -0,0 +1 @@ +Don't render me!
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/nested_layout.erb b/actionview/test/fixtures/test/nested_layout.erb index 6078f74b4c..6078f74b4c 100644 --- a/actionpack/test/fixtures/test/nested_layout.erb +++ b/actionview/test/fixtures/test/nested_layout.erb diff --git a/actionpack/test/fixtures/test/nested_streaming.erb b/actionview/test/fixtures/test/nested_streaming.erb index 55525e0c92..55525e0c92 100644 --- a/actionpack/test/fixtures/test/nested_streaming.erb +++ b/actionview/test/fixtures/test/nested_streaming.erb diff --git a/actionpack/test/fixtures/test/one.html.erb b/actionview/test/fixtures/test/one.html.erb index 0151874809..0151874809 100644 --- a/actionpack/test/fixtures/test/one.html.erb +++ b/actionview/test/fixtures/test/one.html.erb diff --git a/actionview/test/fixtures/test/render_file_with_ivar.erb b/actionview/test/fixtures/test/render_file_with_ivar.erb new file mode 100644 index 0000000000..8b8a449236 --- /dev/null +++ b/actionview/test/fixtures/test/render_file_with_ivar.erb @@ -0,0 +1 @@ +The secret is <%= @secret %> diff --git a/actionview/test/fixtures/test/render_file_with_locals.erb b/actionview/test/fixtures/test/render_file_with_locals.erb new file mode 100644 index 0000000000..ebe09faee6 --- /dev/null +++ b/actionview/test/fixtures/test/render_file_with_locals.erb @@ -0,0 +1 @@ +The secret is <%= secret %> diff --git a/actionview/test/fixtures/test/render_file_with_locals_and_default.erb b/actionview/test/fixtures/test/render_file_with_locals_and_default.erb new file mode 100644 index 0000000000..9b4900acc5 --- /dev/null +++ b/actionview/test/fixtures/test/render_file_with_locals_and_default.erb @@ -0,0 +1 @@ +<%= secret ||= 'one' %>
\ No newline at end of file diff --git a/actionview/test/fixtures/test/render_partial_inside_directory.html.erb b/actionview/test/fixtures/test/render_partial_inside_directory.html.erb new file mode 100644 index 0000000000..1461b95186 --- /dev/null +++ b/actionview/test/fixtures/test/render_partial_inside_directory.html.erb @@ -0,0 +1 @@ +<%= render partial: 'test/_directory/partial_with_locales', locals: {'name' => 'Jane'} %> diff --git a/actionview/test/fixtures/test/render_two_partials.html.erb b/actionview/test/fixtures/test/render_two_partials.html.erb new file mode 100644 index 0000000000..3db6025860 --- /dev/null +++ b/actionview/test/fixtures/test/render_two_partials.html.erb @@ -0,0 +1,2 @@ +<%= render :partial => 'partial', :locals => {'first' => '1'} %> +<%= render :partial => 'partial', :locals => {'second' => '2'} %> diff --git a/actionpack/test/fixtures/test/streaming.erb b/actionview/test/fixtures/test/streaming.erb index fb9b8b1ade..fb9b8b1ade 100644 --- a/actionpack/test/fixtures/test/streaming.erb +++ b/actionview/test/fixtures/test/streaming.erb diff --git a/actionpack/test/fixtures/test/streaming_buster.erb b/actionview/test/fixtures/test/streaming_buster.erb index 4221d56dcc..4221d56dcc 100644 --- a/actionpack/test/fixtures/test/streaming_buster.erb +++ b/actionview/test/fixtures/test/streaming_buster.erb diff --git a/actionpack/test/fixtures/test/sub_template_raise.html.erb b/actionview/test/fixtures/test/sub_template_raise.html.erb index f38c0bda90..f38c0bda90 100644 --- a/actionpack/test/fixtures/test/sub_template_raise.html.erb +++ b/actionview/test/fixtures/test/sub_template_raise.html.erb diff --git a/actionpack/test/fixtures/test/template.erb b/actionview/test/fixtures/test/template.erb index 785afa8f6a..785afa8f6a 100644 --- a/actionpack/test/fixtures/test/template.erb +++ b/actionview/test/fixtures/test/template.erb diff --git a/actionpack/test/fixtures/test/update_element_with_capture.erb b/actionview/test/fixtures/test/update_element_with_capture.erb index fa3ef200f9..fa3ef200f9 100644 --- a/actionpack/test/fixtures/test/update_element_with_capture.erb +++ b/actionview/test/fixtures/test/update_element_with_capture.erb diff --git a/actionpack/test/fixtures/test/utf8.html.erb b/actionview/test/fixtures/test/utf8.html.erb index ac98c2f012..ac98c2f012 100644 --- a/actionpack/test/fixtures/test/utf8.html.erb +++ b/actionview/test/fixtures/test/utf8.html.erb diff --git a/actionpack/test/fixtures/test/utf8_magic.html.erb b/actionview/test/fixtures/test/utf8_magic.html.erb index 257279c29f..257279c29f 100644 --- a/actionpack/test/fixtures/test/utf8_magic.html.erb +++ b/actionview/test/fixtures/test/utf8_magic.html.erb diff --git a/actionpack/test/fixtures/test/utf8_magic_with_bare_partial.html.erb b/actionview/test/fixtures/test/utf8_magic_with_bare_partial.html.erb index cb22692f9a..cb22692f9a 100644 --- a/actionpack/test/fixtures/test/utf8_magic_with_bare_partial.html.erb +++ b/actionview/test/fixtures/test/utf8_magic_with_bare_partial.html.erb diff --git a/actionpack/test/fixtures/topic.rb b/actionview/test/fixtures/topic.rb index 9fa9746535..9fa9746535 100644 --- a/actionpack/test/fixtures/topic.rb +++ b/actionview/test/fixtures/topic.rb diff --git a/actionpack/test/fixtures/topics.yml b/actionview/test/fixtures/topics.yml index 7fdd49d54e..7fdd49d54e 100644 --- a/actionpack/test/fixtures/topics.yml +++ b/actionview/test/fixtures/topics.yml diff --git a/actionpack/test/fixtures/topics/_topic.html.erb b/actionview/test/fixtures/topics/_topic.html.erb index 98659ca098..98659ca098 100644 --- a/actionpack/test/fixtures/topics/_topic.html.erb +++ b/actionview/test/fixtures/topics/_topic.html.erb diff --git a/actionpack/test/fixtures/translations/templates/array.erb b/actionview/test/fixtures/translations/templates/array.erb index d86045a172..d86045a172 100644 --- a/actionpack/test/fixtures/translations/templates/array.erb +++ b/actionview/test/fixtures/translations/templates/array.erb diff --git a/actionpack/test/fixtures/translations/templates/default.erb b/actionview/test/fixtures/translations/templates/default.erb index 8b70031071..8b70031071 100644 --- a/actionpack/test/fixtures/translations/templates/default.erb +++ b/actionview/test/fixtures/translations/templates/default.erb diff --git a/actionpack/test/fixtures/translations/templates/found.erb b/actionview/test/fixtures/translations/templates/found.erb index 080c9c0aee..080c9c0aee 100644 --- a/actionpack/test/fixtures/translations/templates/found.erb +++ b/actionview/test/fixtures/translations/templates/found.erb diff --git a/actionpack/test/fixtures/translations/templates/missing.erb b/actionview/test/fixtures/translations/templates/missing.erb index 0f3f17f8ef..0f3f17f8ef 100644 --- a/actionpack/test/fixtures/translations/templates/missing.erb +++ b/actionview/test/fixtures/translations/templates/missing.erb diff --git a/actionpack/test/fixtures/with_format.json.erb b/actionview/test/fixtures/with_format.json.erb index a7f480ab1d..a7f480ab1d 100644 --- a/actionpack/test/fixtures/with_format.json.erb +++ b/actionview/test/fixtures/with_format.json.erb diff --git a/actionview/test/lib/controller/fake_controllers.rb b/actionview/test/lib/controller/fake_controllers.rb new file mode 100644 index 0000000000..1a2863b689 --- /dev/null +++ b/actionview/test/lib/controller/fake_controllers.rb @@ -0,0 +1,35 @@ +class ContentController < ActionController::Base; end + +module Admin + class AccountsController < ActionController::Base; end + class PostsController < ActionController::Base; end + class StuffController < ActionController::Base; end + class UserController < ActionController::Base; end + class UsersController < ActionController::Base; end +end + +module Api + class UsersController < ActionController::Base; end + class ProductsController < ActionController::Base; end +end + +class AccountController < ActionController::Base; end +class ArchiveController < ActionController::Base; end +class ArticlesController < ActionController::Base; end +class BarController < ActionController::Base; end +class BlogController < ActionController::Base; end +class BooksController < ActionController::Base; end +class CarsController < ActionController::Base; end +class CcController < ActionController::Base; end +class CController < ActionController::Base; end +class FooController < ActionController::Base; end +class GeocodeController < ActionController::Base; end +class NewsController < ActionController::Base; end +class NotesController < ActionController::Base; end +class PagesController < ActionController::Base; end +class PeopleController < ActionController::Base; end +class PostsController < ActionController::Base; end +class SubpathBooksController < ActionController::Base; end +class SymbolsController < ActionController::Base; end +class UserController < ActionController::Base; end +class UsersController < ActionController::Base; end diff --git a/actionview/test/lib/controller/fake_models.rb b/actionview/test/lib/controller/fake_models.rb new file mode 100644 index 0000000000..a463a08bb6 --- /dev/null +++ b/actionview/test/lib/controller/fake_models.rb @@ -0,0 +1,185 @@ +require "active_model" + +class Customer < Struct.new(:name, :id) + extend ActiveModel::Naming + include ActiveModel::Conversion + + undef_method :to_json + + def to_xml(options={}) + if options[:builder] + options[:builder].name name + else + "<name>#{name}</name>" + end + end + + def to_js(options={}) + "name: #{name.inspect}" + end + alias :to_text :to_js + + def errors + [] + end + + def persisted? + id.present? + end +end + +class GoodCustomer < Customer +end + +class Post < Struct.new(:title, :author_name, :body, :secret, :persisted, :written_on, :cost) + extend ActiveModel::Naming + include ActiveModel::Conversion + extend ActiveModel::Translation + + alias_method :secret?, :secret + alias_method :persisted?, :persisted + + def initialize(*args) + super + @persisted = false + end + + attr_accessor :author + def author_attributes=(attributes); end + + attr_accessor :comments, :comment_ids + def comments_attributes=(attributes); end + + attr_accessor :tags + def tags_attributes=(attributes); end +end + +class Comment + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + attr_reader :post_id + def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end + def to_key; id ? [id] : nil end + def save; @id = 1; @post_id = 1 end + def persisted?; @id.present? end + def to_param; @id.to_s; end + def name + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end + + attr_accessor :relevances + def relevances_attributes=(attributes); end + + attr_accessor :body +end + +class Tag + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + attr_reader :post_id + def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end + def to_key; id ? [id] : nil end + def save; @id = 1; @post_id = 1 end + def persisted?; @id.present? end + def to_param; @id; end + def value + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end + + attr_accessor :relevances + def relevances_attributes=(attributes); end + +end + +class CommentRelevance + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + attr_reader :comment_id + def initialize(id = nil, comment_id = nil); @id, @comment_id = id, comment_id end + def to_key; id ? [id] : nil end + def save; @id = 1; @comment_id = 1 end + def persisted?; @id.present? end + def to_param; @id; end + def value + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end +end + +class Sheep + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + def to_key; id ? [id] : nil end + def save; @id = 1 end + def new_record?; @id.nil? end + def name + @id.nil? ? 'new sheep' : "sheep ##{@id}" + end +end + +class TagRelevance + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + attr_reader :tag_id + def initialize(id = nil, tag_id = nil); @id, @tag_id = id, tag_id end + def to_key; id ? [id] : nil end + def save; @id = 1; @tag_id = 1 end + def persisted?; @id.present? end + def to_param; @id; end + def value + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end +end + +class Author < Comment + attr_accessor :post + def post_attributes=(attributes); end +end + +class HashBackedAuthor < Hash + extend ActiveModel::Naming + include ActiveModel::Conversion + + def persisted?; false; end + + def name + "hash backed author" + end +end + +module Blog + def self.use_relative_model_naming? + true + end + + class Post < Struct.new(:title, :id) + extend ActiveModel::Naming + include ActiveModel::Conversion + + def persisted? + id.present? + end + end +end + +class ArelLike + def to_ary + true + end + def each + a = Array.new(2) { |id| Comment.new(id + 1) } + a.each { |i| yield i } + end +end + +class Car < Struct.new(:color) +end diff --git a/actionpack/test/template/active_model_helper_test.rb b/actionview/test/template/active_model_helper_test.rb index 86bccdfade..86bccdfade 100644 --- a/actionpack/test/template/active_model_helper_test.rb +++ b/actionview/test/template/active_model_helper_test.rb diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionview/test/template/asset_tag_helper_test.rb index 67f593c22f..214a13654e 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionview/test/template/asset_tag_helper_test.rb @@ -48,6 +48,9 @@ class AssetTagHelperTest < ActionView::TestCase %(asset_path("style.min")) => %(/style.min), %(asset_path("style.min.css")) => %(/style.min.css), + %(asset_path("http://www.outside.com/image.jpg")) => %(http://www.outside.com/image.jpg), + %(asset_path("HTTP://www.outside.com/image.jpg")) => %(HTTP://www.outside.com/image.jpg), + %(asset_path("style", type: :stylesheet)) => %(/stylesheets/style.css), %(asset_path("xmlhr", type: :javascript)) => %(/javascripts/xmlhr.js), %(asset_path("xml.png", type: :image)) => %(/images/xml.png) @@ -298,13 +301,15 @@ class AssetTagHelperTest < ActionView::TestCase %(font_path("font.ttf?123")) => %(/fonts/font.ttf?123) } - def test_autodiscovery_link_tag_deprecated_types - result = nil - assert_deprecated do - result = auto_discovery_link_tag(:xml) + def test_autodiscovery_link_tag_with_unknown_type_but_not_pass_type_option_key + assert_raise(ArgumentError) do + auto_discovery_link_tag(:xml) end + end - expected = %(<link href="http://www.example.com" rel="alternate" title="XML" type="application/xml" />) + def test_autodiscovery_link_tag_with_unknown_type + result = auto_discovery_link_tag(:xml, '/feed.xml', :type => 'application/xml') + expected = %(<link href="/feed.xml" rel="alternate" title="XML" type="application/xml" />) assert_equal expected, result end @@ -443,8 +448,8 @@ class AssetTagHelperTest < ActionView::TestCase [nil, '/', '/foo/bar/', 'foo/bar/'].each do |prefix| assert_equal 'Rails', image_alt("#{prefix}rails.png") assert_equal 'Rails', image_alt("#{prefix}rails-9c0a079bdd7701d7e729bd956823d153.png") - assert_equal 'Long file name with hyphens', image_alt("#{prefix}long-file-name-with-hyphens.png") - assert_equal 'Long file name with underscores', image_alt("#{prefix}long_file_name_with_underscores.png") + assert_equal 'Long file name with hyphens', image_alt("#{prefix}long-file-name-with-hyphens.png") + assert_equal 'Long file name with underscores', image_alt("#{prefix}long_file_name_with_underscores.png") end end diff --git a/actionpack/test/template/atom_feed_helper_test.rb b/actionview/test/template/atom_feed_helper_test.rb index 63b5ac0fab..63b5ac0fab 100644 --- a/actionpack/test/template/atom_feed_helper_test.rb +++ b/actionview/test/template/atom_feed_helper_test.rb diff --git a/actionpack/test/template/capture_helper_test.rb b/actionview/test/template/capture_helper_test.rb index 938f1c3e54..938f1c3e54 100644 --- a/actionpack/test/template/capture_helper_test.rb +++ b/actionview/test/template/capture_helper_test.rb diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionview/test/template/compiled_templates_test.rb index f5dc2fbb33..2336321f3e 100644 --- a/actionpack/test/template/compiled_templates_test.rb +++ b/actionview/test/template/compiled_templates_test.rb @@ -1,5 +1,4 @@ require 'abstract_unit' -require 'controller/fake_models' class CompiledTemplatesTest < ActiveSupport::TestCase def setup diff --git a/actionpack/test/template/date_helper_i18n_test.rb b/actionview/test/template/date_helper_i18n_test.rb index 21fca35185..21fca35185 100644 --- a/actionpack/test/template/date_helper_i18n_test.rb +++ b/actionview/test/template/date_helper_i18n_test.rb diff --git a/actionpack/test/template/date_helper_test.rb b/actionview/test/template/date_helper_test.rb index 242b56a1fd..242b56a1fd 100644 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionview/test/template/date_helper_test.rb diff --git a/actionpack/test/template/debug_helper_test.rb b/actionview/test/template/debug_helper_test.rb index 42d06bd9ff..42d06bd9ff 100644 --- a/actionpack/test/template/debug_helper_test.rb +++ b/actionview/test/template/debug_helper_test.rb diff --git a/actionview/test/template/dependency_tracker_test.rb b/actionview/test/template/dependency_tracker_test.rb new file mode 100644 index 0000000000..7a9b4b26ac --- /dev/null +++ b/actionview/test/template/dependency_tracker_test.rb @@ -0,0 +1,74 @@ +require 'abstract_unit' +require 'action_view/dependency_tracker' + +class NeckbeardTracker + def self.call(name, template) + ["foo/#{name}"] + end +end + +class FakeTemplate + attr_reader :source, :handler + + def initialize(source, handler = Neckbeard) + @source, @handler = source, handler + end +end + +Neckbeard = lambda {|template| template.source } +Bowtie = lambda {|template| template.source } + +class DependencyTrackerTest < ActionView::TestCase + def tracker + ActionView::DependencyTracker + end + + def setup + ActionView::Template.register_template_handler :neckbeard, Neckbeard + tracker.register_tracker(:neckbeard, NeckbeardTracker) + end + + def teardown + tracker.remove_tracker(:neckbeard) + end + + def test_finds_tracker_by_template_handler + template = FakeTemplate.new("boo/hoo") + dependencies = tracker.find_dependencies("boo/hoo", template) + assert_equal ["foo/boo/hoo"], dependencies + end + + def test_returns_empty_array_if_no_tracker_is_found + template = FakeTemplate.new("boo/hoo", Bowtie) + dependencies = tracker.find_dependencies("boo/hoo", template) + assert_equal [], dependencies + end +end + +class ERBTrackerTest < Minitest::Test + def make_tracker(name, template) + ActionView::DependencyTracker::ERBTracker.new(name, template) + end + + def test_dependency_of_erb_template_with_number_in_filename + template = FakeTemplate.new("<%# render 'messages/message123' %>", :erb) + tracker = make_tracker('messages/_message123', template) + + assert_equal ["messages/message123"], tracker.dependencies + end + + def test_finds_dependency_in_correct_directory + template = FakeTemplate.new("<%# render(message.topic) %>", :erb) + tracker = make_tracker('messages/_message', template) + + assert_equal ["topics/topic"], tracker.dependencies + end + + def test_finds_dependency_in_correct_directory_with_underscore + template = FakeTemplate.new("<%# render(message_type.messages) %>", :erb) + tracker = make_tracker('message_types/_message_type', template) + + assert_equal ["messages/message"], tracker.dependencies + end +end + diff --git a/actionpack/test/template/digestor_test.rb b/actionview/test/template/digestor_test.rb index 06735c30d3..06735c30d3 100644 --- a/actionpack/test/template/digestor_test.rb +++ b/actionview/test/template/digestor_test.rb diff --git a/actionpack/test/template/erb/form_for_test.rb b/actionview/test/template/erb/form_for_test.rb index e722b40a9a..e722b40a9a 100644 --- a/actionpack/test/template/erb/form_for_test.rb +++ b/actionview/test/template/erb/form_for_test.rb diff --git a/actionpack/test/template/erb/helper.rb b/actionview/test/template/erb/helper.rb index a1973068d5..a1973068d5 100644 --- a/actionpack/test/template/erb/helper.rb +++ b/actionview/test/template/erb/helper.rb diff --git a/actionpack/test/template/erb/tag_helper_test.rb b/actionview/test/template/erb/tag_helper_test.rb index 84e328d8be..84e328d8be 100644 --- a/actionpack/test/template/erb/tag_helper_test.rb +++ b/actionview/test/template/erb/tag_helper_test.rb diff --git a/actionpack/test/template/erb_util_test.rb b/actionview/test/template/erb_util_test.rb index 3e5b029cea..3e5b029cea 100644 --- a/actionpack/test/template/erb_util_test.rb +++ b/actionview/test/template/erb_util_test.rb diff --git a/actionpack/test/template/form_collections_helper_test.rb b/actionview/test/template/form_collections_helper_test.rb index 2131f81396..bc9c21dfd3 100644 --- a/actionpack/test/template/form_collections_helper_test.rb +++ b/actionview/test/template/form_collections_helper_test.rb @@ -76,6 +76,14 @@ class FormCollectionsHelperTest < ActionView::TestCase assert_select 'input[type=radio][value=false].special-radio#user_active_false' end + test 'collection radio accepts html options as the last element of array' do + collection = [[1, true, {class: 'foo'}], [0, false, {class: 'bar'}]] + with_collection_radio_buttons :user, :active, collection, :second, :first + + assert_select 'input[type=radio][value=true].foo#user_active_true' + assert_select 'input[type=radio][value=false].bar#user_active_false' + end + test 'collection radio does not wrap input inside the label' do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s @@ -192,6 +200,14 @@ class FormCollectionsHelperTest < ActionView::TestCase assert_select 'label[for=user_name_199]', '$1.99' end + test 'collection check boxes accepts html options as the last element of array' do + collection = [[1, 'Category 1', {class: 'foo'}], [2, 'Category 2', {class: 'bar'}]] + with_collection_check_boxes :user, :active, collection, :first, :second + + assert_select 'input[type=checkbox][value=1].foo' + assert_select 'input[type=checkbox][value=2].bar' + end + test 'collection check boxes accepts selected values as :checked option' do collection = (1..3).map{|i| [i, "Category #{i}"] } with_collection_check_boxes :user, :category_ids, collection, :first, :last, :checked => [1, 3] diff --git a/actionpack/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb index 1ff320224d..1ff320224d 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionview/test/template/form_helper_test.rb diff --git a/actionpack/test/template/form_options_helper_i18n_test.rb b/actionview/test/template/form_options_helper_i18n_test.rb index 4972ea6511..4972ea6511 100644 --- a/actionpack/test/template/form_options_helper_i18n_test.rb +++ b/actionview/test/template/form_options_helper_i18n_test.rb diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionview/test/template/form_options_helper_test.rb index 1715902927..1715902927 100644 --- a/actionpack/test/template/form_options_helper_test.rb +++ b/actionview/test/template/form_options_helper_test.rb diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb index 6c6a142397..70fc6a588b 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionview/test/template/form_tag_helper_test.rb @@ -410,15 +410,6 @@ class FormTagHelperTest < ActionView::TestCase ) end - def test_submit_tag_with_deprecated_confirmation - assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use 'data: { confirm: \'Text\' }' instead" do - assert_dom_equal( - %(<input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />), - submit_tag("Save", :confirm => "Are you sure?") - ) - end - end - def test_button_tag assert_dom_equal( %(<button name="button" type="submit">Button</button>), @@ -477,15 +468,6 @@ class FormTagHelperTest < ActionView::TestCase ) end - def test_button_tag_with_deprecated_confirmation - assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use 'data: { confirm: \'Text\' }' instead" do - assert_dom_equal( - %(<button name="button" type="submit" data-confirm="Are you sure?">Save</button>), - button_tag("Save", :type => "submit", :confirm => "Are you sure?") - ) - end - end - def test_image_submit_tag_with_confirmation assert_dom_equal( %(<input alt="Save" type="image" src="/images/save.gif" data-confirm="Are you sure?" />), @@ -493,16 +475,6 @@ class FormTagHelperTest < ActionView::TestCase ) end - def test_image_submit_tag_with_deprecated_confirmation - assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use 'data: { confirm: \'Text\' }' instead" do - assert_dom_equal( - %(<input alt="Save" type="image" src="/images/save.gif" data-confirm="Are you sure?" />), - image_submit_tag("save.gif", :confirm => "Are you sure?") - ) - end - end - - def test_color_field_tag expected = %{<input id="car" name="car" type="color" />} assert_dom_equal(expected, color_field_tag("car")) diff --git a/actionpack/test/template/html-scanner/cdata_node_test.rb b/actionview/test/template/html-scanner/cdata_node_test.rb index 9b58174641..9b58174641 100644 --- a/actionpack/test/template/html-scanner/cdata_node_test.rb +++ b/actionview/test/template/html-scanner/cdata_node_test.rb diff --git a/actionpack/test/template/html-scanner/document_test.rb b/actionview/test/template/html-scanner/document_test.rb index 17f045d549..17f045d549 100644 --- a/actionpack/test/template/html-scanner/document_test.rb +++ b/actionview/test/template/html-scanner/document_test.rb diff --git a/actionpack/test/template/html-scanner/node_test.rb b/actionview/test/template/html-scanner/node_test.rb index 5b5d092036..5b5d092036 100644 --- a/actionpack/test/template/html-scanner/node_test.rb +++ b/actionview/test/template/html-scanner/node_test.rb diff --git a/actionpack/test/template/html-scanner/sanitizer_test.rb b/actionview/test/template/html-scanner/sanitizer_test.rb index b1c1b83807..b1c1b83807 100644 --- a/actionpack/test/template/html-scanner/sanitizer_test.rb +++ b/actionview/test/template/html-scanner/sanitizer_test.rb diff --git a/actionpack/test/template/html-scanner/tag_node_test.rb b/actionview/test/template/html-scanner/tag_node_test.rb index a29d2d43d7..a29d2d43d7 100644 --- a/actionpack/test/template/html-scanner/tag_node_test.rb +++ b/actionview/test/template/html-scanner/tag_node_test.rb diff --git a/actionpack/test/template/html-scanner/text_node_test.rb b/actionview/test/template/html-scanner/text_node_test.rb index cbcb9e78f0..cbcb9e78f0 100644 --- a/actionpack/test/template/html-scanner/text_node_test.rb +++ b/actionview/test/template/html-scanner/text_node_test.rb diff --git a/actionpack/test/template/html-scanner/tokenizer_test.rb b/actionview/test/template/html-scanner/tokenizer_test.rb index 1d59de23b6..1d59de23b6 100644 --- a/actionpack/test/template/html-scanner/tokenizer_test.rb +++ b/actionview/test/template/html-scanner/tokenizer_test.rb diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionview/test/template/javascript_helper_test.rb index 1eed8adb62..de6a6eaab3 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionview/test/template/javascript_helper_test.rb @@ -42,48 +42,6 @@ class JavaScriptHelperTest < ActionView::TestCase assert_instance_of ActiveSupport::SafeBuffer, escape_javascript(ActiveSupport::SafeBuffer.new(given)) end - def test_button_to_function - assert_deprecated do - assert_dom_equal %(<input type="button" onclick="alert('Hello world!');" value="Greeting" />), - button_to_function("Greeting", "alert('Hello world!')") - end - end - - def test_button_to_function_with_onclick - assert_deprecated do - assert_dom_equal "<input onclick=\"alert('Goodbye World :('); alert('Hello world!');\" type=\"button\" value=\"Greeting\" />", - button_to_function("Greeting", "alert('Hello world!')", :onclick => "alert('Goodbye World :(')") - end - end - - def test_button_to_function_without_function - assert_deprecated do - assert_dom_equal "<input onclick=\";\" type=\"button\" value=\"Greeting\" />", - button_to_function("Greeting") - end - end - - def test_link_to_function - assert_deprecated do - assert_dom_equal %(<a href="#" onclick="alert('Hello world!'); return false;">Greeting</a>), - link_to_function("Greeting", "alert('Hello world!')") - end - end - - def test_link_to_function_with_existing_onclick - assert_deprecated do - assert_dom_equal %(<a href="#" onclick="confirm('Sanity!'); alert('Hello world!'); return false;">Greeting</a>), - link_to_function("Greeting", "alert('Hello world!')", :onclick => "confirm('Sanity!')") - end - end - - def test_function_with_href - assert_deprecated do - assert_dom_equal %(<a href="http://example.com/" onclick="alert('Hello world!'); return false;">Greeting</a>), - link_to_function("Greeting", "alert('Hello world!')", :href => 'http://example.com/') - end - end - def test_javascript_tag self.output_buffer = 'foo' diff --git a/actionpack/test/template/log_subscriber_test.rb b/actionview/test/template/log_subscriber_test.rb index 7f4c84929f..7f4c84929f 100644 --- a/actionpack/test/template/log_subscriber_test.rb +++ b/actionview/test/template/log_subscriber_test.rb diff --git a/actionpack/test/template/lookup_context_test.rb b/actionview/test/template/lookup_context_test.rb index 073bd14783..073bd14783 100644 --- a/actionpack/test/template/lookup_context_test.rb +++ b/actionview/test/template/lookup_context_test.rb diff --git a/actionpack/test/template/number_helper_test.rb b/actionview/test/template/number_helper_test.rb index 6e640889d2..6e640889d2 100644 --- a/actionpack/test/template/number_helper_test.rb +++ b/actionview/test/template/number_helper_test.rb diff --git a/actionpack/test/template/output_buffer_test.rb b/actionview/test/template/output_buffer_test.rb index eb0df3d1ab..eb0df3d1ab 100644 --- a/actionpack/test/template/output_buffer_test.rb +++ b/actionview/test/template/output_buffer_test.rb diff --git a/actionpack/test/template/output_safety_helper_test.rb b/actionview/test/template/output_safety_helper_test.rb index 76c71c9e6d..76c71c9e6d 100644 --- a/actionpack/test/template/output_safety_helper_test.rb +++ b/actionview/test/template/output_safety_helper_test.rb diff --git a/actionpack/test/template/record_identifier_test.rb b/actionview/test/template/record_identifier_test.rb index 22038110a5..22038110a5 100644 --- a/actionpack/test/template/record_identifier_test.rb +++ b/actionview/test/template/record_identifier_test.rb diff --git a/actionpack/test/template/record_tag_helper_test.rb b/actionview/test/template/record_tag_helper_test.rb index ab84bccb56..ab84bccb56 100644 --- a/actionpack/test/template/record_tag_helper_test.rb +++ b/actionview/test/template/record_tag_helper_test.rb diff --git a/actionpack/test/template/render_test.rb b/actionview/test/template/render_test.rb index 81f3391fcd..8cffe73cce 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionview/test/template/render_test.rb @@ -376,6 +376,7 @@ module RenderTestCases def test_render_ignores_templates_with_malformed_template_handlers ActiveSupport::Deprecation.silence do %w(malformed malformed.erb malformed.html.erb malformed.en.html.erb).each do |name| + assert File.exists?(File.expand_path("#{FIXTURE_LOAD_PATH}/test/malformed/#{name}~")), "Malformed file (#{name}~) which should be ignored does not exists" assert_raises(ActionView::MissingTemplate) { @view.render(:file => "test/malformed/#{name}") } end end diff --git a/actionpack/test/template/resolver_patterns_test.rb b/actionview/test/template/resolver_patterns_test.rb index 97b1bad055..97b1bad055 100644 --- a/actionpack/test/template/resolver_patterns_test.rb +++ b/actionview/test/template/resolver_patterns_test.rb diff --git a/actionpack/test/template/sanitize_helper_test.rb b/actionview/test/template/sanitize_helper_test.rb index 12d5260a9d..12d5260a9d 100644 --- a/actionpack/test/template/sanitize_helper_test.rb +++ b/actionview/test/template/sanitize_helper_test.rb diff --git a/actionpack/test/template/streaming_render_test.rb b/actionview/test/template/streaming_render_test.rb index 520bf3a824..8a24d78e74 100644 --- a/actionpack/test/template/streaming_render_test.rb +++ b/actionview/test/template/streaming_render_test.rb @@ -1,6 +1,5 @@ # encoding: utf-8 require 'abstract_unit' -require 'controller/fake_models' class TestController < ActionController::Base end diff --git a/actionpack/test/template/tag_helper_test.rb b/actionview/test/template/tag_helper_test.rb index 9e711c6529..802da5d566 100644 --- a/actionpack/test/template/tag_helper_test.rb +++ b/actionview/test/template/tag_helper_test.rb @@ -30,8 +30,8 @@ class TagHelperTest < ActionView::TestCase end def test_tag_options_converts_boolean_option - assert_equal '<p disabled="disabled" itemscope="itemscope" multiple="multiple" readonly="readonly" />', - tag("p", :disabled => true, :itemscope => true, :multiple => true, :readonly => true) + assert_dom_equal '<p disabled="disabled" itemscope="itemscope" multiple="multiple" readonly="readonly" allowfullscreen="allowfullscreen" seamless="seamless" typemustmatch="typemustmatch" sortable="sortable" default="default" inert="inert" truespeed="truespeed" />', + tag("p", :disabled => true, :itemscope => true, :multiple => true, :readonly => true, :allowfullscreen => true, :seamless => true, :typemustmatch => true, :sortable => true, :default => true, :inert => true, :truespeed => true) end def test_content_tag diff --git a/actionpack/test/template/template_error_test.rb b/actionview/test/template/template_error_test.rb index 91424daeed..91424daeed 100644 --- a/actionpack/test/template/template_error_test.rb +++ b/actionview/test/template/template_error_test.rb diff --git a/actionpack/test/template/template_test.rb b/actionview/test/template/template_test.rb index 8d32205fb8..c94508d678 100644 --- a/actionpack/test/template/template_test.rb +++ b/actionview/test/template/template_test.rb @@ -64,13 +64,6 @@ class TestERBTemplate < ActiveSupport::TestCase @context = Context.new end - def test_mime_type_is_deprecated - template = new_template - assert_deprecated 'Template#mime_type is deprecated and will be removed' do - template.mime_type - end - end - def test_basic_template @template = new_template assert_equal "Hello", render diff --git a/actionpack/test/template/test_case_test.rb b/actionview/test/template/test_case_test.rb index acd002ce73..4ee0930341 100644 --- a/actionpack/test/template/test_case_test.rb +++ b/actionview/test/template/test_case_test.rb @@ -1,5 +1,4 @@ require 'abstract_unit' -require 'controller/fake_controllers' module ActionView diff --git a/actionpack/test/template/test_test.rb b/actionview/test/template/test_test.rb index 108a674d95..108a674d95 100644 --- a/actionpack/test/template/test_test.rb +++ b/actionview/test/template/test_test.rb diff --git a/actionpack/test/template/testing/fixture_resolver_test.rb b/actionview/test/template/testing/fixture_resolver_test.rb index 9649f349cb..9649f349cb 100644 --- a/actionpack/test/template/testing/fixture_resolver_test.rb +++ b/actionview/test/template/testing/fixture_resolver_test.rb diff --git a/actionpack/test/template/testing/null_resolver_test.rb b/actionview/test/template/testing/null_resolver_test.rb index 55ec36e753..55ec36e753 100644 --- a/actionpack/test/template/testing/null_resolver_test.rb +++ b/actionview/test/template/testing/null_resolver_test.rb diff --git a/actionpack/test/template/text_helper_test.rb b/actionview/test/template/text_helper_test.rb index 1b2234f4e2..1b2234f4e2 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionview/test/template/text_helper_test.rb diff --git a/actionpack/test/template/translation_helper_test.rb b/actionview/test/template/translation_helper_test.rb index d496dbb35e..d496dbb35e 100644 --- a/actionpack/test/template/translation_helper_test.rb +++ b/actionview/test/template/translation_helper_test.rb diff --git a/actionpack/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb index 9b4c419807..8373d7f992 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionview/test/template/url_helper_test.rb @@ -1,6 +1,5 @@ # encoding: utf-8 require 'abstract_unit' -require 'controller/fake_controllers' class UrlHelperTest < ActiveSupport::TestCase @@ -93,15 +92,6 @@ class UrlHelperTest < ActiveSupport::TestCase ) end - def test_button_to_with_deprecated_confirm - assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use 'data: { confirm: \'Text\' }' instead" do - assert_dom_equal( - %{<form method="post" action="http://www.example.com" class="button_to"><div><input data-confirm="Are you sure?" type="submit" value="Hello" /></div></form>}, - button_to("Hello", "http://www.example.com", confirm: "Are you sure?") - ) - end - end - def test_button_to_with_javascript_disable_with assert_dom_equal( %{<form method="post" action="http://www.example.com" class="button_to"><div><input data-disable-with="Greeting..." type="submit" value="Hello" /></div></form>}, @@ -109,15 +99,6 @@ class UrlHelperTest < ActiveSupport::TestCase ) end - def test_button_to_with_javascript_deprecated_disable_with - assert_deprecated ":disable_with option is deprecated and will be removed from Rails 4.1. Use 'data: { disable_with: \'Text\' }' instead" do - assert_dom_equal( - %{<form method="post" action="http://www.example.com" class="button_to"><div><input data-disable-with="Greeting..." type="submit" value="Hello" /></div></form>}, - button_to("Hello", "http://www.example.com", disable_with: "Greeting...") - ) - end - end - def test_button_to_with_remote_and_form_options assert_dom_equal( %{<form method="post" action="http://www.example.com" class="custom-class" data-remote="true" data-type="json"><div><input type="submit" value="Hello" /></div></form>}, @@ -132,15 +113,6 @@ class UrlHelperTest < ActiveSupport::TestCase ) end - def test_button_to_with_remote_and_javascript_with_deprecated_confirm - assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use 'data: { confirm: \'Text\' }' instead" do - assert_dom_equal( - %{<form method="post" action="http://www.example.com" class="button_to" data-remote="true"><div><input data-confirm="Are you sure?" type="submit" value="Hello" /></div></form>}, - button_to("Hello", "http://www.example.com", remote: true, confirm: "Are you sure?") - ) - end - end - def test_button_to_with_remote_and_javascript_disable_with assert_dom_equal( %{<form method="post" action="http://www.example.com" class="button_to" data-remote="true"><div><input data-disable-with="Greeting..." type="submit" value="Hello" /></div></form>}, @@ -148,15 +120,6 @@ class UrlHelperTest < ActiveSupport::TestCase ) end - def test_button_to_with_remote_and_javascript_deprecated_disable_with - assert_deprecated ":disable_with option is deprecated and will be removed from Rails 4.1. Use 'data: { disable_with: \'Text\' }' instead" do - assert_dom_equal( - %{<form method="post" action="http://www.example.com" class="button_to" data-remote="true"><div><input data-disable-with="Greeting..." type="submit" value="Hello" /></div></form>}, - button_to("Hello", "http://www.example.com", remote: true, disable_with: "Greeting...") - ) - end - end - def test_button_to_with_remote_false assert_dom_equal( %{<form method="post" action="http://www.example.com" class="button_to"><div><input type="submit" value="Hello" /></div></form>}, @@ -265,27 +228,6 @@ class UrlHelperTest < ActiveSupport::TestCase ) end - def test_link_tag_with_deprecated_confirm - assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use 'data: { confirm: \'Text\' }' instead" do - assert_dom_equal( - %{<a href="http://www.example.com" data-confirm="Are you sure?">Hello</a>}, - link_to("Hello", "http://www.example.com", confirm: "Are you sure?") - ) - end - assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use 'data: { confirm: \'Text\' }' instead" do - assert_dom_equal( - %{<a href="http://www.example.com" data-confirm="You cant possibly be sure, can you?">Hello</a>}, - link_to("Hello", "http://www.example.com", confirm: "You cant possibly be sure, can you?") - ) - end - assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use 'data: { confirm: \'Text\' }' instead" do - assert_dom_equal( - %{<a href="http://www.example.com" data-confirm="You cant possibly be sure,\n can you?">Hello</a>}, - link_to("Hello", "http://www.example.com", confirm: "You cant possibly be sure,\n can you?") - ) - end - end - def test_link_to_with_remote assert_dom_equal( %{<a href="http://www.example.com" data-remote="true">Hello</a>}, @@ -349,15 +291,6 @@ class UrlHelperTest < ActiveSupport::TestCase ) end - def test_link_tag_using_post_javascript_and_with_deprecated_confirm - assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use 'data: { confirm: \'Text\' }' instead" do - assert_dom_equal( - %{<a href="http://www.example.com" data-method="post" rel="nofollow" data-confirm="Are you serious?">Hello</a>}, - link_to("Hello", "http://www.example.com", method: :post, confirm: "Are you serious?") - ) - end - end - def test_link_tag_using_delete_javascript_and_href_and_confirm assert_dom_equal( %{<a href="\#" rel="nofollow" data-confirm="Are you serious?" data-method="delete">Destroy</a>}, @@ -365,15 +298,6 @@ class UrlHelperTest < ActiveSupport::TestCase ) end - def test_link_tag_using_delete_javascript_and_href_and_with_deprecated_confirm - assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use 'data: { confirm: \'Text\' }' instead" do - assert_dom_equal( - %{<a href="\#" rel="nofollow" data-confirm="Are you serious?" data-method="delete">Destroy</a>}, - link_to("Destroy", "http://www.example.com", method: :delete, href: '#', confirm: "Are you serious?") - ) - end - end - def test_link_tag_with_block assert_dom_equal %{<a href="/"><span>Example site</span></a>}, link_to('/') { content_tag(:span, 'Example site') } @@ -423,6 +347,11 @@ class UrlHelperTest < ActiveSupport::TestCase link_to_unless(true, "Showing", url_hash) { "test" } + + assert_equal %{<b>Showing</b>}, link_to_unless(true, "<b>Showing</b>", url_hash) + assert_equal %{<a href="/"><b>Showing</b></a>}, link_to_unless(false, "<b>Showing</b>", url_hash) + assert_equal %{<b>Showing</b>}, link_to_unless(true, "<b>Showing</b>".html_safe, url_hash) + assert_equal %{<a href="/"><b>Showing</b></a>}, link_to_unless(false, "<b>Showing</b>".html_safe, url_hash) end def test_link_to_if diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index b73d688964..0568e5d545 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -1,7 +1,17 @@ -* `validates_inclusion_of` for ranges uses the speedy Range#cover for numerical ranges, and the accurate Range#include? for non-numerical ranges. +* `inclusion` / `exclusion` validations with ranges will only use the faster + `Range#cover` for numerical ranges, and the more accurate `Range#include?` + for non-numerical ones. + + Fixes range validations like `:a..:f` that used to pass with values like `:be`. + Fixes #10593 *Charles Bergeron* +* Fix regression in has_secure_password. When a password is set, but a + confirmation is an empty string, it would incorrectly save. + + *Steve Klabnik* and *Phillip Calvin* + * Deprecate `Validator#setup`. This should be done manually now in the validator's constructor. *Nick Sutterer* diff --git a/activemodel/Rakefile b/activemodel/Rakefile index fc5aaf9f8f..f72b949c64 100644 --- a/activemodel/Rakefile +++ b/activemodel/Rakefile @@ -20,7 +20,6 @@ namespace :test do end end -require 'rake/packagetask' require 'rubygems/package_task' spec = eval(File.read("#{dir}/activemodel.gemspec")) @@ -29,7 +28,7 @@ Gem::PackageTask.new(spec) do |p| p.gem_spec = spec end -desc "Release to gemcutter" +desc "Release to rubygems" task :release => :package do require 'rake/gemcutter' Rake::Gemcutter::Tasks.new(spec).define diff --git a/activemodel/examples/validations.rb b/activemodel/examples/validations.rb index a56ec4db39..2c5cc11f49 100644 --- a/activemodel/examples/validations.rb +++ b/activemodel/examples/validations.rb @@ -4,7 +4,7 @@ class Person include ActiveModel::Conversion include ActiveModel::Validations - validates_presence_of :name + validates :name, presence: true attr_accessor :name diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb index 8b09f8b203..377aa6ee27 100644 --- a/activemodel/lib/active_model/callbacks.rb +++ b/activemodel/lib/active_model/callbacks.rb @@ -135,7 +135,10 @@ module ActiveModel klass.define_singleton_method("after_#{callback}") do |*args, &block| options = args.extract_options! options[:prepend] = true - options[:if] = Array(options[:if]) << "value != false" + conditional = ActiveSupport::Callbacks::Conditionals::Value.new { |v| + v != false + } + options[:if] = Array(options[:if]) << conditional set_callback(:"#{callback}", :after, *(args << options), &block) end end diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb index cafdb946c0..ea5ddf71de 100644 --- a/activemodel/lib/active_model/dirty.rb +++ b/activemodel/lib/active_model/dirty.rb @@ -142,23 +142,23 @@ module ActiveModel @changed_attributes ||= {} end - private + # Handle <tt>*_changed?</tt> for +method_missing+. + def attribute_changed?(attr) + changed_attributes.include?(attr) + end - # Handle <tt>*_changed?</tt> for +method_missing+. - def attribute_changed?(attr) - changed_attributes.include?(attr) - end + # Handle <tt>*_was</tt> for +method_missing+. + def attribute_was(attr) + attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr) + end + + private # Handle <tt>*_change</tt> for +method_missing+. def attribute_change(attr) [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr) end - # Handle <tt>*_was</tt> for +method_missing+. - def attribute_was(attr) - attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr) - end - # Handle <tt>*_will_change!</tt> for +method_missing+. def attribute_will_change!(attr) return if attribute_changed?(attr) diff --git a/activemodel/lib/active_model/model.rb b/activemodel/lib/active_model/model.rb index 62383a03e8..f048dda5c6 100644 --- a/activemodel/lib/active_model/model.rb +++ b/activemodel/lib/active_model/model.rb @@ -79,6 +79,8 @@ module ActiveModel params.each do |attr, value| self.public_send("#{attr}=", value) end if params + + super() end # Indicates if the model is persisted. Default is +false+. diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb index 750fd723a0..7156f1bb30 100644 --- a/activemodel/lib/active_model/secure_password.rb +++ b/activemodel/lib/active_model/secure_password.rb @@ -15,7 +15,7 @@ module ActiveModel # argument. You can add more validations by hand if need be. # # If you don't need the confirmation validation, just don't set any - # value to the password_confirmation attribute and the the validation + # value to the password_confirmation attribute and the validation # will not be triggered. # # You need to add bcrypt-ruby (~> 3.0.0) to Gemfile to use #has_secure_password: @@ -56,8 +56,9 @@ module ActiveModel include InstanceMethodsOnActivation if options.fetch(:validations, true) - validates_confirmation_of :password + validates_confirmation_of :password, if: lambda { |m| m.password.present? } validates_presence_of :password, on: :create + validates_presence_of :password_confirmation, if: lambda { |m| m.password.present? } before_create { raise "Password digest missing on new record" if password_digest.blank? } end @@ -106,9 +107,7 @@ module ActiveModel end def password_confirmation=(unencrypted_password) - unless unencrypted_password.blank? - @password_confirmation = unencrypted_password - end + @password_confirmation = unencrypted_password end end end diff --git a/activemodel/lib/active_model/serializers/json.rb b/activemodel/lib/active_model/serializers/json.rb index 9d984b7a18..05e2e089e5 100644 --- a/activemodel/lib/active_model/serializers/json.rb +++ b/activemodel/lib/active_model/serializers/json.rb @@ -109,7 +109,7 @@ module ActiveModel # # def attributes=(hash) # hash.each do |key, value| - # instance_variable_set("@#{key}", value) + # send("#{key}=", value) # end # end # diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb index 92206450d2..31c2245265 100644 --- a/activemodel/lib/active_model/validations.rb +++ b/activemodel/lib/active_model/validations.rb @@ -142,7 +142,9 @@ module ActiveModel if options.key?(:on) options = options.dup options[:if] = Array(options[:if]) - options[:if].unshift("validation_context == :#{options[:on]}") + options[:if].unshift lambda { |o| + o.validation_context == options[:on] + } end args << options set_callback(:validate, *args, &block) @@ -226,7 +228,6 @@ module ActiveModel # Person.validators_on(:name) # # => [ # # #<ActiveModel::Validations::PresenceValidator:0x007fe604914e60 @attributes=[:name], @options={}>, - # # #<ActiveModel::Validations::InclusionValidator:0x007fe603bb8780 @attributes=[:age], @options={in:0..99}> # # ] def validators_on(*attributes) attributes.flat_map do |attribute| diff --git a/activemodel/test/cases/model_test.rb b/activemodel/test/cases/model_test.rb index 24e4ca91c6..ee0fa26546 100644 --- a/activemodel/test/cases/model_test.rb +++ b/activemodel/test/cases/model_test.rb @@ -3,7 +3,30 @@ require 'cases/helper' class ModelTest < ActiveModel::TestCase include ActiveModel::Lint::Tests + module DefaultValue + def self.included(klass) + klass.class_eval { attr_accessor :hello } + end + + def initialize(*args) + @attr ||= 'default value' + super + end + end + class BasicModel + include DefaultValue + include ActiveModel::Model + attr_accessor :attr + end + + class BasicModelWithReversedMixins + include ActiveModel::Model + include DefaultValue + attr_accessor :attr + end + + class SimpleModel include ActiveModel::Model attr_accessor :attr end @@ -14,14 +37,20 @@ class ModelTest < ActiveModel::TestCase def test_initialize_with_params object = BasicModel.new(attr: "value") - assert_equal object.attr, "value" + assert_equal "value", object.attr + end + + def test_initialize_with_params_and_mixins_reversed + object = BasicModelWithReversedMixins.new(attr: "value") + assert_equal "value", object.attr end def test_initialize_with_nil_or_empty_hash_params_does_not_explode assert_nothing_raised do BasicModel.new() - BasicModel.new nil + BasicModel.new(nil) BasicModel.new({}) + SimpleModel.new(attr: 'value') end end @@ -29,4 +58,18 @@ class ModelTest < ActiveModel::TestCase object = BasicModel.new(attr: "value") assert object.persisted? == false end + + def test_mixin_inclusion_chain + object = BasicModel.new + assert_equal 'default value', object.attr + end + + def test_mixin_initializer_when_args_exist + object = BasicModel.new(hello: 'world') + assert_equal 'world', object.hello + end + + def test_mixin_initializer_when_args_dont_exist + assert_raises(NoMethodError) { SimpleModel.new(hello: 'world') } + end end diff --git a/activemodel/test/cases/railtie_test.rb b/activemodel/test/cases/railtie_test.rb index d44a3448df..0643fa775d 100644 --- a/activemodel/test/cases/railtie_test.rb +++ b/activemodel/test/cases/railtie_test.rb @@ -7,8 +7,12 @@ class RailtieTest < ActiveModel::TestCase def setup require 'active_model/railtie' + # Set a fake logger to avoid creating the log directory automatically + fake_logger = mock() + @app ||= Class.new(::Rails::Application) do config.eager_load = false + config.logger = fake_logger end end diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb index 02cd3b8a93..0b900d934d 100644 --- a/activemodel/test/cases/secure_password_test.rb +++ b/activemodel/test/cases/secure_password_test.rb @@ -94,4 +94,13 @@ class SecurePasswordTest < ActiveModel::TestCase @user.password_confirmation = "" assert @user.valid?(:update), "user should be valid" end + + test "will not save if confirmation is blank but password is not" do + @user.password = "password" + @user.password_confirmation = "" + assert_not @user.valid?(:create) + + @user.password_confirmation = "password" + assert @user.valid?(:create) + end end diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 5f63b6d7ae..e38d8aecf5 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,154 @@ +* Remove Oracle / Sqlserver / Firebird database tasks that were deprecated in 4.0. + + *kennyj* + +* `find_each` now returns an `Enumerator` when called without a block, so that it + can be chained with other `Enumerable` methods. + + *Ben Woosley* + +* `ActiveRecord::Result.each` now returns an `Enumerator` when called without + a block, so that it can be chained with other `Enumerable` methods. + + *Ben Woosley* + +* Flatten merged join_values before building the joins. + + While joining_values special treatment is given to string values. + By flattening the array it ensures that string values are detected + as strings and not arrays. + + Fixes #10669. + + *Neeraj Singh and iwiznia* + +* Do not load all child records for inverse case. + + currently `post.comments.find(Comment.first.id)` would load all + comments for the given post to set the inverse association. + + This has a huge performance penalty. Because if post has 100k + records and all these 100k records would be loaded in memory + even though the comment id was supplied. + + Fix is to use in-memory records only if loaded? is true. Otherwise + load the records using full sql. + + Fixes #10509. + + *Neeraj Singh* + +* `inspect` on Active Record model classes does not initiate a + new connection. This means that calling `inspect`, when the + database is missing, will no longer raise an exception. + Fixes #10936. + + Example: + + Author.inspect # => "Author(no database connection)" + + *Yves Senn* + +* Handle single quotes in PostgreSQL default column values. + Fixes #10881. + + *Dylan Markow* + +* Log the sql that is actually sent to the database. + + If I have a query that produces sql + `WHERE "users"."name" = 'a b'` then in the log all the + whitespace is being squeezed. So the sql that is printed in the + log is `WHERE "users"."name" = 'a b'`. + + Do not squeeze whitespace out of sql queries. Fixes #10982. + + *Neeraj Singh* + +* Fixture setup does no longer depend on `ActiveRecord::Base.configurations`. + This is relevant when `ENV["DATABASE_URL"]` is used in place of a `database.yml`. + + *Yves Senn* + +* Fix mysql2 adapter raises the correct exception when executing a query on a + closed connection. + + *Yves Senn* + +* Ambiguous reflections are on :through relationships are no longer supported. + For example, you need to change this: + + class Author < ActiveRecord::Base + has_many :posts + has_many :taggings, :through => :posts + end + + class Post < ActiveRecord::Base + has_one :tagging + has_many :taggings + end + + class Tagging < ActiveRecord::Base + end + + To this: + + class Author < ActiveRecord::Base + has_many :posts + has_many :taggings, :through => :posts, :source => :tagging + end + + class Post < ActiveRecord::Base + has_one :tagging + has_many :taggings + end + + class Tagging < ActiveRecord::Base + end + + *Aaron Peterson* + +* Remove column restrictions for `count`, let the database raise if the SQL is + invalid. The previous behavior was untested and surprising for the user. + Fixes #5554. + + Example: + + User.select("name, username").count + # Before => SELECT count(*) FROM users + # After => ActiveRecord::StatementInvalid + + # you can still use `count(:all)` to perform a query unrelated to the + # selected columns + User.select("name, username").count(:all) # => SELECT count(*) FROM users + + *Yves Senn* + +* Rails now automatically detects inverse associations. If you do not set the + `:inverse_of` option on the association, then Active Record will guess the + inverse association based on heuristics. + + Note that automatic inverse detection only works on `has_many`, `has_one`, + and `belongs_to` associations. Extra options on the associations will + also prevent the association's inverse from being found automatically. + + The automatic guessing of the inverse association uses a heuristic based + on the name of the class, so it may not work for all associations, + especially the ones with non-standard names. + + You can turn off the automatic detection of inverse associations by setting + the `:inverse_of` option to `false` like so: + + class Taggable < ActiveRecord::Base + belongs_to :tag, inverse_of: false + end + + *John Wang* + +* Fix `add_column` with `array` option when using PostgreSQL. Fixes #10432 + + *Adam Anderson* + * Usage of `implicit_readonly` is being removed`. Please use `readonly` method explicitly to mark records as `readonly. Fixes #10615. @@ -15,7 +166,7 @@ *Yves Senn* -* Fix bug where tiny types are incorectly coerced as booleand when the length is more than 1. +* Fix bug where tiny types are incorrectly coerced as boolean when the length is more than 1. Fixes #10620. @@ -28,7 +179,7 @@ * Deprecate `ConnectionAdapters::SchemaStatements#distinct`, as it is no longer used by internals. - *Ben Woosley# + *Ben Woosley* * Fix pending migrations error when loading schema and `ActiveRecord::Base.table_name_prefix` is not blank. @@ -98,8 +249,8 @@ *Olek Janiszewski* -* fixes bug introduced by #3329. Now, when autosaving associations, - deletions happen before inserts and saves. This prevents a 'duplicate +* fixes bug introduced by #3329. Now, when autosaving associations, + deletions happen before inserts and saves. This prevents a 'duplicate unique value' database error that would occur if a record being created had the same value on a unique indexed field as that of a record being destroyed. diff --git a/activerecord/Rakefile b/activerecord/Rakefile index cd73489cbe..18f03e6562 100644 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -1,5 +1,4 @@ require 'rake/testtask' -require 'rake/packagetask' require 'rubygems/package_task' require File.expand_path(File.dirname(__FILE__)) + "/test/config" @@ -63,7 +62,7 @@ end (Dir["test/cases/**/*_test.rb"].reject { |x| x =~ /\/adapters\// } + Dir["test/cases/adapters/#{adapter_short}/**/*_test.rb"]).all? do |file| - sh(ruby, "-Itest", file) + sh(ruby, '-w' ,"-Itest", file) end or raise "Failures" end @@ -223,7 +222,7 @@ end # Publishing ------------------------------------------------------ -desc "Release to gemcutter" +desc "Release to rubygems" task :release => :package do require 'rake/gemcutter' Rake::Gemcutter::Tasks.new(spec).define diff --git a/activerecord/examples/performance.rb b/activerecord/examples/performance.rb index ad12f8597f..1f23b13cac 100644 --- a/activerecord/examples/performance.rb +++ b/activerecord/examples/performance.rb @@ -5,12 +5,12 @@ require 'benchmark/ips' TIME = (ENV['BENCHMARK_TIME'] || 20).to_i RECORDS = (ENV['BENCHMARK_RECORDS'] || TIME*1000).to_i -conn = { :adapter => 'sqlite3', :database => ':memory:' } +conn = { adapter: 'sqlite3', database: ':memory:' } ActiveRecord::Base.establish_connection(conn) class User < ActiveRecord::Base - connection.create_table :users, :force => true do |t| + connection.create_table :users, force: true do |t| t.string :name, :email t.timestamps end @@ -19,7 +19,7 @@ class User < ActiveRecord::Base end class Exhibit < ActiveRecord::Base - connection.create_table :exhibits, :force => true do |t| + connection.create_table :exhibits, force: true do |t| t.belongs_to :user t.string :name t.text :notes @@ -77,28 +77,28 @@ today = Date.today puts "Inserting #{RECORDS} users and exhibits..." RECORDS.times do user = User.create( - :created_at => today, - :name => ActiveRecord::Faker.name, - :email => ActiveRecord::Faker.email + created_at: today, + name: ActiveRecord::Faker.name, + email: ActiveRecord::Faker.email ) Exhibit.create( - :created_at => today, - :name => ActiveRecord::Faker.name, - :user => user, - :notes => notes + created_at: today, + name: ActiveRecord::Faker.name, + user: user, + notes: notes ) end Benchmark.ips(TIME) do |x| ar_obj = Exhibit.find(1) - attrs = { :name => 'sam' } - attrs_first = { :name => 'sam' } - attrs_second = { :name => 'tom' } + attrs = { name: 'sam' } + attrs_first = { name: 'sam' } + attrs_second = { name: 'tom' } exhibit = { - :name => ActiveRecord::Faker.name, - :notes => notes, - :created_at => Date.today + name: ActiveRecord::Faker.name, + notes: notes, + :created_at: Date.today } x.report("Model#id") do diff --git a/activerecord/examples/simple.rb b/activerecord/examples/simple.rb index c12f746992..ee3c42a05b 100644 --- a/activerecord/examples/simple.rb +++ b/activerecord/examples/simple.rb @@ -2,13 +2,13 @@ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib" require 'active_record' class Person < ActiveRecord::Base - establish_connection :adapter => 'sqlite3', :database => 'foobar.db' - connection.create_table table_name, :force => true do |t| + establish_connection adapter: 'sqlite3', database: 'foobar.db' + connection.create_table table_name, force: true do |t| t.string :name end end -bob = Person.create!(:name => 'bob') +bob = Person.create!(name: 'bob') puts Person.all.inspect bob.destroy puts Person.all.inspect diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 3490057298..6fd4f3042c 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -586,9 +586,10 @@ module ActiveRecord # belongs_to :tag, inverse_of: :taggings # end # - # If you do not set the +:inverse_of+ record, the association will do its - # best to match itself up with the correct inverse. Automatic +:inverse_of+ - # detection only works on +has_many+, +has_one+, and +belongs_to+ associations. + # If you do not set the <tt>:inverse_of</tt> record, the association will + # do its best to match itself up with the correct inverse. Automatic + # inverse detection only works on <tt>has_many</tt>, <tt>has_one</tt>, and + # <tt>belongs_to</tt> associations. # # Extra options on the associations, as defined in the # <tt>AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS</tt> constant, will @@ -599,10 +600,10 @@ module ActiveRecord # especially the ones with non-standard names. # # You can turn off the automatic detection of inverse associations by setting - # the +:automatic_inverse_of+ option to +false+ like so: + # the <tt>:inverse_of</tt> option to <tt>false</tt> like so: # # class Taggable < ActiveRecord::Base - # belongs_to :tag, automatic_inverse_of: false + # belongs_to :tag, inverse_of: false # end # # == Nested \Associations diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 608a6af16c..ee62298793 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -200,13 +200,14 @@ module ActiveRecord creation_attributes.each { |key, value| record[key] = value } end - # Should be true if there is a foreign key present on the owner which + # Returns true if there is a foreign key present on the owner which # references the target. This is used to determine whether we can load # the target if the owner is currently a new record (and therefore - # without a key). + # without a key). If the owner is a new record then foreign_key must + # be present in order to load target. # # Currently implemented by belongs_to (vanilla and polymorphic) and - # has_one/has_many :through associations which go through a belongs_to + # has_one/has_many :through associations which go through a belongs_to. def foreign_key_present? false end diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index aa5551fe0c..f1bec5787a 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -96,7 +96,7 @@ module ActiveRecord item = eval_scope(klass, scope_chain_item) if scope_chain_item == self.reflection.scope - scope.merge! item.except(:where, :includes) + scope.merge! item.except(:where, :includes, :bind) end scope.includes! item.includes_values diff --git a/activerecord/lib/active_record/associations/builder/association.rb b/activerecord/lib/active_record/associations/builder/association.rb index 6a3658f328..3254da4677 100644 --- a/activerecord/lib/active_record/associations/builder/association.rb +++ b/activerecord/lib/active_record/associations/builder/association.rb @@ -111,13 +111,8 @@ module ActiveRecord::Associations::Builder ) end - mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1 - def #{macro}_dependent_for_#{name} - association(:#{name}).handle_dependency - end - CODE - - model.before_destroy "#{macro}_dependent_for_#{name}" + n = name + model.before_destroy lambda { |o| o.association(n).handle_dependency } end def valid_dependent_options diff --git a/activerecord/lib/active_record/associations/builder/belongs_to.rb b/activerecord/lib/active_record/associations/builder/belongs_to.rb index 63e9526436..d4e1a0dda1 100644 --- a/activerecord/lib/active_record/associations/builder/belongs_to.rb +++ b/activerecord/lib/active_record/associations/builder/belongs_to.rb @@ -19,82 +19,116 @@ module ActiveRecord::Associations::Builder reflection end - def add_counter_cache_callbacks(reflection) - cache_column = reflection.counter_cache_column - foreign_key = reflection.foreign_key + def valid_dependent_options + [:destroy, :delete] + end + + private - mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1 - def belongs_to_counter_cache_after_create_for_#{name} - if record = #{name} - record.class.increment_counter(:#{cache_column}, record.id) + def add_counter_cache_methods(mixin) + return if mixin.method_defined? :belongs_to_counter_cache_after_create + + mixin.class_eval do + def belongs_to_counter_cache_after_create(association, reflection) + if record = send(association.name) + cache_column = reflection.counter_cache_column + record.class.increment_counter(cache_column, record.id) @_after_create_counter_called = true end end - def belongs_to_counter_cache_before_destroy_for_#{name} - unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == #{foreign_key.to_sym.inspect} - record = #{name} + def belongs_to_counter_cache_before_destroy(association, reflection) + foreign_key = reflection.foreign_key.to_sym + unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key + record = send association.name if record && !self.destroyed? - record.class.decrement_counter(:#{cache_column}, record.id) + cache_column = reflection.counter_cache_column + record.class.decrement_counter(cache_column, record.id) end end end - def belongs_to_counter_cache_after_update_for_#{name} + def belongs_to_counter_cache_after_update(association, reflection) + foreign_key = reflection.foreign_key + cache_column = reflection.counter_cache_column + if (@_after_create_counter_called ||= false) @_after_create_counter_called = false - elsif self.#{foreign_key}_changed? && !new_record? && defined?(#{name.to_s.camelize}) - model = #{name.to_s.camelize} - foreign_key_was = self.#{foreign_key}_was - foreign_key = self.#{foreign_key} + elsif attribute_changed?(foreign_key) && !new_record? && association.constructable? + model = reflection.klass + foreign_key_was = attribute_was foreign_key + foreign_key = attribute foreign_key if foreign_key && model.respond_to?(:increment_counter) - model.increment_counter(:#{cache_column}, foreign_key) + model.increment_counter(cache_column, foreign_key) end if foreign_key_was && model.respond_to?(:decrement_counter) - model.decrement_counter(:#{cache_column}, foreign_key_was) + model.decrement_counter(cache_column, foreign_key_was) end end end - CODE + end + end + + def add_counter_cache_callbacks(reflection) + cache_column = reflection.counter_cache_column + add_counter_cache_methods mixin + association = self + + model.after_create lambda { |record| + record.belongs_to_counter_cache_after_create(association, reflection) + } - model.after_create "belongs_to_counter_cache_after_create_for_#{name}" - model.before_destroy "belongs_to_counter_cache_before_destroy_for_#{name}" - model.after_update "belongs_to_counter_cache_after_update_for_#{name}" + model.before_destroy lambda { |record| + record.belongs_to_counter_cache_before_destroy(association, reflection) + } + + model.after_update lambda { |record| + record.belongs_to_counter_cache_after_update(association, reflection) + } klass = reflection.class_name.safe_constantize klass.attr_readonly cache_column if klass && klass.respond_to?(:attr_readonly) end - def add_touch_callbacks(reflection) - mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1 - def belongs_to_touch_after_save_or_destroy_for_#{name} - foreign_key_field = #{reflection.foreign_key.inspect} - old_foreign_id = attribute_was(foreign_key_field) + def self.touch_record(o, foreign_key, name, touch) # :nodoc: + old_foreign_id = o.attribute_was(foreign_key) - if old_foreign_id - klass = association(#{name.inspect}).klass - old_record = klass.find_by(klass.primary_key => old_foreign_id) + if old_foreign_id + klass = o.association(name).klass + old_record = klass.find_by(klass.primary_key => old_foreign_id) - if old_record - old_record.touch #{options[:touch].inspect if options[:touch] != true} - end - end - - record = #{name} - unless record.nil? || record.new_record? - record.touch #{options[:touch].inspect if options[:touch] != true} + if old_record + if touch != true + old_record.touch touch + else + old_record.touch end end - CODE - - model.after_save "belongs_to_touch_after_save_or_destroy_for_#{name}" - model.after_touch "belongs_to_touch_after_save_or_destroy_for_#{name}" - model.after_destroy "belongs_to_touch_after_save_or_destroy_for_#{name}" + end + + record = o.send name + unless record.nil? || record.new_record? + if touch != true + record.touch touch + else + record.touch + end + end end - def valid_dependent_options - [:destroy, :delete] + def add_touch_callbacks(reflection) + foreign_key = reflection.foreign_key + n = name + touch = options[:touch] + + callback = lambda { |record| + BelongsTo.touch_record(record, foreign_key, n, touch) + } + + model.after_save callback + model.after_touch callback + model.after_destroy callback end end end diff --git a/activerecord/lib/active_record/associations/builder/has_many.rb b/activerecord/lib/active_record/associations/builder/has_many.rb index 429def5455..0d1bdd21ee 100644 --- a/activerecord/lib/active_record/associations/builder/has_many.rb +++ b/activerecord/lib/active_record/associations/builder/has_many.rb @@ -5,7 +5,7 @@ module ActiveRecord::Associations::Builder end def valid_options - super + [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of, :automatic_inverse_of, :counter_cache] + super + [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of, :counter_cache] end def valid_dependent_options diff --git a/activerecord/lib/active_record/associations/builder/singular_association.rb b/activerecord/lib/active_record/associations/builder/singular_association.rb index 96ccbeb8a3..76e48e66e5 100644 --- a/activerecord/lib/active_record/associations/builder/singular_association.rb +++ b/activerecord/lib/active_record/associations/builder/singular_association.rb @@ -3,7 +3,7 @@ module ActiveRecord::Associations::Builder class SingularAssociation < Association #:nodoc: def valid_options - super + [:remote, :dependent, :counter_cache, :primary_key, :inverse_of, :automatic_inverse_of] + super + [:remote, :dependent, :counter_cache, :primary_key, :inverse_of] end def constructable? diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index efd7ecb97c..9833822f8f 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -81,7 +81,7 @@ module ActiveRecord else if options[:finder_sql] find_by_scan(*args) - elsif options[:inverse_of] + elsif options[:inverse_of] && loaded? args = args.flatten raise RecordNotFound, "Couldn't find #{scope.klass.name} without an ID" if args.blank? diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index e82c195335..7cdb5ba5b3 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -830,7 +830,7 @@ module ActiveRecord # person.pets.include?(Pet.find(20)) # => true # person.pets.include?(Pet.find(21)) # => false def include?(record) - @association.include?(record) + !!@association.include?(record) end def proxy_association diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index 7f1ebab4cd..1287de0d0d 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -50,20 +50,17 @@ module ActiveRecord end end - # *DEPRECATED*: Use ActiveRecord::AttributeMethods::Serialization::ClassMethods#serialized_attributes class level method instead. - def serialized_attributes - message = "Instance level serialized_attributes method is deprecated, please use class level method." - ActiveSupport::Deprecation.warn message - defined?(@serialized_attributes) ? @serialized_attributes : self.class.serialized_attributes - end - class Type # :nodoc: def initialize(column) @column = column end def type_cast(value) - value.unserialized_value + if value.state == :serialized + value.unserialized_value @column.type_cast value.value + else + value.unserialized_value + end end def type @@ -72,17 +69,17 @@ module ActiveRecord end class Attribute < Struct.new(:coder, :value, :state) # :nodoc: - def unserialized_value - state == :serialized ? unserialize : value + def unserialized_value(v = value) + state == :serialized ? unserialize(v) : value end def serialized_value state == :unserialized ? serialize : value end - def unserialize + def unserialize(v) self.state = :unserialized - self.value = coder.load(value) + self.value = coder.load(v) end def serialize diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index 87d4daa6d9..a8a1847554 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -301,7 +301,7 @@ module ActiveRecord def association_valid?(reflection, record) return true if record.destroyed? || record.marked_for_destruction? - unless valid = record.valid?(validation_context) + unless valid = record.valid? if reflection.options[:autosave] record.errors.each do |attribute, message| attribute = "#{reflection.name}.#{attribute}" diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index aabedf15e9..0be4b5cb19 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -25,6 +25,9 @@ module ActiveRecord end end + class ChangeColumnDefinition < Struct.new(:column, :type, :options) #:nodoc: + end + # Represents the schema of an SQL table in an abstract way. This class # provides methods for manipulating the schema representation. # @@ -269,6 +272,7 @@ module ActiveRecord end column.limit = limit + column.array = options[:array] if column.respond_to?(:array) column.precision = options[:precision] column.scale = options[:scale] column.default = options[:default] 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 8ffe150de6..9a1923dec5 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -214,8 +214,8 @@ module ActiveRecord # its block form to do so yourself: # # create_join_table :products, :categories do |t| - # t.index :products - # t.index :categories + # t.index :product_id + # t.index :category_id # end # # ====== Add a backend specific option to the generated SQL (MySQL) @@ -606,7 +606,7 @@ module ActiveRecord index_options = options.delete(:index) add_column(table_name, "#{ref_name}_id", :integer, options) add_column(table_name, "#{ref_name}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic - add_index(table_name, polymorphic ? %w[id type].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options : nil) if index_options + add_index(table_name, polymorphic ? %w[id type].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options end alias :add_belongs_to :add_reference @@ -694,17 +694,6 @@ module ActiveRecord end end - def add_column_options!(sql, options) #:nodoc: - sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options) - # must explicitly check for :null to allow change_column to work on migrations - if options[:null] == false - sql << " NOT NULL" - end - if options[:auto_increment] == true - sql << " AUTO_INCREMENT" - end - end - # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause. # # distinct("posts.id", ["posts.created_at desc"]) @@ -775,37 +764,23 @@ module ActiveRecord column_names = Array(column_name) index_name = index_name(table_name, column: column_names) - if Hash === options # legacy support, since this param was a string - options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type) - - index_type = options[:unique] ? "UNIQUE" : "" - index_type = options[:type].to_s if options.key?(:type) - index_name = options[:name].to_s if options.key?(:name) - max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length + options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type) - if options.key?(:algorithm) - algorithm = index_algorithms.fetch(options[:algorithm]) { - raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}") - } - end + index_type = options[:unique] ? "UNIQUE" : "" + index_type = options[:type].to_s if options.key?(:type) + index_name = options[:name].to_s if options.key?(:name) + max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length - using = "USING #{options[:using]}" if options[:using].present? - - if supports_partial_index? - index_options = options[:where] ? " WHERE #{options[:where]}" : "" - end - else - if options - message = "Passing a string as third argument of `add_index` is deprecated and will" + - " be removed in Rails 4.1." + - " Use add_index(#{table_name.inspect}, #{column_name.inspect}, unique: true) instead" + if options.key?(:algorithm) + algorithm = index_algorithms.fetch(options[:algorithm]) { + raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}") + } + end - ActiveSupport::Deprecation.warn message - end + using = "USING #{options[:using]}" if options[:using].present? - index_type = options - max_index_length = allowed_index_name_length - algorithm = using = nil + if supports_partial_index? + index_options = options[:where] ? " WHERE #{options[:where]}" : "" end if index_name.length > max_index_length diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 26586f0974..e232cad982 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -116,6 +116,12 @@ module ActiveRecord send m, o end + def visit_AddColumn(o) + sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale) + sql = "ADD #{quote_column_name(o.name)} #{sql_type}" + add_column_options!(sql, column_options(o)) + end + private def visit_AlterTable(o) @@ -123,12 +129,6 @@ module ActiveRecord sql << o.adds.map { |col| visit_AddColumn col }.join(' ') end - def visit_AddColumn(o) - sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale) - sql = "ADD #{quote_column_name(o.name)} #{sql_type}" - add_column_options!(sql, column_options(o)) - end - def visit_ColumnDefinition(o) sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale) column_sql = "#{quote_column_name(o.name)} #{sql_type}" @@ -149,6 +149,8 @@ module ActiveRecord column_options[:null] = o.null unless o.null.nil? column_options[:default] = o.default unless o.default.nil? column_options[:column] = o + column_options[:first] = o.first + column_options[:after] = o.after column_options end @@ -164,9 +166,20 @@ module ActiveRecord @conn.type_to_sql type.to_sym, limit, precision, scale end - def add_column_options!(column_sql, column_options) - @conn.add_column_options! column_sql, column_options - column_sql + def add_column_options!(sql, options) + sql << " DEFAULT #{@conn.quote(options[:default], options[:column])}" if options_include_default?(options) + # must explicitly check for :null to allow change_column to work on migrations + if options[:null] == false + sql << " NOT NULL" + end + if options[:auto_increment] == true + sql << " AUTO_INCREMENT" + end + sql + end + + def options_include_default?(options) + options.include?(:default) && !(options[:null] == false && options[:default].nil?) end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index d098ded77c..5b25b26164 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -4,17 +4,26 @@ module ActiveRecord module ConnectionAdapters class AbstractMysqlAdapter < AbstractAdapter class SchemaCreation < AbstractAdapter::SchemaCreation - private def visit_AddColumn(o) - add_column_position!(super, o) + add_column_position!(super, column_options(o)) + end + + private + def visit_ChangeColumnDefinition(o) + column = o.column + options = o.options + sql_type = type_to_sql(o.type, options[:limit], options[:precision], options[:scale]) + change_column_sql = "CHANGE #{quote_column_name(column.name)} #{quote_column_name(options[:name])} #{sql_type}" + add_column_options!(change_column_sql, options) + add_column_position!(change_column_sql, options) end - def add_column_position!(sql, column) - if column.first + def add_column_position!(sql, options) + if options[:first] sql << " FIRST" - elsif column.after - sql << " AFTER #{quote_column_name(column.after)}" + elsif options[:after] + sql << " AFTER #{quote_column_name(options[:after])}" end sql end @@ -661,10 +670,9 @@ module ActiveRecord end def add_column_sql(table_name, column_name, type, options = {}) - add_column_sql = "ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" - add_column_options!(add_column_sql, options) - add_column_position!(add_column_sql, options) - add_column_sql + td = create_table_definition table_name, options[:temporary], options[:options] + cd = td.new_column_definition(column_name, type, options) + schema_creation.visit_AddColumn cd end def change_column_sql(table_name, column_name, type, options = {}) @@ -678,14 +686,12 @@ module ActiveRecord options[:null] = column.null end - change_column_sql = "CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" - add_column_options!(change_column_sql, options) - add_column_position!(change_column_sql, options) - change_column_sql + options[:name] = column.name + schema_creation.accept ChangeColumnDefinition.new column, type, options end def rename_column_sql(table_name, column_name, new_column_name) - options = {} + options = { name: new_column_name } if column = columns(table_name).find { |c| c.name == column_name.to_s } options[:default] = column.default @@ -696,9 +702,7 @@ module ActiveRecord end current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'", 'SCHEMA')["Type"] - rename_column_sql = "CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}" - add_column_options!(rename_column_sql, options) - rename_column_sql + schema_creation.accept ChangeColumnDefinition.new column, current_type, options end def remove_column_sql(table_name, column_name, type = nil, options = {}) diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 530a27d099..edeb338310 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -213,9 +213,11 @@ module ActiveRecord # Executes the SQL statement in the context of this connection. def execute(sql, name = nil) - # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been - # made since we established the connection - @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone + if @connection + # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been + # made since we established the connection + @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone + end super end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index d5a603cadc..98126249df 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -84,7 +84,7 @@ module ActiveRecord $1 # Character types when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m - $1 + $1.gsub(/''/, "'") # Binary data types when /\A'(.*)'::bytea\z/m $1 diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index ba053700f2..f0141aaaab 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -123,6 +123,8 @@ module ActiveRecord super elsif abstract_class? "#{super}(abstract)" + elsif !connected? + "#{super}(no database connection)" elsif table_exists? attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', ' "#{super}(#{attr_list})" diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb index 81cca37939..e1faadf1ab 100644 --- a/activerecord/lib/active_record/counter_cache.rb +++ b/activerecord/lib/active_record/counter_cache.rb @@ -50,7 +50,7 @@ module ActiveRecord # ==== Parameters # # * +id+ - The id of the object you wish to update a counter on or an Array of ids. - # * +counters+ - An Array of Hashes containing the names of the fields + # * +counters+ - A Hash containing the names of the fields # to update as keys and the amount to update the field by as values. # # ==== Examples diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index 017b8bace6..7e38719811 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -69,10 +69,6 @@ module ActiveRecord end end - # Raised when SQL statement is invalid and the application gets a blank result. - class ThrowResult < ActiveRecordError - end - # Defunct wrapper class kept for compatibility. # +StatementInvalid+ wraps the original exception now. class WrappedDatabaseException < StatementInvalid diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 33e19313a0..70eda332b3 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -841,8 +841,6 @@ module ActiveRecord end def setup_fixtures - return if ActiveRecord::Base.configurations.blank? - if pre_loaded_fixtures && !use_transactional_fixtures raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures' end @@ -875,8 +873,6 @@ module ActiveRecord end def teardown_fixtures - return if ActiveRecord::Base.configurations.blank? - # Rollback changes if a transaction is active. if run_in_transaction? @fixture_connections.each do |connection| diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb index 40976bc29e..e826762def 100644 --- a/activerecord/lib/active_record/inheritance.rb +++ b/activerecord/lib/active_record/inheritance.rb @@ -5,7 +5,7 @@ module ActiveRecord extend ActiveSupport::Concern included do - # Determine whether to store the full constant name including namespace when using STI + # Determines whether to store the full constant name including namespace when using STI. class_attribute :store_full_sti_class, instance_writer: false self.store_full_sti_class = true end @@ -13,7 +13,7 @@ module ActiveRecord module ClassMethods # Determines if one of the attributes passed in is the inheritance column, # and if the inheritance column is attr accessible, it initializes an - # instance of the given subclass instead of the base class + # instance of the given subclass instead of the base class. def new(*args, &block) if abstract_class? || self == Base raise NotImplementedError, "#{self} is an abstract class and can not be instantiated." @@ -27,7 +27,8 @@ module ActiveRecord super end - # True if this isn't a concrete subclass needing a STI type condition. + # Returns +true+ if this does not need STI type condition. Returns + # +false+ if STI type condition needs to be applied. def descends_from_active_record? if self == Base false diff --git a/activerecord/lib/active_record/locking/pessimistic.rb b/activerecord/lib/active_record/locking/pessimistic.rb index 8e4ddcac82..ddf2afca0c 100644 --- a/activerecord/lib/active_record/locking/pessimistic.rb +++ b/activerecord/lib/active_record/locking/pessimistic.rb @@ -64,7 +64,7 @@ module ActiveRecord end # Wraps the passed block in a transaction, locking the object - # before yielding. You pass can the SQL locking clause + # before yielding. You can pass the SQL locking clause # as argument (see <tt>lock!</tt>). def with_lock(lock = true) transaction do diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb index 61e5c120df..0358a36b14 100644 --- a/activerecord/lib/active_record/log_subscriber.rb +++ b/activerecord/lib/active_record/log_subscriber.rb @@ -41,7 +41,7 @@ module ActiveRecord return if IGNORE_PAYLOAD_NAMES.include?(payload[:name]) name = "#{payload[:name]} (#{event.duration.round(1)}ms)" - sql = payload[:sql].squeeze(' ') + sql = payload[:sql] binds = nil unless (payload[:binds] || []).empty? diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 511a1585a7..e96c347f6f 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -357,11 +357,14 @@ module ActiveRecord class CheckPending def initialize(app) @app = app + @last_check = 0 end def call(env) - ActiveRecord::Base.logger.silence do + mtime = ActiveRecord::Migrator.last_migration.mtime.to_i + if @last_check < mtime ActiveRecord::Migration.check_pending! + @last_check = mtime end @app.call(env) end @@ -700,6 +703,10 @@ module ActiveRecord File.basename(filename) end + def mtime + File.mtime filename + end + delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration private @@ -715,6 +722,16 @@ module ActiveRecord end + class NullMigration < MigrationProxy #:nodoc: + def initialize + super(nil, 0, nil, nil) + end + + def mtime + 0 + end + end + class Migrator#:nodoc: class << self attr_writer :migrations_paths @@ -785,7 +802,11 @@ module ActiveRecord end def last_version - migrations(migrations_paths).last.try(:version)||0 + last_migration.version + end + + def last_migration #:nodoc: + migrations(migrations_paths).last || NullMigration.new end def proper_table_name(name) diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index 8bdaeef924..e53e8553ad 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -230,6 +230,10 @@ module ActiveRecord # validates_presence_of :member # end # + # Note that if you do not specify the <tt>inverse_of</tt> option, then + # Active Record will try to automatically guess the inverse association + # based on heuristics. + # # For one-to-one nested associations, if you build the new (in-memory) # child object yourself before assignment, then this module will not # overwrite it, e.g.: @@ -302,14 +306,9 @@ module ActiveRecord attr_names.each do |association_name| if reflection = reflect_on_association(association_name) - reflection.options[:autosave] = true + reflection.autosave = true add_autosave_association_callbacks(reflection) - # Clear cached values of any inverse associations found in the - # reflection and prevent the reflection from finding inverses - # automatically in the future. - reflection.remove_automatic_inverse_of! - nested_attributes_options = self.nested_attributes_options.dup nested_attributes_options[association_name.to_sym] = options self.nested_attributes_options = nested_attributes_options diff --git a/activerecord/lib/active_record/null_relation.rb b/activerecord/lib/active_record/null_relation.rb index 711fc8b883..d166f0dd66 100644 --- a/activerecord/lib/active_record/null_relation.rb +++ b/activerecord/lib/active_record/null_relation.rb @@ -39,7 +39,7 @@ module ActiveRecord end def to_sql - @to_sql ||= "" + "" end def where_values_hash @@ -55,7 +55,11 @@ module ActiveRecord end def calculate(_operation, _column_name, _options = {}) - nil + if _operation == :count + 0 + else + nil + end end def exists?(_id = false) diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index a8905ed739..582006ea7d 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -333,10 +333,44 @@ module ActiveRecord toggle(attribute).update_attribute(attribute, self[attribute]) end - # Reloads the attributes of this object from the database. - # The optional options argument is passed to find when reloading so you - # may do e.g. record.reload(lock: true) to reload the same record with - # an exclusive row lock. + # Reloads the record from the database. + # + # This method modifies the receiver in-place. Attributes are updated, and + # caches busted, in particular the associations cache. + # + # If the record no longer exists in the database <tt>ActiveRecord::RecordNotFound</tt> + # is raised. Otherwise, in addition to the in-place modification the method + # returns +self+ for convenience. + # + # The optional <tt>:lock</tt> flag option allows you to lock the reloaded record: + # + # reload(lock: true) # reload with pessimistic locking + # + # Reloading is commonly used in test suites to test something is actually + # written to the database, or when some action modifies the corresponding + # row in the database but not the object in memory: + # + # assert account.deposit!(25) + # assert_equal 25, account.credit # check it is updated in memory + # assert_equal 25, account.reload.credit # check it is also persisted + # + # Another commom use case is optimistic locking handling: + # + # def with_optimistic_retry + # begin + # yield + # rescue ActiveRecord::StaleObjectError + # begin + # # Reload lock_version in particular. + # reload + # rescue ActiveRecord::RecordNotFound + # # If the record is gone there is nothing to do. + # else + # retry + # end + # end + # end + # def reload(options = nil) clear_aggregation_cache clear_association_cache diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index 31a0ace864..afb0be7b74 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -37,16 +37,21 @@ module ActiveRecord rake_tasks do require "active_record/base" - ActiveRecord::Tasks::DatabaseTasks.env = Rails.env - ActiveRecord::Tasks::DatabaseTasks.db_dir = Rails.application.config.paths["db"].first ActiveRecord::Tasks::DatabaseTasks.seed_loader = Rails.application - ActiveRecord::Tasks::DatabaseTasks.database_configuration = Rails.application.config.database_configuration - ActiveRecord::Tasks::DatabaseTasks.migrations_paths = Rails.application.paths['db/migrate'].to_a - ActiveRecord::Tasks::DatabaseTasks.fixtures_path = File.join Rails.root, 'test', 'fixtures' + ActiveRecord::Tasks::DatabaseTasks.env = Rails.env + + namespace :db do + task :load_config do + ActiveRecord::Tasks::DatabaseTasks.db_dir = Rails.application.config.paths["db"].first + ActiveRecord::Tasks::DatabaseTasks.database_configuration = Rails.application.config.database_configuration + ActiveRecord::Tasks::DatabaseTasks.migrations_paths = Rails.application.paths['db/migrate'].to_a + ActiveRecord::Tasks::DatabaseTasks.fixtures_path = File.join Rails.root, 'test', 'fixtures' - if defined?(APP_RAKEFILE) && engine = Rails::Engine.find(find_engine_path(APP_RAKEFILE)) - if engine.paths['db/migrate'].existent - ActiveRecord::Tasks::DatabaseTasks.migrations_paths += engine.paths['db/migrate'].to_a + if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH) + if engine.paths['db/migrate'].existent + ActiveRecord::Tasks::DatabaseTasks.migrations_paths += engine.paths['db/migrate'].to_a + end + end end end diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index f69e9b2217..0b74553bf8 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -324,7 +324,7 @@ db_namespace = namespace :db do ActiveRecord::Schema.verbose = false db_namespace["schema:load"].invoke ensure - ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[Rails.env]) + ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env]) end end diff --git a/activerecord/lib/active_record/readonly_attributes.rb b/activerecord/lib/active_record/readonly_attributes.rb index 8499bb16e7..b3ddfd63d4 100644 --- a/activerecord/lib/active_record/readonly_attributes.rb +++ b/activerecord/lib/active_record/readonly_attributes.rb @@ -20,11 +20,5 @@ module ActiveRecord self._attr_readonly end end - - def _attr_readonly - message = "Instance level _attr_readonly method is deprecated, please use class level method." - ActiveSupport::Deprecation.warn message - defined?(@_attr_readonly) ? @_attr_readonly : self.class._attr_readonly - end end end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 27aa20b6c0..8a9488656b 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -5,7 +5,9 @@ module ActiveRecord included do class_attribute :reflections + class_attribute :aggregate_reflections self.reflections = {} + self.aggregate_reflections = {} end # \Reflection enables to interrogate Active Record classes and objects @@ -27,13 +29,18 @@ module ActiveRecord reflection = klass.new(macro, name, scope, options, active_record) - self.reflections = self.reflections.merge(name => reflection) + if klass == AggregateReflection + self.aggregate_reflections = self.aggregate_reflections.merge(name => reflection) + else + self.reflections = self.reflections.merge(name => reflection) + end + reflection end # Returns an array of AggregateReflection objects for all the aggregations in the class. def reflect_on_all_aggregations - reflections.values.grep(AggregateReflection) + aggregate_reflections.values end # Returns the AggregateReflection object for the named +aggregation+ (use the symbol). @@ -41,8 +48,7 @@ module ActiveRecord # Account.reflect_on_aggregation(:balance) # => the balance AggregateReflection # def reflect_on_aggregation(aggregation) - reflection = reflections[aggregation] - reflection if reflection.is_a?(AggregateReflection) + aggregate_reflections[aggregation] end # Returns an array of AssociationReflection objects for all the @@ -56,7 +62,7 @@ module ActiveRecord # Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations # def reflect_on_all_associations(macro = nil) - association_reflections = reflections.values.grep(AssociationReflection) + association_reflections = reflections.values macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections end @@ -66,8 +72,7 @@ module ActiveRecord # Invoice.reflect_on_association(:line_items).macro # returns :has_many # def reflect_on_association(association) - reflection = reflections[association] - reflection if reflection.is_a?(AssociationReflection) + reflections[association] end # Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled. @@ -118,6 +123,11 @@ module ActiveRecord name.to_s.pluralize : name.to_s end + def autosave=(autosave) + @automatic_inverse_of = false + @options[:autosave] = autosave + end + # Returns the class for the macro. # # <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class @@ -179,10 +189,14 @@ module ActiveRecord @klass ||= active_record.send(:compute_type, class_name) end + attr_reader :type, :foreign_type + def initialize(*args) super @collection = [:has_many, :has_and_belongs_to_many].include?(macro) @automatic_inverse_of = nil + @type = options[:as] && "#{options[:as]}_type" + @foreign_type = options[:foreign_type] || "#{name}_type" end # Returns a new, unsaved instance of the associated class. +attributes+ will @@ -192,11 +206,11 @@ module ActiveRecord end def table_name - @table_name ||= klass.table_name + klass.table_name end def quoted_table_name - @quoted_table_name ||= klass.quoted_table_name + klass.quoted_table_name end def join_table @@ -207,16 +221,8 @@ module ActiveRecord @foreign_key ||= options[:foreign_key] || derive_foreign_key end - def foreign_type - @foreign_type ||= options[:foreign_type] || "#{name}_type" - end - - def type - @type ||= options[:as] && "#{options[:as]}_type" - end - def primary_key_column - @primary_key_column ||= klass.columns.find { |c| c.name == klass.primary_key } + klass.columns_hash[klass.primary_key] end def association_foreign_key @@ -240,14 +246,6 @@ module ActiveRecord end end - def columns(tbl_name) - @columns ||= klass.connection.columns(tbl_name) - end - - def reset_column_information - @columns = nil - end - def check_validity! check_validity_of_inverse! @@ -291,30 +289,13 @@ module ActiveRecord alias :source_macro :macro def has_inverse? - @options[:inverse_of] || find_inverse_of_automatically + inverse_name end def inverse_of - @inverse_of ||= if options[:inverse_of] - klass.reflect_on_association(options[:inverse_of]) - else - find_inverse_of_automatically - end - end + return unless inverse_name - # Clears the cached value of +@inverse_of+ on this object. This will - # not remove the :inverse_of option however, so future calls on the - # +inverse_of+ will have to recompute the inverse. - def clear_inverse_of_cache! - @inverse_of = nil - end - - # Removes the cached inverse association that was found automatically - # and prevents this object from finding the inverse association - # automatically in the future. - def remove_automatic_inverse_of! - @automatic_inverse_of = nil - options[:automatic_inverse_of] = false + @inverse_of ||= klass.reflect_on_association inverse_name end def polymorphic_inverse_of(associated_class) @@ -389,26 +370,21 @@ module ActiveRecord INVALID_AUTOMATIC_INVERSE_OPTIONS = [:conditions, :through, :polymorphic, :foreign_key] private - # Attempts to find the inverse association automatically. - # If it cannot find a suitable inverse association, it returns + # Attempts to find the inverse association name automatically. + # If it cannot find a suitable inverse association name, it returns # nil. - def find_inverse_of_automatically - if @automatic_inverse_of == false - nil - elsif @automatic_inverse_of.nil? - set_automatic_inverse_of - else - klass.reflect_on_association(@automatic_inverse_of) + def inverse_name + options.fetch(:inverse_of) do + if @automatic_inverse_of == false + nil + else + @automatic_inverse_of ||= automatic_inverse_of + end end end - # Sets the +@automatic_inverse_of+ instance variable, and returns - # either nil or the inverse association that it finds. - # - # This method caches the inverse association that is found so that - # future calls to +find_inverse_of_automatically+ have much less - # overhead. - def set_automatic_inverse_of + # returns either nil or the inverse association name that it finds. + def automatic_inverse_of if can_find_inverse_of_automatically?(self) inverse_name = active_record.name.downcase.to_sym @@ -421,16 +397,11 @@ module ActiveRecord end if valid_inverse_reflection?(reflection) - @automatic_inverse_of = inverse_name - reflection - else - @automatic_inverse_of = false - nil + return inverse_name end - else - @automatic_inverse_of = false - nil end + + false end # Checks if the inverse reflection that is returned from the @@ -442,22 +413,23 @@ module ActiveRecord # from calling +klass+, +reflection+ will already be set to false. def valid_inverse_reflection?(reflection) reflection && - klass.name == reflection.active_record.try(:name) && + klass.name == reflection.active_record.name && klass.primary_key == reflection.active_record_primary_key && can_find_inverse_of_automatically?(reflection) end # Checks to see if the reflection doesn't have any options that prevent # us from being able to guess the inverse automatically. First, the - # +automatic_inverse_of+ option cannot be set to false. Second, we must - # have +has_many+, +has_one+, +belongs_to+ associations. Third, we must - # not have options such as +:polymorphic+ or +:foreign_key+ which prevent us - # from correctly guessing the inverse association. + # <tt>inverse_of</tt> option cannot be set to false. Second, we must + # have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations. + # Third, we must not have options such as <tt>:polymorphic</tt> or + # <tt>:foreign_key</tt> which prevent us from correctly guessing the + # inverse association. # # Anything with a scope can additionally ruin our attempt at finding an # inverse, so we exclude reflections with scopes. def can_find_inverse_of_automatically?(reflection) - reflection.options[:automatic_inverse_of] != false && + reflection.options[:inverse_of] != false && VALID_AUTOMATIC_INVERSE_MACROS.include?(reflection.macro) && !INVALID_AUTOMATIC_INVERSE_OPTIONS.any? { |opt| reflection.options[opt] } && !reflection.scope @@ -494,6 +466,11 @@ module ActiveRecord delegate :foreign_key, :foreign_type, :association_foreign_key, :active_record_primary_key, :type, :to => :source_reflection + def initialize(macro, name, scope, options, active_record) + super + @source_reflection_name = options[:source] + end + # Returns the source of the through reflection. It checks both a singularized # and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>. # @@ -512,7 +489,7 @@ module ActiveRecord # # => <ActiveRecord::Reflection::AssociationReflection: @macro=:belongs_to, @name=:tag, @active_record=Tagging, @plural_name="tags"> # def source_reflection - @source_reflection ||= source_reflection_names.collect { |name| through_reflection.klass.reflect_on_association(name) }.compact.first + through_reflection.klass.reflect_on_association(source_reflection_name) end # Returns the AssociationReflection object specified in the <tt>:through</tt> option @@ -528,7 +505,7 @@ module ActiveRecord # # => <ActiveRecord::Reflection::AssociationReflection: @macro=:has_many, @name=:taggings, @active_record=Post, @plural_name="taggings"> # def through_reflection - @through_reflection ||= active_record.reflect_on_association(options[:through]) + active_record.reflect_on_association(options[:through]) end # Returns an array of reflections which are involved in this association. Each item in the @@ -630,7 +607,32 @@ module ActiveRecord # # => [:tag, :tags] # def source_reflection_names - @source_reflection_names ||= (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym } + (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }.uniq + end + + def source_reflection_name # :nodoc: + return @source_reflection_name if @source_reflection_name + + names = [name.to_s.singularize, name].collect { |n| n.to_sym }.uniq + names = names.find_all { |n| + through_reflection.klass.reflect_on_association(n) + } + + if names.length > 1 + example_options = options.dup + example_options[:source] = source_reflection_names.first + ActiveSupport::Deprecation.warn <<-eowarn +Ambiguous source reflection for through association. Please specify a :source +directive on your declaration like: + + class #{active_record.name} < ActiveRecord::Base + #{macro} :#{name}, #{example_options} + end + + eowarn + end + + @source_reflection_name = names.first end def source_options diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 9857ab0f8f..d37471e9ad 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -154,34 +154,58 @@ module ActiveRecord first || new(attributes, &block) end - # Finds the first record with the given attributes, or creates a record with the attributes - # if one is not found. + # Finds the first record with the given attributes, or creates a record + # with the attributes if one is not found: # - # ==== Examples - # # Find the first user named Penélope or create a new one. + # # Find the first user named "Penélope" or create a new one. # User.find_or_create_by(first_name: 'Penélope') - # # => <User id: 1, first_name: 'Penélope', last_name: nil> + # # => #<User id: 1, first_name: "Penélope", last_name: nil> # - # # Find the first user named Penélope or create a new one. + # # Find the first user named "Penélope" or create a new one. # # We already have one so the existing record will be returned. # User.find_or_create_by(first_name: 'Penélope') - # # => <User id: 1, first_name: 'Penélope', last_name: nil> + # # => #<User id: 1, first_name: "Penélope", last_name: nil> # - # # Find the first user named Scarlett or create a new one with a particular last name. + # # Find the first user named "Scarlett" or create a new one with + # # a particular last name. # User.create_with(last_name: 'Johansson').find_or_create_by(first_name: 'Scarlett') - # # => <User id: 2, first_name: 'Scarlett', last_name: 'Johansson'> + # # => #<User id: 2, first_name: "Scarlett", last_name: "Johansson"> # - # # Find the first user named Scarlett or create a new one with a different last name. - # # We already have one so the existing record will be returned. + # This method accepts a block, which is passed down to +create+. The last example + # above can be alternatively written this way: + # + # # Find the first user named "Scarlett" or create a new one with a + # # different last name. # User.find_or_create_by(first_name: 'Scarlett') do |user| - # user.last_name = "O'Hara" + # user.last_name = 'Johansson' # end - # # => <User id: 2, first_name: 'Scarlett', last_name: 'Johansson'> + # # => #<User id: 2, first_name: "Scarlett", last_name: "Johansson"> + # + # This method always returns a record, but if creation was attempted and + # failed due to validation errors it won't be persisted, you get what + # +create+ returns in such situation. + # + # Please note *this method is not atomic*, it runs first a SELECT, and if + # there are no results an INSERT is attempted. If there are other threads + # or processes there is a race condition between both calls and it could + # be the case that you end up with two similar records. + # + # Whether that is a problem or not depends on the logic of the + # application, but in the particular case in which rows have a UNIQUE + # constraint an exception may be raised, just retry: + # + # begin + # CreditAccount.find_or_create_by(user_id: user.id) + # rescue ActiveRecord::RecordNotUnique + # retry + # end + # def find_or_create_by(attributes, &block) find_by(attributes) || create(attributes, &block) end - # Like <tt>find_or_create_by</tt>, but calls <tt>create!</tt> so an exception is raised if the created record is invalid. + # Like <tt>find_or_create_by</tt>, but calls <tt>create!</tt> so an exception + # is raised if the created record is invalid. def find_or_create_by!(attributes, &block) find_by(attributes) || create!(attributes, &block) end @@ -223,7 +247,7 @@ module ActiveRecord def empty? return @records.empty? if loaded? - c = count + c = count(:all) c.respond_to?(:zero?) ? c.zero? : c.empty? end diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index b921f2eddb..91ea1756c4 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -11,7 +11,7 @@ module ActiveRecord # The #find_each method uses #find_in_batches with a batch size of 1000 (or as # specified by the +:batch_size+ option). # - # Person.all.find_each do |person| + # Person.find_each do |person| # person.do_awesome_stuff # end # @@ -19,40 +19,71 @@ module ActiveRecord # person.party_all_night! # end # - # You can also pass the +:start+ option to specify - # an offset to control the starting point. - def find_each(options = {}) - find_in_batches(options) do |records| - records.each { |record| yield record } - end - end - - # Yields each batch of records that was found by the find +options+ as - # an array. The size of each batch is set by the +:batch_size+ - # option; the default is 1000. + # If you do not provide a block to #find_each, it will return an Enumerator + # for chaining with other methods: + # + # Person.find_each.with_index do |person, index| + # person.award_trophy(index + 1) + # end + # + # ==== Options + # * <tt>:batch_size</tt> - Specifies the size of the batch. Default to 1000. + # * <tt>:start</tt> - Specifies the starting point for the batch processing. + # This is especially useful if you want multiple workers dealing with + # the same processing queue. You can make worker 1 handle all the records + # between id 0 and 10,000 and worker 2 handle from 10,000 and beyond + # (by setting the +:start+ option on that worker). # - # You can control the starting point for the batch processing by - # supplying the +:start+ option. This is especially useful if you - # want multiple workers dealing with the same processing queue. You can - # make worker 1 handle all the records between id 0 and 10,000 and - # worker 2 handle from 10,000 and beyond (by setting the +:start+ - # option on that worker). + # # Let's process for a batch of 2000 records, skiping the first 2000 rows + # Person.find_each(start: 2000, batch_size: 2000) do |person| + # person.party_all_night! + # end # - # It's not possible to set the order. That is automatically set to + # NOTE: It's not possible to set the order. That is automatically set to # ascending on the primary key ("id ASC") to make the batch ordering # work. This also means that this method only works with integer-based - # primary keys. You can't set the limit either, that's used to control + # primary keys. + # + # NOTE: You can't set the limit either, that's used to control # the batch sizes. + def find_each(options = {}) + if block_given? + find_in_batches(options) do |records| + records.each { |record| yield record } + end + else + enum_for :find_each, options + end + end + + # Yields each batch of records that was found by the find +options+ as + # an array. # # Person.where("age > 21").find_in_batches do |group| # sleep(50) # Make sure it doesn't get too crowded in there! # group.each { |person| person.party_all_night! } # end # + # ==== Options + # * <tt>:batch_size</tt> - Specifies the size of the batch. Default to 1000. + # * <tt>:start</tt> - Specifies the starting point for the batch processing. + # This is especially useful if you want multiple workers dealing with + # the same processing queue. You can make worker 1 handle all the records + # between id 0 and 10,000 and worker 2 handle from 10,000 and beyond + # (by setting the +:start+ option on that worker). + # # # Let's process the next 2000 records - # Person.all.find_in_batches(start: 2000, batch_size: 2000) do |group| + # Person.find_in_batches(start: 2000, batch_size: 2000) do |group| # group.each { |person| person.party_all_night! } # end + # + # NOTE: It's not possible to set the order. That is automatically set to + # ascending on the primary key ("id ASC") to make the batch ordering + # work. This also means that this method only works with integer-based + # primary keys. + # + # NOTE: You can't set the limit either, that's used to control + # the batch sizes. def find_in_batches(options = {}) options.assert_valid_keys(:start, :batch_size) diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 7239270c4d..4becf3980d 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -56,15 +56,7 @@ module ActiveRecord # # Person.sum(:age) # => 4562 def sum(*args) - if block_given? - ActiveSupport::Deprecation.warn( - "Calling #sum with a block is deprecated and will be removed in Rails 4.1. " \ - "If you want to perform sum calculation over the array of elements, use `to_a.sum(&block)`." - ) - self.to_a.sum(*args) {|*block_args| yield(*block_args)} - else - calculate(:sum, *args) - end + calculate(:sum, *args) end # This calculates aggregate values in the given column. Methods for count, sum, average, @@ -114,8 +106,6 @@ module ActiveRecord else relation.calculate(operation, column_name, options) end - rescue ThrowResult - 0 end # Use <tt>pluck</tt> as a shortcut to select one or more attributes without @@ -217,15 +207,18 @@ module ActiveRecord end if operation == "count" - column_name ||= (select_for_count || :all) + if select_values.present? + column_name ||= select_values.join(", ") + else + column_name ||= :all + end unless arel.ast.grep(Arel::Nodes::OuterJoin).empty? distinct = true end column_name = primary_key if column_name == :all && distinct - - distinct = nil if column_name =~ /\s*DISTINCT\s+/i + distinct = nil if column_name =~ /\s*DISTINCT[\s(]+/i end if group_values.any? @@ -386,13 +379,6 @@ module ActiveRecord column ? column.type_cast(value) : value end - def select_for_count - if select_values.present? - select = select_values.join(", ") - select if select !~ /[,*]/ - end - end - def build_count_subquery(relation, column_name, distinct) column_alias = Arel.sql('count_column') subquery_alias = Arel.sql('subquery_for_count') diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index ba222aac93..3ea3c33fcc 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -11,9 +11,11 @@ module ActiveRecord # Person.find([1]) # returns an array for the object with ID = 1 # Person.where("administrator = 1").order("created_on DESC").find(1) # - # Note that returned records may not be in the same order as the ids you - # provide since database rows are unordered. Give an explicit <tt>order</tt> - # to ensure the results are sorted. + # <tt>ActiveRecord::RecordNotFound</tt> will be raised if one or more ids are not found. + # + # NOTE: The returned records may not be in the same order as the ids you + # provide since database rows are unordered. You'd need to provide an explicit <tt>order</tt> + # option if you want the results are sorted. # # ==== Find with lock # @@ -28,6 +30,34 @@ module ActiveRecord # person.visits += 1 # person.save! # end + # + # ==== Variations of +find+ + # + # Person.where(name: 'Spartacus', rating: 4) + # # returns a chainable list (which can be empty). + # + # Person.find_by(name: 'Spartacus', rating: 4) + # # returns the first item or nil. + # + # Person.where(name: 'Spartacus', rating: 4).first_or_initialize + # # returns the first item or returns a new instance (requires you call .save to persist against the database). + # + # Person.where(name: 'Spartacus', rating: 4).first_or_create + # # returns the first item or creates it and returns it, available since Rails 3.2.1. + # + # ==== Alternatives for +find+ + # + # Person.where(name: 'Spartacus', rating: 4).exists?(conditions = :none) + # # returns a boolean indicating if any record with the given conditions exist. + # + # Person.where(name: 'Spartacus', rating: 4).select("field1, field2, field3") + # # returns a chainable list of instances with only the mentioned fields. + # + # Person.where(name: 'Spartacus', rating: 4).ids + # # returns an Array of ids, available since Rails 3.2.1. + # + # Person.where(name: 'Spartacus', rating: 4).pluck(:field1, :field2) + # # returns an Array of the required fields, available since Rails 3.1. def find(*args) if block_given? to_a.find { |*block_args| yield(*block_args) } @@ -79,13 +109,22 @@ module ActiveRecord # Person.where(["user_name = :u", { u: user_name }]).first # Person.order("created_on DESC").offset(5).first # Person.first(3) # returns the first three objects fetched by SELECT * FROM people LIMIT 3 + # + # ==== Rails 3 + # + # Person.first # SELECT "people".* FROM "people" LIMIT 1 + # + # NOTE: Rails 3 may not order this query by the primary key and the order + # will depend on the database implementation. In order to ensure that behavior, + # use <tt>User.order(:id).first</tt> instead. + # + # ==== Rails 4 + # + # Person.first # SELECT "people".* FROM "people" ORDER BY "people"."id" ASC LIMIT 1 + # def first(limit = nil) if limit - if order_values.empty? && primary_key - order(arel_table[primary_key].asc).limit(limit).to_a - else - limit(limit).to_a - end + find_first_with_limit(order_values, limit) else find_first end @@ -160,8 +199,9 @@ module ActiveRecord conditions = conditions.id if Base === conditions return false if !conditions - join_dependency = construct_join_dependency - relation = construct_relation_for_association_find(join_dependency) + relation = construct_relation_for_association_find(construct_join_dependency) + return false if ActiveRecord::NullRelation === relation + relation = relation.except(:select, :order).select("1 AS one").limit(1) case conditions @@ -171,9 +211,8 @@ module ActiveRecord relation = relation.where(table[primary_key].eq(conditions)) if conditions != :none end - connection.select_value(relation, "#{name} Exists", relation.bind_values) - rescue ThrowResult - false + relation = relation.with_default_scope + connection.select_value(relation.arel, "#{name} Exists", relation.bind_values) end # This method is called whenever no records are found with either a single @@ -203,10 +242,12 @@ module ActiveRecord def find_with_associations join_dependency = construct_join_dependency relation = construct_relation_for_association_find(join_dependency) - rows = connection.select_all(relation, 'SQL', relation.bind_values.dup) - join_dependency.instantiate(rows) - rescue ThrowResult - [] + if ActiveRecord::NullRelation === relation + [] + else + rows = connection.select_all(relation, 'SQL', relation.bind_values.dup) + join_dependency.instantiate(rows) + end end def construct_join_dependency(joins = []) @@ -230,21 +271,22 @@ module ActiveRecord if using_limitable_reflections?(join_dependency.reflections) relation else - relation.where!(construct_limited_ids_condition(relation)) if relation.limit_value + if relation.limit_value + limited_ids = limited_ids_for(relation) + limited_ids.empty? ? relation.none! : relation.where!(table[primary_key].in(limited_ids)) + end relation.except(:limit, :offset) end end - def construct_limited_ids_condition(relation) + def limited_ids_for(relation) values = @klass.connection.columns_for_distinct( "#{quoted_table_name}.#{quoted_primary_key}", relation.order_values) relation = relation.except(:select).select(values).distinct! id_rows = @klass.connection.select_all(relation.arel, 'SQL', relation.bind_values) - ids_array = id_rows.map {|row| row[primary_key]} - - ids_array.empty? ? raise(ThrowResult) : table[primary_key].in(ids_array) + id_rows.map {|row| row[primary_key]} end def find_with_ids(*ids) @@ -312,12 +354,15 @@ module ActiveRecord if loaded? @records.first else - @first ||= - if with_default_scope.order_values.empty? && primary_key - order(arel_table[primary_key].asc).limit(1).to_a.first - else - limit(1).to_a.first - end + @first ||= find_first_with_limit(with_default_scope.order_values, 1).first + end + end + + def find_first_with_limit(order_values, limit) + if order_values.empty? && primary_key + order(arel_table[primary_key].asc).limit(limit).to_a + else + limit(limit).to_a end end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index fe8fec4dfa..0200fcf69b 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -802,7 +802,7 @@ module ActiveRecord def build_arel arel = Arel::SelectManager.new(table.engine, table) - build_joins(arel, joins_values) unless joins_values.empty? + build_joins(arel, joins_values.flatten) unless joins_values.empty? collapse_wheres(arel, (where_values - ['']).uniq) @@ -1010,7 +1010,7 @@ module ActiveRecord end def validate_order_args(args) - args.select { |a| Hash === a }.each do |h| + args.grep(Hash) do |h| unless (h.values - [:asc, :desc]).empty? raise ArgumentError, 'Direction should be :asc or :desc' end diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb index bea195e9b8..6156b3a5ba 100644 --- a/activerecord/lib/active_record/result.rb +++ b/activerecord/lib/active_record/result.rb @@ -18,7 +18,11 @@ module ActiveRecord end def each - hash_rows.each { |row| yield row } + if block_given? + hash_rows.each { |row| yield row } + else + hash_rows.to_enum + end end def to_hash diff --git a/activerecord/lib/active_record/schema_migration.rb b/activerecord/lib/active_record/schema_migration.rb index 6077144265..fee19b1096 100644 --- a/activerecord/lib/active_record/schema_migration.rb +++ b/activerecord/lib/active_record/schema_migration.rb @@ -4,31 +4,37 @@ require 'active_record/base' module ActiveRecord class SchemaMigration < ActiveRecord::Base + class << self - def self.table_name - "#{Base.table_name_prefix}schema_migrations#{Base.table_name_suffix}" - end + def table_name + "#{table_name_prefix}schema_migrations#{table_name_suffix}" + end - def self.index_name - "#{Base.table_name_prefix}unique_schema_migrations#{Base.table_name_suffix}" - end + def index_name + "#{table_name_prefix}unique_schema_migrations#{table_name_suffix}" + end - def self.create_table(limit=nil) - unless connection.table_exists?(table_name) - version_options = {null: false} - version_options[:limit] = limit if limit + def table_exists? + connection.table_exists?(table_name) + end + + def create_table(limit=nil) + unless table_exists? + version_options = {null: false} + version_options[:limit] = limit if limit - connection.create_table(table_name, id: false) do |t| - t.column :version, :string, version_options + connection.create_table(table_name, id: false) do |t| + t.column :version, :string, version_options + end + connection.add_index table_name, :version, unique: true, name: index_name end - connection.add_index table_name, :version, unique: true, name: index_name end - end - def self.drop_table - if connection.table_exists?(table_name) - connection.remove_index table_name, name: index_name - connection.drop_table(table_name) + def drop_table + if table_exists? + connection.remove_index table_name, name: index_name + connection.drop_table(table_name) + end end end diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index 3e8b79c7a0..5ff594fdca 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -50,10 +50,6 @@ module ActiveRecord register_task(/postgresql/, ActiveRecord::Tasks::PostgreSQLDatabaseTasks) register_task(/sqlite/, ActiveRecord::Tasks::SQLiteDatabaseTasks) - register_task(/firebird/, ActiveRecord::Tasks::FirebirdDatabaseTasks) - register_task(/sqlserver/, ActiveRecord::Tasks::SqlserverDatabaseTasks) - register_task(/(oci|oracle)/, ActiveRecord::Tasks::OracleDatabaseTasks) - def current_config(options = {}) options.reverse_merge! :env => env if options.has_key?(:config) diff --git a/activerecord/lib/active_record/tasks/firebird_database_tasks.rb b/activerecord/lib/active_record/tasks/firebird_database_tasks.rb deleted file mode 100644 index 98014a38ea..0000000000 --- a/activerecord/lib/active_record/tasks/firebird_database_tasks.rb +++ /dev/null @@ -1,56 +0,0 @@ -module ActiveRecord - module Tasks # :nodoc: - class FirebirdDatabaseTasks # :nodoc: - delegate :connection, :establish_connection, to: ActiveRecord::Base - - def initialize(configuration) - ActiveSupport::Deprecation.warn "This database tasks were deprecated, because this tasks should be served by the 3rd party adapter." - @configuration = configuration - end - - def create - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def drop - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def purge - establish_connection(:test) - connection.recreate_database! - end - - def charset - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def structure_dump(filename) - set_firebird_env(configuration) - db_string = firebird_db_string(configuration) - Kernel.system "isql -a #{db_string} > #{filename}" - end - - def structure_load(filename) - set_firebird_env(configuration) - db_string = firebird_db_string(configuration) - Kernel.system "isql -i #{filename} #{db_string}" - end - - private - - def set_firebird_env(config) - ENV['ISC_USER'] = config['username'].to_s if config['username'] - ENV['ISC_PASSWORD'] = config['password'].to_s if config['password'] - end - - def firebird_db_string(config) - FireRuby::Database.db_string_for(config.symbolize_keys) - end - - def configuration - @configuration - end - end - end -end diff --git a/activerecord/lib/active_record/tasks/oracle_database_tasks.rb b/activerecord/lib/active_record/tasks/oracle_database_tasks.rb deleted file mode 100644 index de3aa50e5e..0000000000 --- a/activerecord/lib/active_record/tasks/oracle_database_tasks.rb +++ /dev/null @@ -1,45 +0,0 @@ -module ActiveRecord - module Tasks # :nodoc: - class OracleDatabaseTasks # :nodoc: - delegate :connection, :establish_connection, to: ActiveRecord::Base - - def initialize(configuration) - ActiveSupport::Deprecation.warn "This database tasks were deprecated, because this tasks should be served by the 3rd party adapter." - @configuration = configuration - end - - def create - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def drop - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def purge - establish_connection(:test) - connection.structure_drop.split(";\n\n").each { |ddl| connection.execute(ddl) } - end - - def charset - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def structure_dump(filename) - establish_connection(configuration) - File.open(filename, "w:utf-8") { |f| f << connection.structure_dump } - end - - def structure_load(filename) - establish_connection(configuration) - IO.read(filename).split(";\n\n").each { |ddl| connection.execute(ddl) } - end - - private - - def configuration - @configuration - end - end - end -end diff --git a/activerecord/lib/active_record/tasks/sqlserver_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlserver_database_tasks.rb deleted file mode 100644 index c718ee03a8..0000000000 --- a/activerecord/lib/active_record/tasks/sqlserver_database_tasks.rb +++ /dev/null @@ -1,48 +0,0 @@ -require 'shellwords' - -module ActiveRecord - module Tasks # :nodoc: - class SqlserverDatabaseTasks # :nodoc: - delegate :connection, :establish_connection, to: ActiveRecord::Base - - def initialize(configuration) - ActiveSupport::Deprecation.warn "This database tasks were deprecated, because this tasks should be served by the 3rd party adapter." - @configuration = configuration - end - - def create - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def drop - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def purge - test = configuration.deep_dup - test_database = test['database'] - test['database'] = 'master' - establish_connection(test) - connection.recreate_database!(test_database) - end - - def charset - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def structure_dump(filename) - Kernel.system("smoscript -s #{configuration['host']} -d #{configuration['database']} -u #{configuration['username']} -p #{configuration['password']} -f #{filename} -A -U") - end - - def structure_load(filename) - Kernel.system("sqlcmd -S #{configuration['host']} -d #{configuration['database']} -U #{configuration['username']} -P #{configuration['password']} -i #{filename}") - end - - private - - def configuration - @configuration - end - end - end -end diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index ae99cff35e..9253150c4f 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -10,9 +10,9 @@ module ActiveRecord # # config.active_record.record_timestamps = false # - # Timestamps are in the local timezone by default but you can use UTC by setting: + # Timestamps are in UTC by default but you can use the local timezone by setting: # - # config.active_record.default_timezone = :utc + # config.active_record.default_timezone = :local # # == Time Zone aware attributes # diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 77634b40bb..62920d936f 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -245,7 +245,7 @@ module ActiveRecord if options.is_a?(Hash) && options[:on] assert_valid_transaction_action(options[:on]) options[:if] = Array(options[:if]) - fire_on = Array(options[:on]).map(&:to_sym) + fire_on = Array(options[:on]) options[:if] << "transaction_include_any_action?(#{fire_on})" end end @@ -288,17 +288,17 @@ module ActiveRecord clear_transaction_record_state end - # Call the after_commit callbacks + # Call the +after_commit+ callbacks. # # Ensure that it is not called if the object was never persisted (failed create), - # but call it after the commit of a destroyed object + # but call it after the commit of a destroyed object. def committed! #:nodoc: run_callbacks :commit if destroyed? || persisted? ensure clear_transaction_record_state end - # Call the after rollback callbacks. The restore_state argument indicates if the record + # Call the +after_rollback+ callbacks. The +force_restore_state+ argument indicates if the record # state should be rolled back to the beginning or just to the last savepoint. def rolledback!(force_restore_state = false) #:nodoc: run_callbacks :rollback @@ -306,7 +306,7 @@ module ActiveRecord restore_transaction_record_state(force_restore_state) end - # Add the record to the current transaction so that the :after_rollback and :after_commit callbacks + # Add the record to the current transaction so that the +after_rollback+ and +after_commit+ callbacks # can be called. def add_to_transaction if self.class.connection.add_transaction_record(self) diff --git a/activerecord/lib/active_record/validations/associated.rb b/activerecord/lib/active_record/validations/associated.rb index 744780d069..b4785d3ba4 100644 --- a/activerecord/lib/active_record/validations/associated.rb +++ b/activerecord/lib/active_record/validations/associated.rb @@ -2,7 +2,7 @@ module ActiveRecord module Validations class AssociatedValidator < ActiveModel::EachValidator #:nodoc: def validate_each(record, attribute, value) - if Array.wrap(value).reject {|r| r.marked_for_destruction? || r.valid?(record.validation_context) }.any? + if Array.wrap(value).reject {|r| r.marked_for_destruction? || r.valid?}.any? record.errors.add(attribute, :invalid, options.merge(:value => value)) end end diff --git a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb index 16329689c0..22dd48e113 100644 --- a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb @@ -25,9 +25,7 @@ class PostgresqlActiveSchemaTest < ActiveRecord::TestCase def test_add_index # add_index calls index_name_exists? which can't work since execute is stubbed - ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:define_method, :index_name_exists?) do |*| - false - end + ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.stubs(:index_name_exists?).returns(false) expected = %(CREATE UNIQUE INDEX "index_people_on_last_name" ON "people" ("last_name") WHERE state = 'active') assert_equal expected, add_index(:people, :last_name, :unique => true, :where => "state = 'active'") @@ -51,8 +49,6 @@ class PostgresqlActiveSchemaTest < ActiveRecord::TestCase expected = %(CREATE UNIQUE INDEX "index_people_on_last_name" ON "people" USING gist ("last_name") WHERE state = 'active') assert_equal expected, add_index(:people, :last_name, :unique => true, :where => "state = 'active'", :using => :gist) - - ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:remove_method, :index_name_exists?) end private diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb index d7d77f96e2..489efac932 100644 --- a/activerecord/test/cases/adapters/postgresql/bytea_test.rb +++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb @@ -15,6 +15,7 @@ class PostgresqlByteaTest < ActiveRecord::TestCase @connection.transaction do @connection.create_table('bytea_data_type') do |t| t.binary 'payload' + t.binary 'serialized' end end end @@ -84,4 +85,20 @@ class PostgresqlByteaTest < ActiveRecord::TestCase assert_equal(nil, record.payload) assert_equal(nil, ByteaDataType.where(id: record.id).first.payload) end + + class Serializer + def load(str); str; end + def dump(str); str; end + end + + def test_serialize + klass = Class.new(ByteaDataType) { + serialize :serialized, Serializer.new + } + obj = klass.new + obj.serialized = "hello world" + obj.save! + obj.reload + assert_equal "hello world", obj.serialized + end end diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb index b5d7ea603e..36d7294bc8 100644 --- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb +++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb @@ -246,7 +246,7 @@ _SQL assert_equal 2...10, @second_range.int4_range assert_equal 2...Float::INFINITY, @third_range.int4_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.int4_range) - assert_equal nil, @empty_range.int4_range + assert_nil @empty_range.int4_range end def test_int8range_values @@ -255,7 +255,7 @@ _SQL assert_equal 11...100, @second_range.int8_range assert_equal 11...Float::INFINITY, @third_range.int8_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.int8_range) - assert_equal nil, @empty_range.int8_range + assert_nil @empty_range.int8_range end def test_daterange_values @@ -264,7 +264,7 @@ _SQL assert_equal Date.new(2012, 1, 3)...Date.new(2012, 1, 4), @second_range.date_range assert_equal Date.new(2012, 1, 3)...Float::INFINITY, @third_range.date_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.date_range) - assert_equal nil, @empty_range.date_range + assert_nil @empty_range.date_range end def test_numrange_values @@ -273,7 +273,7 @@ _SQL assert_equal BigDecimal.new('0.1')...BigDecimal.new('0.2'), @second_range.num_range assert_equal BigDecimal.new('0.1')...BigDecimal.new('Infinity'), @third_range.num_range assert_equal BigDecimal.new('-Infinity')...BigDecimal.new('Infinity'), @fourth_range.num_range - assert_equal nil, @empty_range.num_range + assert_nil @empty_range.num_range end def test_tsrange_values @@ -282,7 +282,7 @@ _SQL assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)..Time.send(tz, 2011, 1, 1, 14, 30, 0), @first_range.ts_range assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 1, 1, 14, 30, 0), @second_range.ts_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.ts_range) - assert_equal nil, @empty_range.ts_range + assert_nil @empty_range.ts_range end def test_tstzrange_values @@ -290,7 +290,7 @@ _SQL assert_equal Time.parse('2010-01-01 09:30:00 UTC')..Time.parse('2011-01-01 17:30:00 UTC'), @first_range.tstz_range assert_equal Time.parse('2010-01-01 09:30:00 UTC')...Time.parse('2011-01-01 17:30:00 UTC'), @second_range.tstz_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.tstz_range) - assert_equal nil, @empty_range.tstz_range + assert_nil @empty_range.tstz_range end def test_money_values @@ -314,11 +314,11 @@ _SQL assert @first_range.tstz_range = new_tstzrange assert @first_range.save assert @first_range.reload - assert_equal @first_range.tstz_range, new_tstzrange + assert_equal new_tstzrange, @first_range.tstz_range assert @first_range.tstz_range = Time.parse('2010-01-01 14:30:00 +0100')...Time.parse('2010-01-01 13:30:00 +0000') assert @first_range.save assert @first_range.reload - assert_equal @first_range.tstz_range, nil + assert_nil @first_range.tstz_range end def test_create_tsrange @@ -338,11 +338,11 @@ _SQL assert @first_range.ts_range = new_tsrange assert @first_range.save assert @first_range.reload - assert_equal @first_range.ts_range, new_tsrange + assert_equal new_tsrange, @first_range.ts_range assert @first_range.ts_range = Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2010, 1, 1, 14, 30, 0) assert @first_range.save assert @first_range.reload - assert_equal @first_range.ts_range, nil + assert_nil @first_range.ts_range end def test_create_numrange @@ -360,11 +360,11 @@ _SQL assert @first_range.num_range = new_numrange assert @first_range.save assert @first_range.reload - assert_equal @first_range.num_range, new_numrange + assert_equal new_numrange, @first_range.num_range assert @first_range.num_range = BigDecimal.new('0.5')...BigDecimal.new('0.5') assert @first_range.save assert @first_range.reload - assert_equal @first_range.num_range, nil + assert_nil @first_range.num_range end def test_create_daterange @@ -382,11 +382,11 @@ _SQL assert @first_range.date_range = new_daterange assert @first_range.save assert @first_range.reload - assert_equal @first_range.date_range, new_daterange + assert_equal new_daterange, @first_range.date_range assert @first_range.date_range = Date.new(2012, 2, 3)...Date.new(2012, 2, 3) assert @first_range.save assert @first_range.reload - assert_equal @first_range.date_range, nil + assert_nil @first_range.date_range end def test_create_int4range @@ -404,11 +404,11 @@ _SQL assert @first_range.int4_range = new_int4range assert @first_range.save assert @first_range.reload - assert_equal @first_range.int4_range, new_int4range + assert_equal new_int4range, @first_range.int4_range assert @first_range.int4_range = 3...3 assert @first_range.save assert @first_range.reload - assert_equal @first_range.int4_range, nil + assert_nil @first_range.int4_range end def test_create_int8range @@ -426,11 +426,11 @@ _SQL assert @first_range.int8_range = new_int8range assert @first_range.save assert @first_range.reload - assert_equal @first_range.int8_range, new_int8range + assert_equal new_int8range, @first_range.int8_range assert @first_range.int8_range = 39999...39999 assert @first_range.save assert @first_range.reload - assert_equal @first_range.int8_range, nil + assert_nil @first_range.int8_range end def test_update_tsvector @@ -441,7 +441,7 @@ _SQL assert @first_tsvector.text_vector = new_text_vector assert @first_tsvector.save assert @first_tsvector.reload - assert_equal @first_tsvector.text_vector, new_text_vector + assert_equal new_text_vector, @first_tsvector.text_vector end def test_number_values @@ -482,11 +482,11 @@ _SQL assert @first_array.commission_by_quarter = new_value assert @first_array.save assert @first_array.reload - assert_equal @first_array.commission_by_quarter, new_value + assert_equal new_value, @first_array.commission_by_quarter assert @first_array.commission_by_quarter = new_value assert @first_array.save assert @first_array.reload - assert_equal @first_array.commission_by_quarter, new_value + assert_equal new_value, @first_array.commission_by_quarter end def test_update_text_array @@ -494,11 +494,11 @@ _SQL assert @first_array.nicknames = new_value assert @first_array.save assert @first_array.reload - assert_equal @first_array.nicknames, new_value + assert_equal new_value, @first_array.nicknames assert @first_array.nicknames = new_value assert @first_array.save assert @first_array.reload - assert_equal @first_array.nicknames, new_value + assert_equal new_value, @first_array.nicknames end def test_update_money @@ -516,15 +516,15 @@ _SQL assert @first_number.double = new_double assert @first_number.save assert @first_number.reload - assert_equal @first_number.single, new_single - assert_equal @first_number.double, new_double + assert_equal new_single, @first_number.single + assert_equal new_double, @first_number.double end def test_update_time assert @first_time.time_interval = '2 years 3 minutes' assert @first_time.save assert @first_time.reload - assert_equal @first_time.time_interval, '2 years 00:03:00' + assert_equal '2 years 00:03:00', @first_time.time_interval end def test_update_network_address @@ -548,10 +548,10 @@ _SQL assert @first_bit_string.bit_string_varying = new_bit_string_varying assert @first_bit_string.save assert @first_bit_string.reload - assert_equal @first_bit_string.bit_string, new_bit_string + assert_equal new_bit_string, @first_bit_string.bit_string assert_equal @first_bit_string.bit_string, @first_bit_string.bit_string_varying end - + def test_invalid_hex_string new_bit_string = 'FF' @first_bit_string.bit_string = new_bit_string @@ -563,7 +563,7 @@ _SQL assert @first_oid.obj_id = new_value assert @first_oid.save assert @first_oid.reload - assert_equal @first_oid.obj_id, new_value + assert_equal new_value, @first_oid.obj_id end def test_timestamp_with_zone_values_with_rails_time_zone_support diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 87af24cbe6..95896971a8 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -338,7 +338,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase topic.replies.create!(:title => "re: 37s", :content => "rails") assert_equal 1, Topic.find(topic.id)[:replies_count] - topic.update_columns(content: "rails is wonderfull") + topic.update_columns(content: "rails is wonderful") assert_equal 1, Topic.find(topic.id)[:replies_count] end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 4aa6567d85..1cfaf552af 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -250,7 +250,8 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_nil Post.all.merge!(:includes => :author).find(posts(:authorless).id).author end - def test_nested_loading_with_no_associations + # Regression test for 21c75e5 + def test_nested_loading_does_not_raise_exception_when_association_does_not_exist assert_nothing_raised do Post.all.merge!(:includes => {:author => :author_addresss}).find(posts(:authorless).id) end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 058c812dca..8f5e18b863 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -176,6 +176,16 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_raise(ActiveRecord::SubclassNotFound) { firm.companies.build(:type => "Account") } end + test "building the association with an array" do + speedometer = Speedometer.new(speedometer_id: "a") + data = [{name: "first"}, {name: "second"}] + speedometer.minivans.build(data) + + assert_equal 2, speedometer.minivans.size + assert speedometer.save + assert_equal ["first", "second"], speedometer.reload.minivans.map(&:name) + end + def test_association_keys_bypass_attribute_protection car = Car.create(:name => 'honda') @@ -418,7 +428,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase client_ary = firm.clients_using_finder_sql.find("2", "3") assert_kind_of Array, client_ary assert_equal 2, client_ary.size - assert client_ary.include?(client) + assert_equal true, client_ary.include?(client) end def test_find_all @@ -1220,14 +1230,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_included_in_collection - assert companies(:first_firm).clients.include?(Client.find(2)) + assert_equal true, companies(:first_firm).clients.include?(Client.find(2)) end def test_included_in_collection_for_new_records client = Client.create(:name => 'Persisted') assert_nil client.client_of - assert !Firm.new.clients_of_firm.include?(client), - 'includes a client that does not belong to any firm' + assert_equal false, Firm.new.clients_of_firm.include?(client), + 'includes a client that does not belong to any firm' end def test_adding_array_and_collection @@ -1254,7 +1264,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase firm.save firm.reload assert_equal 2, firm.clients.length - assert !firm.clients.include?(:first_client) + assert_equal false, firm.clients.include?(:first_client) end def test_replace_failure @@ -1326,13 +1336,40 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [companies(:second_client).id, companies(:first_client).id], companies(:first_firm).clients_ordered_by_name_ids end + def test_get_ids_for_association_on_new_record_does_not_try_to_find_records + Company.columns # Load schema information so we don't query below + Contract.columns # if running just this test. + + company = Company.new + assert_queries(0) do + company.contract_ids + end + + assert_equal [], company.contract_ids + end + + def test_set_ids_for_association_on_new_record_applies_association_correctly + contract_a = Contract.create! + contract_b = Contract.create! + Contract.create! # another contract + company = Company.new(:name => "Some Company") + + company.contract_ids = [contract_a.id, contract_b.id] + assert_equal [contract_a.id, contract_b.id], company.contract_ids + assert_equal [contract_a, contract_b], company.contracts + + company.save! + assert_equal company, contract_a.reload.company + assert_equal company, contract_b.reload.company + end + def test_assign_ids_ignoring_blanks firm = Firm.create!(:name => 'Apple') firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, ''] firm.save! assert_equal 2, firm.clients(true).size - assert firm.clients.include?(companies(:second_client)) + assert_equal true, firm.clients.include?(companies(:second_client)) end def test_get_ids_for_through @@ -1366,7 +1403,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_no_queries do assert firm.clients.loaded? - assert firm.clients.include?(client) + assert_equal true, firm.clients.include?(client) end end @@ -1377,7 +1414,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase firm.reload assert ! firm.clients.loaded? assert_queries(1) do - assert firm.clients.include?(client) + assert_equal true, firm.clients.include?(client) end assert ! firm.clients.loaded? end @@ -1388,7 +1425,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase firm.reload assert ! firm.clients_using_sql.loaded? - assert firm.clients_using_sql.include?(client) + assert_equal true, firm.clients_using_sql.include?(client) assert firm.clients_using_sql.loaded? end @@ -1398,7 +1435,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase client = Client.create!(:name => 'Not Associated') assert ! firm.clients.loaded? - assert ! firm.clients.include?(client) + assert_equal false, firm.clients.include?(client) end def test_calling_first_or_last_on_association_should_not_load_association @@ -1613,7 +1650,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_include_method_in_has_many_association_should_return_true_for_instance_added_with_build post = Post.new comment = post.comments.build - assert post.comments.include?(comment) + assert_equal true, post.comments.include?(comment) end def test_load_target_respects_protected_attributes @@ -1747,12 +1784,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_deprecated { klass.has_many :foo, :counter_sql => 'lol' } end - test "sum calculation with block for array compatibility is deprecated" do - assert_deprecated do - posts(:welcome).comments.sum { |c| c.id } - end - end - test "has many associations on new records use null relations" do post = Post.new diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb index b1f0be3204..71cf1237e8 100644 --- a/activerecord/test/cases/associations/inverse_associations_test.rb +++ b/activerecord/test/cases/associations/inverse_associations_test.rb @@ -401,10 +401,22 @@ class InverseHasManyTests < ActiveRecord::TestCase assert_equal man.name, man.interests.find(interest.id).man.name, "The name of the man should match after the child name is changed" end + def test_find_on_child_instance_with_id_should_not_load_all_child_records + man = Man.create! + interest = Interest.create!(man: man) + + man.interests.find(interest.id) + refute man.interests.loaded? + end + def test_raise_record_not_found_error_when_invalid_ids_are_passed + # delete all interest records to ensure that hard coded invalid_id(s) + # are indeed invalid. + Interest.delete_all + man = Man.create! - invalid_id = 2394823094892348920348523452345 + invalid_id = 245324523 assert_raise(ActiveRecord::RecordNotFound) { man.interests.find(invalid_id) } invalid_ids = [8432342, 2390102913, 2453245234523452] diff --git a/activerecord/test/cases/attribute_methods/serialization_test.rb b/activerecord/test/cases/attribute_methods/serialization_test.rb new file mode 100644 index 0000000000..75de773961 --- /dev/null +++ b/activerecord/test/cases/attribute_methods/serialization_test.rb @@ -0,0 +1,29 @@ +require "cases/helper" + +module ActiveRecord + module AttributeMethods + class SerializationTest < ActiveSupport::TestCase + class FakeColumn < Struct.new(:name) + def type; :integer; end + def type_cast(s); "#{s}!"; end + end + + class NullCoder + def load(v); v; end + end + + def test_type_cast_serialized_value + value = Serialization::Attribute.new(NullCoder.new, "Hello world", :serialized) + type = Serialization::Type.new(FakeColumn.new) + assert_equal "Hello world!", type.type_cast(value) + end + + def test_type_cast_unserialized_value + value = Serialization::Attribute.new(nil, "Hello world", :unserialized) + type = Serialization::Type.new(FakeColumn.new) + type.type_cast(value) + assert_equal "Hello world", type.type_cast(value) + end + end + end +end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 56b417562b..395f28f280 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -581,12 +581,6 @@ class BasicsTest < ActiveRecord::TestCase assert_equal "changed", post.body end - def test_attr_readonly_is_class_level_setting - post = ReadonlyTitlePost.new - assert_raise(NoMethodError) { post._attr_readonly = [:title] } - assert_deprecated { post._attr_readonly } - end - def test_non_valid_identifier_column_name weird = Weird.create('a$b' => 'value') weird.reload @@ -1228,38 +1222,6 @@ class BasicsTest < ActiveRecord::TestCase assert_no_queries { assert true } end - def test_silence_sets_log_level_to_error_in_block - original_logger = ActiveRecord::Base.logger - - assert_deprecated do - log = StringIO.new - ActiveRecord::Base.logger = ActiveSupport::Logger.new(log) - ActiveRecord::Base.logger.level = Logger::DEBUG - ActiveRecord::Base.silence do - ActiveRecord::Base.logger.warn "warn" - ActiveRecord::Base.logger.error "error" - end - assert_equal "error\n", log.string - end - ensure - ActiveRecord::Base.logger = original_logger - end - - def test_silence_sets_log_level_back_to_level_before_yield - original_logger = ActiveRecord::Base.logger - - assert_deprecated do - log = StringIO.new - ActiveRecord::Base.logger = ActiveSupport::Logger.new(log) - ActiveRecord::Base.logger.level = Logger::WARN - ActiveRecord::Base.silence do - end - assert_equal Logger::WARN, ActiveRecord::Base.logger.level - end - ensure - ActiveRecord::Base.logger = original_logger - end - def test_benchmark_with_log_level original_logger = ActiveRecord::Base.logger log = StringIO.new diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index e09fa95756..1d6676da1c 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -26,6 +26,24 @@ class EachTest < ActiveRecord::TestCase end end + def test_each_should_return_an_enumerator_if_no_block_is_present + assert_queries(1) do + Post.find_each(:batch_size => 100000).with_index do |post, index| + assert_kind_of Post, post + assert_kind_of Integer, index + end + end + end + + def test_each_enumerator_should_execute_one_query_per_batch + assert_queries(@total + 1) do + Post.find_each(:batch_size => 1).with_index do |post, index| + assert_kind_of Post, post + assert_kind_of Integer, index + end + end + end + def test_each_should_raise_if_select_is_set_without_id assert_raise(RuntimeError) do Post.select(:title).find_each(:batch_size => 1) { |post| post } diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index f49bef2346..0f3f9aecfc 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -6,6 +6,7 @@ require 'models/edge' require 'models/organization' require 'models/possession' require 'models/topic' +require 'models/reply' require 'models/minivan' require 'models/speedometer' require 'models/ship_part' @@ -166,6 +167,15 @@ class CalculationsTest < ActiveRecord::TestCase assert_no_match(/OFFSET/, queries.first) end + def test_count_on_invalid_columns_raises + e = assert_raises(ActiveRecord::StatementInvalid) { + Account.select("credit_limit, firm_name").count + } + + assert_match "accounts", e.message + assert_match "credit_limit, firm_name", e.message + end + def test_should_group_by_summed_field_having_condition c = Account.group(:firm_id).having('sum(credit_limit) > 50').sum(:credit_limit) assert_nil c[1] @@ -410,12 +420,6 @@ class CalculationsTest < ActiveRecord::TestCase Account.where("credit_limit > 50").from('accounts').sum(:credit_limit) end - def test_sum_array_compatibility_deprecation - assert_deprecated do - assert_equal Account.sum(:credit_limit), Account.sum(&:credit_limit) - end - end - def test_average_with_from_option assert_equal Account.average(:credit_limit), Account.from('accounts').average(:credit_limit) assert_equal Account.where("credit_limit > 50").average(:credit_limit), @@ -478,6 +482,11 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal [1,2,3,4], Topic.order(:id).pluck(:id) end + def test_pluck_without_column_names + assert_equal [[1, "Firm", 1, nil, "37signals", nil, 1, nil, ""]], + Company.order(:id).limit(1).pluck + end + def test_pluck_type_cast topic = topics(:first) relation = Topic.where(:id => topic.id) @@ -539,6 +548,11 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal Company.all.map(&:id).sort, Company.ids.sort end + def test_pluck_with_includes_limit_and_empty_result + assert_equal [], Topic.includes(:replies).limit(0).pluck(:id) + assert_equal [], Topic.includes(:replies).limit(1).where('0 = 1').pluck(:id) + end + def test_pluck_not_auto_table_name_prefix_if_column_included Company.create!(:name => "test", :contracts => [Contract.new(:developer_id => 7)]) ids = Company.includes(:contracts).pluck(:developer_id) diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb index e6af29282c..d5365b695e 100644 --- a/activerecord/test/cases/connection_pool_test.rb +++ b/activerecord/test/cases/connection_pool_test.rb @@ -329,7 +329,7 @@ module ActiveRecord end # make sure exceptions are thrown when establish_connection - # is called with a anonymous class + # is called with an anonymous class def test_anonymous_class_exception anonymous = Class.new(ActiveRecord::Base) handler = ActiveRecord::Base.connection_handler diff --git a/activerecord/test/cases/counter_cache_test.rb b/activerecord/test/cases/counter_cache_test.rb index 61f9d4cdae..ee3d8a81c2 100644 --- a/activerecord/test/cases/counter_cache_test.rb +++ b/activerecord/test/cases/counter_cache_test.rb @@ -51,14 +51,9 @@ class CounterCacheTest < ActiveRecord::TestCase end end - test 'reset multiple association counters' do - Topic.increment_counter(:replies_count, @topic.id) - assert_difference '@topic.reload.replies_count', -1 do - Topic.reset_counters(@topic.id, :replies, :unique_replies) - end - - Topic.increment_counter(:unique_replies_count, @topic.id) - assert_difference '@topic.reload.unique_replies_count', -1 do + test 'reset multiple counters' do + Topic.update_counters @topic.id, replies_count: 1, unique_replies_count: 1 + assert_difference ['@topic.reload.replies_count', '@topic.reload.unique_replies_count'], -1 do Topic.reset_counters(@topic.id, :replies, :unique_replies) end end @@ -127,6 +122,12 @@ class CounterCacheTest < ActiveRecord::TestCase end end + test 'update multiple counters' do + assert_difference ['@topic.reload.replies_count', '@topic.reload.unique_replies_count'], 2 do + Topic.update_counters @topic.id, replies_count: 2, unique_replies_count: 2 + end + end + test "update other counters on parent destroy" do david, joanna = dog_lovers(:david, :joanna) joanna = joanna # squelch a warning diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index e0cf4adf13..7e3d91e08c 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -39,6 +39,31 @@ class DefaultTest < ActiveRecord::TestCase end end +class DefaultStringsTest < ActiveRecord::TestCase + class DefaultString < ActiveRecord::Base; end + + setup do + @connection = ActiveRecord::Base.connection + @connection.create_table :default_strings do |t| + t.string :string_col, default: "Smith" + t.string :string_col_with_quotes, default: "O'Connor" + end + DefaultString.reset_column_information + end + + def test_default_strings + assert_equal "Smith", DefaultString.new.string_col + end + + def test_default_strings_containing_single_quotes + assert_equal "O'Connor", DefaultString.new.string_col_with_quotes + end + + teardown do + @connection.drop_table :default_strings + end +end + if current_adapter?(:MysqlAdapter, :Mysql2Adapter) class DefaultsTestWithoutTransactionalFixtures < ActiveRecord::TestCase # ActiveRecord::Base#create! (and #save and other related methods) will diff --git a/activerecord/test/cases/disconnected_test.rb b/activerecord/test/cases/disconnected_test.rb new file mode 100644 index 0000000000..cc2c1f6489 --- /dev/null +++ b/activerecord/test/cases/disconnected_test.rb @@ -0,0 +1,26 @@ +require "cases/helper" + +class TestRecord < ActiveRecord::Base +end + +class TestDisconnectedAdapter < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + def setup + @connection = ActiveRecord::Base.connection + end + + def teardown + spec = ActiveRecord::Base.connection_config + ActiveRecord::Base.establish_connection(spec) + @connection = nil + end + + test "can't execute statements while disconnected" do + @connection.execute "SELECT count(*) from products" + @connection.disconnect! + assert_raises(ActiveRecord::StatementInvalid) do + @connection.execute "SELECT count(*) from products" + end + end +end diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index f6cfee0cb8..df6edc4057 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -245,6 +245,22 @@ class FixturesTest < ActiveRecord::TestCase def test_serialized_fixtures assert_equal ["Green", "Red", "Orange"], traffic_lights(:uk).state end + + def test_fixtures_are_set_up_with_database_env_variable + ENV.stubs(:[]).with("DATABASE_URL").returns("sqlite3:///:memory:") + ActiveRecord::Base.stubs(:configurations).returns({}) + test_case = Class.new(ActiveRecord::TestCase) do + fixtures :accounts + + def test_fixtures + assert accounts(:signals37) + end + end + + result = test_case.new(:test_fixtures).run + + assert result.passed?, "Expected #{result.name} to pass:\n#{result}" + end end if Account.connection.respond_to?(:reset_pk_sequence!) diff --git a/activerecord/test/cases/invalid_connection_test.rb b/activerecord/test/cases/invalid_connection_test.rb new file mode 100644 index 0000000000..f6fe7f0d7d --- /dev/null +++ b/activerecord/test/cases/invalid_connection_test.rb @@ -0,0 +1,20 @@ +require "cases/helper" +require "models/bird" + +class TestAdapterWithInvalidConnection < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + def setup + @spec = ActiveRecord::Base.connection_config + non_existing_spec = {adapter: @spec[:adapter], database: "i_do_not_exist"} + ActiveRecord::Base.establish_connection(non_existing_spec) + end + + def teardown + ActiveRecord::Base.establish_connection(@spec) + end + + test "inspect on Model class does not raise" do + assert_equal "Bird(no database connection)", Bird.inspect + end +end diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 77891b9156..0030f1b464 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -242,7 +242,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase car = Car.create! assert_difference 'car.wheels.count' do - car.wheels << Wheel.create! + car.wheels << Wheel.create! end assert_difference 'car.wheels.count', -1 do car.destroy diff --git a/activerecord/test/cases/log_subscriber_test.rb b/activerecord/test/cases/log_subscriber_test.rb index 57eac0c175..3bdc5a1302 100644 --- a/activerecord/test/cases/log_subscriber_test.rb +++ b/activerecord/test/cases/log_subscriber_test.rb @@ -56,6 +56,13 @@ class LogSubscriberTest < ActiveRecord::TestCase assert_equal 2, logger.debugs.length end + def test_sql_statements_are_not_squeezed + event = Struct.new(:duration, :payload) + logger = TestDebugLogSubscriber.new + logger.sql(event.new(0, sql: 'ruby rails')) + assert_match(/ruby rails/, logger.debugs.first) + end + def test_ignore_binds_payload_with_nil_column event = Struct.new(:duration, :payload) diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb index 54fff8a0f5..e37dca856d 100644 --- a/activerecord/test/cases/migration/change_schema_test.rb +++ b/activerecord/test/cases/migration/change_schema_test.rb @@ -74,6 +74,35 @@ module ActiveRecord assert_equal "hello", five.default unless mysql end + def test_add_column_with_array + if current_adapter?(:PostgreSQLAdapter) + connection.create_table :testings + connection.add_column :testings, :foo, :string, :array => true + + columns = connection.columns(:testings) + array_column = columns.detect { |c| c.name == "foo" } + + assert array_column.array + else + skip "array option only supported in PostgreSQLAdapter" + end + end + + def test_create_table_with_array_column + if current_adapter?(:PostgreSQLAdapter) + connection.create_table :testings do |t| + t.string :foo, :array => true + end + + columns = connection.columns(:testings) + array_column = columns.detect { |c| c.name == "foo" } + + assert array_column.array + else + skip "array option only supported in PostgreSQLAdapter" + end + end + def test_create_table_with_limits connection.create_table :testings do |t| t.column :foo, :string, :limit => 255 diff --git a/activerecord/test/cases/migration/index_test.rb b/activerecord/test/cases/migration/index_test.rb index 0e375af6e8..04521a5f5a 100644 --- a/activerecord/test/cases/migration/index_test.rb +++ b/activerecord/test/cases/migration/index_test.rb @@ -109,16 +109,6 @@ module ActiveRecord end end - def test_deprecated_type_argument - message = "Passing a string as third argument of `add_index` is deprecated and will" + - " be removed in Rails 4.1." + - " Use add_index(:testings, [:foo, :bar], unique: true) instead" - - assert_deprecated message do - connection.add_index :testings, [:foo, :bar], "UNIQUE" - end - end - def test_unique_index_exists connection.add_index :testings, :foo, :unique => true diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 193ffb26e3..e99312c245 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -849,4 +849,13 @@ class CopyMigrationsTest < ActiveRecord::TestCase ensure clear end + + def test_check_pending_with_stdlib_logger + old, ActiveRecord::Base.logger = ActiveRecord::Base.logger, ::Logger.new($stdout) + quietly do + assert_nothing_raised { ActiveRecord::Migration::CheckPending.new(Proc.new {}).call({}) } + end + ensure + ActiveRecord::Base.logger = old + end end diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 6fe81e0d96..2f89699df7 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -797,26 +797,6 @@ module NestedAttributesOnACollectionAssociationTests end end - def test_validate_presence_of_parent_fails_without_inverse_of - Man.accepts_nested_attributes_for(:interests) - Man.reflect_on_association(:interests).options.delete(:inverse_of) - Man.reflect_on_association(:interests).clear_inverse_of_cache! - Interest.reflect_on_association(:man).options.delete(:inverse_of) - Interest.reflect_on_association(:man).clear_inverse_of_cache! - - repair_validations(Interest) do - Interest.validates_presence_of(:man) - assert_no_difference ['Man.count', 'Interest.count'] do - man = Man.create(:name => 'John', - :interests_attributes => [{:topic=>'Cars'}, {:topic=>'Sports'}]) - assert !man.errors[:"interests.man"].empty? - end - end - ensure - Man.reflect_on_association(:interests).options[:inverse_of] = :man - Interest.reflect_on_association(:man).options[:inverse_of] = :interests - end - def test_can_use_symbols_as_object_identifier @pirate.attributes = { :parrots_attributes => { :foo => { :name => 'Lovely Day' }, :bar => { :name => 'Blown Away' } } } assert_nothing_raised(NoMethodError) { @pirate.save! } diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb index 03c7009568..693b36f35c 100644 --- a/activerecord/test/cases/relation_test.rb +++ b/activerecord/test/cases/relation_test.rb @@ -176,7 +176,7 @@ module ActiveRecord assert_equal ['foo = bar'], relation.where_values end - def test_relation_merging_with_merged_joins + def test_relation_merging_with_merged_joins_as_symbols special_comments_with_ratings = SpecialComment.joins(:ratings) posts_with_special_comments_with_ratings = Post.group("posts.id").joins(:special_comments).merge(special_comments_with_ratings) assert_equal 3, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count.length @@ -186,10 +186,17 @@ module ActiveRecord post = Post.select(:title).first assert_equal false, post.respond_to?(:body), "post should not respond_to?(:body) since invoking it raises exception" - post = Post.select("'title' as post_title").first + silence_warnings { post = Post.select("'title' as post_title").first } assert_equal false, post.respond_to?(:title), "post should not respond_to?(:body) since invoking it raises exception" end + def test_relation_merging_with_merged_joins_as_strings + join_string = "LEFT OUTER JOIN #{Rating.quoted_table_name} ON #{SpecialComment.quoted_table_name}.id = #{Rating.quoted_table_name}.comment_id" + special_comments_with_ratings = SpecialComment.joins join_string + posts_with_special_comments_with_ratings = Post.group("posts.id").joins(:special_comments).merge(special_comments_with_ratings) + assert_equal 3, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count.length + end + end class RelationMutationTest < ActiveSupport::TestCase diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index b64ff13d29..e746ca2805 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -278,8 +278,9 @@ class RelationTest < ActiveRecord::TestCase def test_null_relation_calculations_methods assert_no_queries do - assert_equal 0, Developer.none.count - assert_equal nil, Developer.none.calculate(:average, 'salary') + assert_equal 0, Developer.none.count + assert_equal 0, Developer.none.calculate(:count, nil, {}) + assert_equal nil, Developer.none.calculate(:average, 'salary') end end diff --git a/activerecord/test/cases/result_test.rb b/activerecord/test/cases/result_test.rb new file mode 100644 index 0000000000..b6c583dbf5 --- /dev/null +++ b/activerecord/test/cases/result_test.rb @@ -0,0 +1,32 @@ +require "cases/helper" + +module ActiveRecord + class ResultTest < ActiveRecord::TestCase + def result + Result.new(['col_1', 'col_2'], [ + ['row 1 col 1', 'row 1 col 2'], + ['row 2 col 1', 'row 2 col 2'] + ]) + end + + def test_to_hash_returns_row_hashes + assert_equal [ + {'col_1' => 'row 1 col 1', 'col_2' => 'row 1 col 2'}, + {'col_1' => 'row 2 col 1', 'col_2' => 'row 2 col 2'} + ], result.to_hash + end + + def test_each_with_block_returns_row_hashes + result.each do |row| + assert_equal ['col_1', 'col_2'], row.keys + end + end + + def test_each_without_block_returns_an_enumerator + result.each.with_index do |row, index| + assert_equal ['col_1', 'col_2'], row.keys + assert_kind_of Integer, index + end + end + end +end diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb index 765e92ccca..b49c27bc78 100644 --- a/activerecord/test/cases/serialized_attribute_test.rb +++ b/activerecord/test/cases/serialized_attribute_test.rb @@ -19,12 +19,6 @@ class SerializedAttributeTest < ActiveRecord::TestCase assert_equal %w(content), Topic.serialized_attributes.keys end - def test_serialized_attributes_are_class_level_settings - topic = Topic.new - assert_raise(NoMethodError) { topic.serialized_attributes = [] } - assert_deprecated { topic.serialized_attributes } - end - def test_serialized_attribute Topic.serialize("content", MyObject) diff --git a/activerecord/test/cases/store_test.rb b/activerecord/test/cases/store_test.rb index 3e32d866ee..c2c56abacd 100644 --- a/activerecord/test/cases/store_test.rb +++ b/activerecord/test/cases/store_test.rb @@ -150,9 +150,4 @@ class StoreTest < ActiveRecord::TestCase test "all stored attributes are returned" do assert_equal [:color, :homepage, :favorite_food], Admin::User.stored_attributes[:settings] end - - test "stores_attributes are class level settings" do - assert_raise(NoMethodError) { @john.stored_attributes = Hash.new } - assert_raise(NoMethodError) { @john.stored_attributes } - end end diff --git a/activerecord/test/cases/tasks/firebird_rake_test.rb b/activerecord/test/cases/tasks/firebird_rake_test.rb deleted file mode 100644 index c54989ae34..0000000000 --- a/activerecord/test/cases/tasks/firebird_rake_test.rb +++ /dev/null @@ -1,100 +0,0 @@ -require 'cases/helper' - -unless defined?(FireRuby::Database) -module FireRuby - module Database; end -end -end - -module ActiveRecord - module FirebirdSetupper - def setup - @database = 'db.firebird' - @connection = stub :connection - @configuration = { - 'adapter' => 'firebird', - 'database' => @database - } - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - - @tasks = Class.new(ActiveRecord::Tasks::FirebirdDatabaseTasks) do - def initialize(configuration) - ActiveSupport::Deprecation.silence { super } - end - end - ActiveRecord::Tasks::DatabaseTasks.stubs(:class_for_adapter).returns(@tasks) unless defined? ActiveRecord::ConnectionAdapters::FirebirdAdapter - end - end - - class FirebirdDBCreateTest < ActiveRecord::TestCase - include FirebirdSetupper - - def test_db_retrieves_create - message = capture(:stderr) do - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end - assert_match(/not supported/, message) - end - end - - class FirebirdDBDropTest < ActiveRecord::TestCase - include FirebirdSetupper - - def test_db_retrieves_drop - message = capture(:stderr) do - ActiveRecord::Tasks::DatabaseTasks.drop @configuration - end - assert_match(/not supported/, message) - end - end - - class FirebirdDBCharsetAndCollationTest < ActiveRecord::TestCase - include FirebirdSetupper - - def test_db_retrieves_collation - assert_raise NoMethodError do - ActiveRecord::Tasks::DatabaseTasks.collation @configuration - end - end - - def test_db_retrieves_charset - message = capture(:stderr) do - ActiveRecord::Tasks::DatabaseTasks.charset @configuration - end - assert_match(/not supported/, message) - end - end - - class FirebirdStructureDumpTest < ActiveRecord::TestCase - include FirebirdSetupper - - def setup - super - FireRuby::Database.stubs(:db_string_for).returns(@database) - end - - def test_structure_dump - filename = "filebird.sql" - Kernel.expects(:system).with("isql -a #{@database} > #{filename}") - - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) - end - end - - class FirebirdStructureLoadTest < ActiveRecord::TestCase - include FirebirdSetupper - - def setup - super - FireRuby::Database.stubs(:db_string_for).returns(@database) - end - - def test_structure_load - filename = "firebird.sql" - Kernel.expects(:system).with("isql -i #{filename} #{@database}") - - ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) - end - end -end diff --git a/activerecord/test/cases/tasks/oracle_rake_test.rb b/activerecord/test/cases/tasks/oracle_rake_test.rb deleted file mode 100644 index 5f840febbc..0000000000 --- a/activerecord/test/cases/tasks/oracle_rake_test.rb +++ /dev/null @@ -1,93 +0,0 @@ -require 'cases/helper' - -module ActiveRecord - module OracleSetupper - def setup - @database = 'db.oracle' - @connection = stub :connection - @configuration = { - 'adapter' => 'oracle', - 'database' => @database - } - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - - @tasks = Class.new(ActiveRecord::Tasks::OracleDatabaseTasks) do - def initialize(configuration) - ActiveSupport::Deprecation.silence { super } - end - end - ActiveRecord::Tasks::DatabaseTasks.stubs(:class_for_adapter).returns(@tasks) unless defined? ActiveRecord::ConnectionAdapters::OracleAdapter - end - end - - class OracleDBCreateTest < ActiveRecord::TestCase - include OracleSetupper - - def test_db_retrieves_create - message = capture(:stderr) do - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end - assert_match(/not supported/, message) - end - end - - class OracleDBDropTest < ActiveRecord::TestCase - include OracleSetupper - - def test_db_retrieves_drop - message = capture(:stderr) do - ActiveRecord::Tasks::DatabaseTasks.drop @configuration - end - assert_match(/not supported/, message) - end - end - - class OracleDBCharsetAndCollationTest < ActiveRecord::TestCase - include OracleSetupper - - def test_db_retrieves_collation - assert_raise NoMethodError do - ActiveRecord::Tasks::DatabaseTasks.collation @configuration - end - end - - def test_db_retrieves_charset - message = capture(:stderr) do - ActiveRecord::Tasks::DatabaseTasks.charset @configuration - end - assert_match(/not supported/, message) - end - end - - class OracleStructureDumpTest < ActiveRecord::TestCase - include OracleSetupper - - def setup - super - @connection.stubs(:structure_dump).returns("select sysdate from dual;") - end - - def test_structure_dump - filename = "oracle.sql" - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) - assert File.exists?(filename) - ensure - FileUtils.rm_f(filename) - end - end - - class OracleStructureLoadTest < ActiveRecord::TestCase - include OracleSetupper - - def test_structure_load - filename = "oracle.sql" - - open(filename, 'w') { |f| f.puts("select sysdate from dual;") } - @connection.stubs(:execute).with("select sysdate from dual;\n") - ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) - ensure - FileUtils.rm_f(filename) - end - end -end diff --git a/activerecord/test/cases/tasks/sqlserver_rake_test.rb b/activerecord/test/cases/tasks/sqlserver_rake_test.rb deleted file mode 100644 index 0f1264b8ce..0000000000 --- a/activerecord/test/cases/tasks/sqlserver_rake_test.rb +++ /dev/null @@ -1,87 +0,0 @@ -require 'cases/helper' - -module ActiveRecord - module SqlserverSetupper - def setup - @database = 'db.sqlserver' - @connection = stub :connection - @configuration = { - 'adapter' => 'sqlserver', - 'database' => @database, - 'host' => 'localhost', - 'username' => 'username', - 'password' => 'password', - } - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - - @tasks = Class.new(ActiveRecord::Tasks::SqlserverDatabaseTasks) do - def initialize(configuration) - ActiveSupport::Deprecation.silence { super } - end - end - ActiveRecord::Tasks::DatabaseTasks.stubs(:class_for_adapter).returns(@tasks) unless defined? ActiveRecord::ConnectionAdapters::SQLServerAdapter - end - end - - class SqlserverDBCreateTest < ActiveRecord::TestCase - include SqlserverSetupper - - def test_db_retrieves_create - message = capture(:stderr) do - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end - assert_match(/not supported/, message) - end - end - - class SqlserverDBDropTest < ActiveRecord::TestCase - include SqlserverSetupper - - def test_db_retrieves_drop - message = capture(:stderr) do - ActiveRecord::Tasks::DatabaseTasks.drop @configuration - end - assert_match(/not supported/, message) - end - end - - class SqlserverDBCharsetAndCollationTest < ActiveRecord::TestCase - include SqlserverSetupper - - def test_db_retrieves_collation - assert_raise NoMethodError do - ActiveRecord::Tasks::DatabaseTasks.collation @configuration - end - end - - def test_db_retrieves_charset - message = capture(:stderr) do - ActiveRecord::Tasks::DatabaseTasks.charset @configuration - end - assert_match(/not supported/, message) - end - end - - class SqlserverStructureDumpTest < ActiveRecord::TestCase - include SqlserverSetupper - - def test_structure_dump - filename = "sqlserver.sql" - Kernel.expects(:system).with("smoscript -s localhost -d #{@database} -u username -p password -f #{filename} -A -U") - - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) - end - end - - class SqlserverStructureLoadTest < ActiveRecord::TestCase - include SqlserverSetupper - - def test_structure_load - filename = "sqlserver.sql" - Kernel.expects(:system).with("sqlcmd -S localhost -d #{@database} -U username -P password -i #{filename}") - - ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) - end - end -end diff --git a/activerecord/test/cases/validations/association_validation_test.rb b/activerecord/test/cases/validations/association_validation_test.rb index 7ac34bc71e..7e92a2b127 100644 --- a/activerecord/test/cases/validations/association_validation_test.rb +++ b/activerecord/test/cases/validations/association_validation_test.rb @@ -118,21 +118,4 @@ class AssociationValidationTest < ActiveRecord::TestCase end end - def test_validates_associated_models_in_the_same_context - Topic.validates_presence_of :title, :on => :custom_context - Topic.validates_associated :replies - Reply.validates_presence_of :title, :on => :custom_context - - t = Topic.new('title' => '') - r = t.replies.new('title' => '') - - assert t.valid? - assert !t.valid?(:custom_context) - - t.title = "Longer" - assert !t.valid?(:custom_context), "Should NOT be valid if the associated object is not valid in the same context." - - r.title = "Longer" - assert t.valid?(:custom_context), "Should be valid if the associated object is not valid in the same context." - end end diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index a96899ae10..af80b1ba42 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -85,7 +85,7 @@ class Author < ActiveRecord::Base has_many :author_favorites has_many :favorite_authors, -> { order('name') }, :through => :author_favorites - has_many :taggings, :through => :posts + has_many :taggings, :through => :posts, :source => :taggings has_many :taggings_2, :through => :posts, :source => :tagging has_many :tags, :through => :posts has_many :post_categories, :through => :posts, :source => :categories diff --git a/activerecord/test/models/club.rb b/activerecord/test/models/club.rb index 7d7c205041..816c5e6937 100644 --- a/activerecord/test/models/club.rb +++ b/activerecord/test/models/club.rb @@ -1,6 +1,6 @@ class Club < ActiveRecord::Base has_one :membership - has_many :memberships, :automatic_inverse_of => false + has_many :memberships, :inverse_of => false has_many :members, :through => :memberships has_many :current_memberships has_one :sponsor diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index dcda62e71d..b988184f34 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -141,7 +141,7 @@ class Client < Company belongs_to :firm_with_primary_key_symbols, :class_name => "Firm", :primary_key => :name, :foreign_key => :firm_name belongs_to :readonly_firm, -> { readonly }, :class_name => "Firm", :foreign_key => "firm_id" belongs_to :bob_firm, -> { where :name => "Bob" }, :class_name => "Firm", :foreign_key => "client_of" - has_many :accounts, :through => :firm + has_many :accounts, :through => :firm, :source => :accounts belongs_to :account class RaisedOnSave < RuntimeError; end diff --git a/activerecord/test/models/interest.rb b/activerecord/test/models/interest.rb index f772bb1c7f..d5d9226204 100644 --- a/activerecord/test/models/interest.rb +++ b/activerecord/test/models/interest.rb @@ -1,5 +1,5 @@ class Interest < ActiveRecord::Base - belongs_to :man, :inverse_of => :interests, :automatic_inverse_of => false + belongs_to :man, :inverse_of => :interests belongs_to :polymorphic_man, :polymorphic => true, :inverse_of => :polymorphic_interests belongs_to :zine, :inverse_of => :interests end diff --git a/activerecord/test/models/man.rb b/activerecord/test/models/man.rb index 49f002aa9a..4bff92dc98 100644 --- a/activerecord/test/models/man.rb +++ b/activerecord/test/models/man.rb @@ -1,7 +1,7 @@ class Man < ActiveRecord::Base has_one :face, :inverse_of => :man has_one :polymorphic_face, :class_name => 'Face', :as => :polymorphic_man, :inverse_of => :polymorphic_man - has_many :interests, :inverse_of => :man, :automatic_inverse_of => false + has_many :interests, :inverse_of => :man has_many :polymorphic_interests, :class_name => 'Interest', :as => :polymorphic_man, :inverse_of => :polymorphic_man # These are "broken" inverse_of associations for the purposes of testing has_one :dirty_face, :class_name => 'Face', :inverse_of => :dirty_man diff --git a/activerecord/test/models/member.rb b/activerecord/test/models/member.rb index b81304b8e0..cc47c7bc18 100644 --- a/activerecord/test/models/member.rb +++ b/activerecord/test/models/member.rb @@ -9,7 +9,7 @@ class Member < ActiveRecord::Base has_one :hairy_club, -> { where :clubs => {:name => "Moustache and Eyebrow Fancier Club"} }, :through => :membership, :source => :club has_one :sponsor, :as => :sponsorable has_one :sponsor_club, :through => :sponsor - has_one :member_detail, :automatic_inverse_of => false + has_one :member_detail, :inverse_of => false has_one :organization, :through => :member_detail belongs_to :member_type diff --git a/activerecord/test/models/member_detail.rb b/activerecord/test/models/member_detail.rb index a256c73c7e..9d253aa126 100644 --- a/activerecord/test/models/member_detail.rb +++ b/activerecord/test/models/member_detail.rb @@ -1,5 +1,5 @@ class MemberDetail < ActiveRecord::Base - belongs_to :member, :automatic_inverse_of => false + belongs_to :member, :inverse_of => false belongs_to :organization has_one :member_type, :through => :member diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 1982811500..45f71daa08 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,40 @@ +* Fix return value from `BacktraceCleaner#noise` when the cleaner is configured + with multiple silencers. + + Fixes #11030 + + *Mark J. Titorenko* + +* `HashWithIndifferentAccess#select` now returns a `HashWithIndifferentAccess` + instance instead of a `Hash` instance. + + Fixes #10723 + + *Albert Llop* + +* Add `DateTime#usec` and `DateTime#nsec` so that `ActiveSupport::TimeWithZone` keeps + sub-second resolution when wrapping a `DateTime` value. + + Fixes #10855 + + *Andrew White* + +* Fix `ActiveSupport::Dependencies::Loadable#load_dependency` calling + `#blame_file!` on Exceptions that do not have the Blamable mixin + + *Andrew Kreiling* + +* Override `Time.at` to support the passing of Time-like values when called with a single argument. + + *Andrew White* + +* Prevent side effects to hashes inside arrays when + `Hash#with_indifferent_access` is called. + + Fixes #10526 + + *Yves Senn* + * Raise an error when multiple `included` blocks are defined for a Concern. The old behavior would silently discard previously defined blocks, running only the last one. diff --git a/activesupport/Rakefile b/activesupport/Rakefile index e3788ed54f..99770bace9 100644 --- a/activesupport/Rakefile +++ b/activesupport/Rakefile @@ -9,20 +9,23 @@ Rake::TestTask.new do |t| t.verbose = true end + namespace :test do - Rake::TestTask.new(:isolated) do |t| - t.pattern = 'test/ts_isolated.rb' + task :isolated do + ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME')) + Dir.glob("test/**/*_test.rb").all? do |file| + sh(ruby, '-w', '-Ilib:test', file) + end or raise "Failures" end end - spec = eval(File.read('activesupport.gemspec')) Gem::PackageTask.new(spec) do |p| p.gem_spec = spec end -desc "Release to gemcutter" +desc "Release to rubygems" task :release => :package do require 'rake/gemcutter' Rake::Gemcutter::Tasks.new(spec).define diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb index 4b41e6247d..c88ae3e661 100644 --- a/activesupport/lib/active_support/backtrace_cleaner.rb +++ b/activesupport/lib/active_support/backtrace_cleaner.rb @@ -13,17 +13,17 @@ module ActiveSupport # can focus on the rest. # # bc = BacktraceCleaner.new - # bc.add_filter { |line| line.gsub(Rails.root, '') } - # bc.add_silencer { |line| line =~ /mongrel|rubygems/ } - # bc.clean(exception.backtrace) # will strip the Rails.root prefix and skip any lines from mongrel or rubygems + # bc.add_filter { |line| line.gsub(Rails.root, '') } # strip the Rails.root prefix + # bc.add_silencer { |line| line =~ /mongrel|rubygems/ } # skip any lines from mongrel or rubygems + # bc.clean(exception.backtrace) # perform the cleanup # # To reconfigure an existing BacktraceCleaner (like the default one in Rails) # and show as much data as possible, you can always call # <tt>BacktraceCleaner#remove_silencers!</tt>, which will restore the # backtrace to a pristine state. If you need to reconfigure an existing # BacktraceCleaner so that it does not filter or modify the paths of any lines - # of the backtrace, you can call BacktraceCleaner#remove_filters! These two - # methods will give you a completely untouched backtrace. + # of the backtrace, you can call <tt>BacktraceCleaner#remove_filters!<tt> + # These two methods will give you a completely untouched backtrace. # # Inspired by the Quiet Backtrace gem by Thoughtbot. class BacktraceCleaner @@ -97,11 +97,7 @@ module ActiveSupport end def noise(backtrace) - @silencers.each do |s| - backtrace = backtrace.select { |line| s.call(line) } - end - - backtrace + backtrace - silence(backtrace) end end end diff --git a/activesupport/lib/active_support/benchmarkable.rb b/activesupport/lib/active_support/benchmarkable.rb index 6413502b53..805b7a714f 100644 --- a/activesupport/lib/active_support/benchmarkable.rb +++ b/activesupport/lib/active_support/benchmarkable.rb @@ -45,15 +45,5 @@ module ActiveSupport yield end end - - # Silence the logger during the execution of the block. - def silence - message = "ActiveSupport::Benchmarkable#silence is deprecated. It will be removed from Rails 4.1." - ActiveSupport::Deprecation.warn message - old_logger_level, logger.level = logger.level, ::Logger::ERROR if logger - yield - ensure - logger.level = old_logger_level if logger - end end end diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index b1ab5570a8..c539048a85 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -228,7 +228,7 @@ module ActiveSupport # # Setting <tt>:race_condition_ttl</tt> is very useful in situations where # a cache entry is used very frequently and is under heavy load. If a - # cache expires and due to heavy load seven different processes will try + # cache expires and due to heavy load several different processes will try # to read data natively and then they all will try to write to cache. To # avoid that case the first process to find an expired cache entry will # bump the cache expiration time by the value set in <tt>:race_condition_ttl</tt>. diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 85b7669353..2cffa342ef 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -94,6 +94,15 @@ module ActiveSupport def halted_callback_hook(filter) end + module Conditionals # :nodoc: + class Value + def initialize(&block) + @block = block + end + def call(target, value); @block.call(value); end + end + end + module Filters Environment = Struct.new(:target, :halted, :value, :run_block) @@ -403,8 +412,8 @@ module ActiveSupport # the same after this point: # # Symbols:: Already methods. - # Strings:: class_eval'ed into methods. - # Procs:: define_method'ed into methods. + # Strings:: class_eval'd into methods. + # Procs:: using define_method compiled into methods. # Objects:: # a method is created that calls the before_foo method # on the object. @@ -415,6 +424,7 @@ module ActiveSupport when String l = eval "lambda { |value| #{filter} }" lambda { |target, value| target.instance_exec(value, &l) } + when Conditionals::Value then filter when ::Proc if filter.arity > 1 return lambda { |target, _, &block| @@ -648,7 +658,7 @@ module ActiveSupport # # * <tt>:terminator</tt> - Determines when a before filter will halt the # callback chain, preventing following callbacks from being called and - # the event from being triggered. This is a string to be eval'ed. The + # the event from being triggered. This is a string to be eval'd. The # result of the callback is available in the +result+ variable. # # define_callbacks :validate, terminator: 'result == false' diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb index 106a65610c..06e4847e82 100644 --- a/activesupport/lib/active_support/core_ext/date/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date/calculations.rb @@ -119,4 +119,15 @@ class Date options.fetch(:day, day) ) end + + # Allow Date to be compared with Time by converting to DateTime and relying on the <=> from there. + def compare_with_coercion(other) + if other.is_a?(Time) + self.to_datetime <=> other + else + compare_without_coercion(other) + end + end + alias_method :compare_without_coercion, :<=> + alias_method :<=>, :compare_with_coercion end diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb index df07917d19..c44626aed9 100644 --- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb @@ -80,6 +80,16 @@ class DateTime seconds_since_unix_epoch.to_i end + # Returns the fraction of a second as microseconds + def usec + (sec_fraction * 1_000_000).to_i + end + + # Returns the fraction of a second as nanoseconds + def nsec + (sec_fraction * 1_000_000_000).to_i + end + private def offset_in_seconds diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 6d42667e97..3dde87ac2e 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -164,7 +164,7 @@ class Module # # Reason is twofold: On one hand doing less calls is in general better. # On the other hand it could be that the target has side-effects, - # whereas conceptualy, from the user point of view, the delegator should + # whereas conceptually, from the user point of view, the delegator should # be doing one call. if allow_nil module_eval(<<-EOS, file, line - 3) diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index a3ce7dbe3f..c65f20c2d5 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -65,6 +65,18 @@ class Time def current ::Time.zone ? ::Time.zone.now : ::Time.now end + + # Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime + # instances can be used when called with a single argument + def at_with_coercion(*args) + if args.size == 1 && args.first.acts_like?(:time) + at_without_coercion(args.first.to_i) + else + at_without_coercion(*args) + end + end + alias_method :at_without_coercion, :at + alias_method :at, :at_with_coercion end # Seconds since midnight: Time.now.seconds_since_midnight diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index fff4c776a9..73559bfe0e 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -213,7 +213,7 @@ module ActiveSupport #:nodoc: yield end rescue Exception => exception # errors from loading file - exception.blame_file! file + exception.blame_file! file if exception.respond_to? :blame_file! raise end @@ -416,7 +416,7 @@ module ActiveSupport #:nodoc: def load_file(path, const_paths = loadable_constants_for_path(path)) log_call path, const_paths const_paths = [const_paths].compact unless const_paths.is_a? Array - parent_paths = const_paths.collect { |const_path| const_path[/.*(?=::)/] || :Object } + parent_paths = const_paths.collect { |const_path| const_path[/.*(?=::)/] || ::Object } result = nil newly_defined_paths = new_constants_in(*parent_paths) do @@ -634,7 +634,7 @@ module ActiveSupport #:nodoc: when String then desc.sub(/^::/, '') when Symbol then desc.to_s when Module - desc.name.presence || + desc.name || raise(ArgumentError, "Anonymous modules have no name to be referenced by") else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}" end diff --git a/activesupport/lib/active_support/file_update_checker.rb b/activesupport/lib/active_support/file_update_checker.rb index 20136dd1b0..d6918bede2 100644 --- a/activesupport/lib/active_support/file_update_checker.rb +++ b/activesupport/lib/active_support/file_update_checker.rb @@ -115,7 +115,7 @@ module ActiveSupport end def compile_glob(hash) - hash.freeze # Freeze so changes aren't accidently pushed + hash.freeze # Freeze so changes aren't accidentally pushed return if hash.empty? globs = hash.map do |key, value| diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index bdb8877f55..95e03ba95c 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -91,7 +91,7 @@ module ActiveSupport # # This value can be later fetched using either +:key+ or +'key'+. def []=(key, value) - regular_writer(convert_key(key), convert_value(value)) + regular_writer(convert_key(key), convert_value(value, for: :assignment)) end alias_method :store, :[]= @@ -224,14 +224,18 @@ module ActiveSupport undef :symbolize_keys! undef :deep_symbolize_keys! def symbolize_keys; to_hash.symbolize_keys! end - def deep_symbolize_keys; to_hash.deep_symbolize_keys end + def deep_symbolize_keys; to_hash.deep_symbolize_keys! end def to_options!; self end + def select(*args, &block) + dup.select!(*args, &block) + end + # Convert to a regular hash with string keys. def to_hash _new_hash= {} each do |key, value| - _new_hash[convert_key(key)] = convert_value(value, true) + _new_hash[convert_key(key)] = convert_value(value, for: :to_hash) end Hash.new(default).merge!(_new_hash) end @@ -241,12 +245,18 @@ module ActiveSupport key.kind_of?(Symbol) ? key.to_s : key end - def convert_value(value, _convert_for_to_hash = false) + def convert_value(value, options = {}) if value.is_a? Hash - _convert_for_to_hash ? value.to_hash : value.nested_under_indifferent_access + if options[:for] == :to_hash + value.to_hash + else + value.nested_under_indifferent_access + end elsif value.is_a?(Array) - value = value.dup if value.frozen? - value.map! { |e| convert_value(e, _convert_for_to_hash) } + unless options[:for] == :assignment + value = value.dup + end + value.map! { |e| convert_value(e, options) } else value end diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index 39648727fd..a2263fa4d0 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -219,7 +219,12 @@ module ActiveSupport # unknown. def constantize(camel_cased_word) names = camel_cased_word.split('::') - names.shift if names.empty? || names.first.empty? + + # Trigger a builtin NameError exception including the ill-formed constant in the message. + Object.const_get(camel_cased_word) if names.empty? + + # Remove the first blank element in case of '::ClassName' notation. + names.shift if names.size > 1 && names.first.empty? names.inject(Object) do |constant, name| if constant == Object @@ -314,9 +319,14 @@ module ActiveSupport private # Mount a regular expression that will match part by part of the constant. - # For instance, Foo::Bar::Baz will generate Foo(::Bar(::Baz)?)? + # + # const_regexp("Foo::Bar::Baz") # => /Foo(::Bar(::Baz)?)?/ + # const_regexp("::") # => /::/ def const_regexp(camel_cased_word) #:nodoc: parts = camel_cased_word.split("::") + + return Regexp.escape(camel_cased_word) if parts.blank? + last = parts.pop parts.reverse.inject(last) do |acc, part| diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index 7f8b41d218..77b5d8d227 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -2,7 +2,6 @@ require 'active_support/core_ext/object/to_json' require 'active_support/core_ext/module/delegation' -require 'active_support/json/variable' require 'bigdecimal' require 'active_support/core_ext/big_decimal/conversions' # for #to_s diff --git a/activesupport/lib/active_support/json/variable.rb b/activesupport/lib/active_support/json/variable.rb deleted file mode 100644 index d69dab6408..0000000000 --- a/activesupport/lib/active_support/json/variable.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'active_support/deprecation' - -module ActiveSupport - module JSON - # Deprecated: A string that returns itself as its JSON-encoded form. - class Variable < String - def initialize(*args) - message = 'ActiveSupport::JSON::Variable is deprecated and will be removed in Rails 4.1. ' \ - 'For your own custom JSON literals, define #as_json and #encode_json yourself.' - ActiveSupport::Deprecation.warn message - super - end - - def as_json(options = nil) self end #:nodoc: - def encode_json(encoder) self end #:nodoc: - end - end -end diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb index c45358bba9..b32aa75e59 100644 --- a/activesupport/lib/active_support/notifications.rb +++ b/activesupport/lib/active_support/notifications.rb @@ -143,8 +143,8 @@ module ActiveSupport # # == Default Queue # - # Notifications ships with a queue implementation that consumes and publish events - # to log subscribers in a thread. You can use any queue implementation you want. + # Notifications ships with a queue implementation that consumes and publishes events + # to all log subscribers. You can use any queue implementation you want. # module Notifications class << self diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb index b124ae184d..2f27aff2bd 100644 --- a/activesupport/lib/active_support/test_case.rb +++ b/activesupport/lib/active_support/test_case.rb @@ -4,7 +4,6 @@ require 'active_support/testing/tagged_logging' require 'active_support/testing/setup_and_teardown' require 'active_support/testing/assertions' require 'active_support/testing/deprecation' -require 'active_support/testing/pending' require 'active_support/testing/declarative' require 'active_support/testing/isolation' require 'active_support/testing/constant_lookup' @@ -54,7 +53,6 @@ module ActiveSupport include ActiveSupport::Testing::SetupAndTeardown include ActiveSupport::Testing::Assertions include ActiveSupport::Testing::Deprecation - include ActiveSupport::Testing::Pending extend ActiveSupport::Testing::Declarative # test/unit backwards compatibility methods diff --git a/activesupport/lib/active_support/testing/declarative.rb b/activesupport/lib/active_support/testing/declarative.rb index 508e37254a..1fa73caefa 100644 --- a/activesupport/lib/active_support/testing/declarative.rb +++ b/activesupport/lib/active_support/testing/declarative.rb @@ -19,9 +19,12 @@ module ActiveSupport end unless defined?(Spec) - # test "verify something" do - # ... - # end + # Helper to define a test method using a String. Under the hood, it replaces + # spaces with underscores and defines the test method. + # + # test "verify something" do + # ... + # end def test(name, &block) test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym defined = instance_method(test_name) rescue false diff --git a/activesupport/lib/active_support/testing/pending.rb b/activesupport/lib/active_support/testing/pending.rb deleted file mode 100644 index b04bbbbaea..0000000000 --- a/activesupport/lib/active_support/testing/pending.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'active_support/deprecation' - -module ActiveSupport - module Testing - module Pending # :nodoc: - unless defined?(Spec) - def pending(description = "", &block) - ActiveSupport::Deprecation.warn("#pending is deprecated and will be removed in Rails 4.1, please use #skip instead.") - skip(description.blank? ? nil : description) - end - end - end - end -end diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index a65148cf1f..33f2b8dc9b 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -3,6 +3,19 @@ require 'active_support/callbacks' module ActiveSupport module Testing + # Adds support for +setup+ and +teardown+ callbacks. + # These callbacks serve as a replacement to overwriting the + # <tt>#setup</tt> and <tt>#teardown</tt> methods of your TestCase. + # + # class ExampleTest < ActiveSupport::TestCase + # setup do + # # ... + # end + # + # teardown do + # # ... + # end + # end module SetupAndTeardown extend ActiveSupport::Concern @@ -12,21 +25,23 @@ module ActiveSupport end module ClassMethods + # Add a callback, which runs before <tt>TestCase#setup</tt>. def setup(*args, &block) set_callback(:setup, :before, *args, &block) end + # Add a callback, which runs after <tt>TestCase#teardown</tt>. def teardown(*args, &block) set_callback(:teardown, :after, *args, &block) end end - def before_setup + def before_setup # :nodoc: super run_callbacks :setup end - def after_teardown + def after_teardown # :nodoc: run_callbacks :teardown super end diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 4a032b0ad0..95b9b8e5ae 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -292,7 +292,7 @@ module ActiveSupport end end - %w(year mon month day mday wday yday hour min sec to_date).each do |method_name| + %w(year mon month day mday wday yday hour min sec usec nsec to_date).each do |method_name| class_eval <<-EOV, __FILE__, __LINE__ + 1 def #{method_name} # def month time.#{method_name} # time.month @@ -300,10 +300,6 @@ module ActiveSupport EOV end - def usec - time.respond_to?(:usec) ? time.usec : 0 - end - def to_a [time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone] end diff --git a/activesupport/test/clean_backtrace_test.rb b/activesupport/test/clean_backtrace_test.rb index b14950acb3..dd67a45cf6 100644 --- a/activesupport/test/clean_backtrace_test.rb +++ b/activesupport/test/clean_backtrace_test.rb @@ -36,6 +36,27 @@ class BacktraceCleanerSilencerTest < ActiveSupport::TestCase end end +class BacktraceCleanerMultipleSilencersTest < ActiveSupport::TestCase + def setup + @bc = ActiveSupport::BacktraceCleaner.new + @bc.add_silencer { |line| line =~ /mongrel/ } + @bc.add_silencer { |line| line =~ /yolo/ } + end + + test "backtrace should not contain lines that match the silencers" do + assert_equal \ + [ "/other/class.rb" ], + @bc.clean([ "/mongrel/class.rb", "/other/class.rb", "/mongrel/stuff.rb", "/other/yolo.rb" ]) + end + + test "backtrace should only contain lines that match the silencers" do + assert_equal \ + [ "/mongrel/class.rb", "/mongrel/stuff.rb", "/other/yolo.rb" ], + @bc.clean([ "/mongrel/class.rb", "/other/class.rb", "/mongrel/stuff.rb", "/other/yolo.rb" ], + :noise) + end +end + class BacktraceCleanerFilterAndSilencerTest < ActiveSupport::TestCase def setup @bc = ActiveSupport::BacktraceCleaner.new diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb index 9b62295c96..bbeb710a0c 100644 --- a/activesupport/test/constantize_test_cases.rb +++ b/activesupport/test/constantize_test_cases.rb @@ -34,8 +34,6 @@ module ConstantizeTestCases assert_equal Case::Dice, yield("Object::Case::Dice") assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") - assert_equal Object, yield("") - assert_equal Object, yield("::") assert_raises(NameError) { yield("UnknownClass") } assert_raises(NameError) { yield("UnknownClass::Ace") } assert_raises(NameError) { yield("UnknownClass::Ace::Base") } @@ -45,6 +43,8 @@ module ConstantizeTestCases assert_raises(NameError) { yield("Ace::Base::ConstantizeTestCases") } assert_raises(NameError) { yield("Ace::Gas::Base") } assert_raises(NameError) { yield("Ace::Gas::ConstantizeTestCases") } + assert_raises(NameError) { yield("") } + assert_raises(NameError) { yield("::") } end def run_safe_constantize_tests_on @@ -58,8 +58,8 @@ module ConstantizeTestCases assert_equal Case::Dice, yield("Object::Case::Dice") assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") - assert_equal Object, yield("") - assert_equal Object, yield("::") + assert_nil yield("") + assert_nil yield("::") assert_nil yield("UnknownClass") assert_nil yield("UnknownClass::Ace") assert_nil yield("UnknownClass::Ace::Base") diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb index b1adf6d396..aa5e4461fd 100644 --- a/activesupport/test/core_ext/date_ext_test.rb +++ b/activesupport/test/core_ext/date_ext_test.rb @@ -48,6 +48,10 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end end + def test_compare_to_time + assert Date.yesterday < Time.now + end + def test_to_datetime assert_equal DateTime.civil(2005, 2, 21), Date.new(2005, 2, 21).to_datetime assert_equal 0, Date.new(2005, 2, 21).to_datetime.offset # use UTC offset diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb index 3e76b8a9b1..571344b728 100644 --- a/activesupport/test/core_ext/date_time_ext_test.rb +++ b/activesupport/test/core_ext/date_time_ext_test.rb @@ -327,6 +327,16 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal 946684800, DateTime.civil(1999,12,31,19,0,0,Rational(-5,24)).to_i end + def test_usec + assert_equal 0, DateTime.civil(2000).usec + assert_equal 500000, DateTime.civil(2000, 1, 1, 0, 0, Rational(1,2)).usec + end + + def test_nsec + assert_equal 0, DateTime.civil(2000).nsec + assert_equal 500000000, DateTime.civil(2000, 1, 1, 0, 0, Rational(1,2)).nsec + end + protected def with_env_tz(new_tz = 'US/Eastern') old_tz, ENV['TZ'] = ENV['TZ'], new_tz diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index dfcc6cd12a..c6d7ab618c 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -480,6 +480,36 @@ class HashExtTest < ActiveSupport::TestCase assert_equal hash.delete('a'), nil end + def test_indifferent_select + hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).select {|k,v| v == 1} + + assert_equal({ 'a' => 1 }, hash) + assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash + end + + def test_indifferent_select_bang + indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@strings) + indifferent_strings.select! {|k,v| v == 1} + + assert_equal({ 'a' => 1 }, indifferent_strings) + assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings + end + + def test_indifferent_reject + hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).reject {|k,v| v != 1} + + assert_equal({ 'a' => 1 }, hash) + assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash + end + + def test_indifferent_reject_bang + indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@strings) + indifferent_strings.reject! {|k,v| v != 1} + + assert_equal({ 'a' => 1 }, indifferent_strings) + assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings + end + def test_indifferent_to_hash # Should convert to a Hash with String keys. assert_equal @strings, @mixed.with_indifferent_access.to_hash @@ -503,6 +533,13 @@ class HashExtTest < ActiveSupport::TestCase assert_equal [1], hash[:a] end + def test_with_indifferent_access_has_no_side_effects_on_existing_hash + hash = {content: [{:foo => :bar, 'bar' => 'baz'}]} + hash.with_indifferent_access + + assert_equal [:foo, "bar"], hash[:content].first.keys + end + def test_indifferent_hash_with_array_of_hashes hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access assert_equal "1", hash[:urls][:url].first[:address] diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index 4e53aff00b..eefcdbb1b3 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -741,6 +741,28 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase assert_equal(-1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone['UTC'] )) end + def test_at_with_datetime + assert_equal Time.utc(2000, 1, 1, 0, 0, 0), Time.at(DateTime.civil(2000, 1, 1, 0, 0, 0)) + + # Only test this if the underlying Time.at raises a TypeError + begin + Time.at_without_coercion(Time.now, 0) + rescue TypeError + assert_raise(TypeError) { assert_equal(Time.utc(2000, 1, 1, 0, 0, 0), Time.at(DateTime.civil(2000, 1, 1, 0, 0, 0), 0)) } + end + end + + def test_at_with_time_with_zone + assert_equal Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'])) + + # Only test this if the underlying Time.at raises a TypeError + begin + Time.at_without_coercion(Time.now, 0) + rescue TypeError + assert_raise(TypeError) { assert_equal(Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC']), 0)) } + end + end + def test_eql? assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']) ) assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Hawaii"]) ) diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index 3ce3297874..ddcfcc491f 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -445,6 +445,16 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal 0, twz.usec end + def test_usec_returns_sec_fraction_when_datetime_is_wrapped + twz = ActiveSupport::TimeWithZone.new(DateTime.civil(2000, 1, 1, 0, 0, Rational(1,2)), @time_zone) + assert_equal 500000, twz.usec + end + + def test_nsec_returns_sec_fraction_when_datetime_is_wrapped + twz = ActiveSupport::TimeWithZone.new(DateTime.civil(2000, 1, 1, 0, 0, Rational(1,2)), @time_zone) + assert_equal 500000000, twz.nsec + end + def test_utc_to_local_conversion_saves_period_in_instance_variable assert_nil @twz.instance_variable_get('@period') @twz.time diff --git a/activesupport/test/dependencies/raises_exception_without_blame_file.rb b/activesupport/test/dependencies/raises_exception_without_blame_file.rb new file mode 100644 index 0000000000..4b2da6ff30 --- /dev/null +++ b/activesupport/test/dependencies/raises_exception_without_blame_file.rb @@ -0,0 +1,5 @@ +exception = Exception.new('I am not blamable!') +class << exception + undef_method(:blame_file!) +end +raise exception diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 4b1426bb2e..68b6cc6e8c 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -76,6 +76,14 @@ class DependenciesTest < ActiveSupport::TestCase end end + def test_dependency_which_raises_doesnt_blindly_call_blame_file! + with_loading do + filename = 'dependencies/raises_exception_without_blame_file' + + assert_raises(Exception) { require_dependency filename } + end + end + def test_warnings_should_be_enabled_on_first_load with_loading 'dependencies' do old_warnings, ActiveSupport::Dependencies.warnings_on_first_load = ActiveSupport::Dependencies.warnings_on_first_load, true diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index 14f4366f7b..ed1326705c 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -96,13 +96,6 @@ class TestJSONEncoding < ActiveSupport::TestCase end end - def test_json_variable - assert_deprecated do - assert_equal ActiveSupport::JSON::Variable.new('foo'), 'foo' - assert_equal ActiveSupport::JSON::Variable.new('alert("foo")'), 'alert("foo")' - end - end - def test_hash_encoding assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(:a => :b) assert_equal %({\"a\":1}), ActiveSupport::JSON.encode('a' => 1) diff --git a/activesupport/test/load_paths_test.rb b/activesupport/test/load_paths_test.rb index 979e25bdf3..ac617a9fd8 100644 --- a/activesupport/test/load_paths_test.rb +++ b/activesupport/test/load_paths_test.rb @@ -10,7 +10,7 @@ class LoadPathsTest < ActiveSupport::TestCase } load_paths_count[File.expand_path('../../lib', __FILE__)] -= 1 - filtered = load_paths_count.select { |k, v| v > 1 } - assert filtered.empty?, filtered.inspect + load_paths_count.select! { |k, v| v > 1 } + assert load_paths_count.empty?, load_paths_count.inspect end end diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb deleted file mode 100644 index 08df67827e..0000000000 --- a/activesupport/test/test_case_test.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'abstract_unit' - -module ActiveSupport - class TestCaseTest < ActiveSupport::TestCase - def test_pending_deprecation - assert_deprecated do - pending "should use #skip instead" - end - end - end -end diff --git a/activesupport/test/ts_isolated.rb b/activesupport/test/ts_isolated.rb deleted file mode 100644 index 294d6595f7..0000000000 --- a/activesupport/test/ts_isolated.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'active_support/testing/autorun' -require 'active_support/test_case' -require 'rbconfig' -require 'active_support/core_ext/kernel/reporting' - -class TestIsolated < ActiveSupport::TestCase - ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME')) - - Dir["#{File.dirname(__FILE__)}/**/*_test.rb"].each do |file| - define_method("test #{file}") do - command = "#{ruby} -Ilib:test #{file}" - result = silence_stderr { `#{command}` } - assert $?.to_i.zero?, "#{command}\n#{result}" - end - end -end diff --git a/activesupport/test/xml_mini/jdom_engine_test.rb b/activesupport/test/xml_mini/jdom_engine_test.rb index 904ef7b208..ed4de8aba2 100644 --- a/activesupport/test/xml_mini/jdom_engine_test.rb +++ b/activesupport/test/xml_mini/jdom_engine_test.rb @@ -178,7 +178,7 @@ if RUBY_PLATFORM =~ /java/ private def assert_equal_rexml(xml) parsed_xml = XmlMini.parse(xml) - hash = XmlMini.with_backend('REXML') { parsed_xml } + hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } assert_equal(hash, parsed_xml) end end diff --git a/activesupport/test/xml_mini/libxml_engine_test.rb b/activesupport/test/xml_mini/libxml_engine_test.rb index e7cb350663..a8df2e1f7b 100644 --- a/activesupport/test/xml_mini/libxml_engine_test.rb +++ b/activesupport/test/xml_mini/libxml_engine_test.rb @@ -195,7 +195,8 @@ class LibxmlEngineTest < ActiveSupport::TestCase private def assert_equal_rexml(xml) parsed_xml = XmlMini.parse(xml) - hash = XmlMini.with_backend('REXML') { parsed_xml } + xml.rewind if xml.respond_to?(:rewind) + hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } assert_equal(hash, parsed_xml) end end diff --git a/activesupport/test/xml_mini/libxmlsax_engine_test.rb b/activesupport/test/xml_mini/libxmlsax_engine_test.rb index 07485911c9..d6d90639e2 100644 --- a/activesupport/test/xml_mini/libxmlsax_engine_test.rb +++ b/activesupport/test/xml_mini/libxmlsax_engine_test.rb @@ -186,7 +186,8 @@ class LibXMLSAXEngineTest < ActiveSupport::TestCase private def assert_equal_rexml(xml) parsed_xml = XmlMini.parse(xml) - hash = XmlMini.with_backend('REXML') { parsed_xml } + xml.rewind if xml.respond_to?(:rewind) + hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } assert_equal(hash, parsed_xml) end end diff --git a/activesupport/test/xml_mini/nokogiri_engine_test.rb b/activesupport/test/xml_mini/nokogiri_engine_test.rb index 937517786e..2e962576b5 100644 --- a/activesupport/test/xml_mini/nokogiri_engine_test.rb +++ b/activesupport/test/xml_mini/nokogiri_engine_test.rb @@ -208,7 +208,8 @@ class NokogiriEngineTest < ActiveSupport::TestCase private def assert_equal_rexml(xml) parsed_xml = XmlMini.parse(xml) - hash = XmlMini.with_backend('REXML') { parsed_xml } + xml.rewind if xml.respond_to?(:rewind) + hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } assert_equal(hash, parsed_xml) end end diff --git a/activesupport/test/xml_mini/nokogirisax_engine_test.rb b/activesupport/test/xml_mini/nokogirisax_engine_test.rb index 84a5c44a87..4f078f31e0 100644 --- a/activesupport/test/xml_mini/nokogirisax_engine_test.rb +++ b/activesupport/test/xml_mini/nokogirisax_engine_test.rb @@ -209,7 +209,8 @@ class NokogiriSAXEngineTest < ActiveSupport::TestCase private def assert_equal_rexml(xml) parsed_xml = XmlMini.parse(xml) - hash = XmlMini.with_backend('REXML') { parsed_xml } + xml.rewind if xml.respond_to?(:rewind) + hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } assert_equal(hash, parsed_xml) end end diff --git a/activesupport/test/xml_mini/rexml_engine_test.rb b/activesupport/test/xml_mini/rexml_engine_test.rb index 70a3b918fd..0c1f11803c 100644 --- a/activesupport/test/xml_mini/rexml_engine_test.rb +++ b/activesupport/test/xml_mini/rexml_engine_test.rb @@ -30,7 +30,8 @@ class REXMLEngineTest < ActiveSupport::TestCase private def assert_equal_rexml(xml) parsed_xml = XmlMini.parse(xml) - hash = XmlMini.with_backend('REXML') { parsed_xml } + xml.rewind if xml.respond_to?(:rewind) + hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } assert_equal(hash, parsed_xml) end end diff --git a/ci/travis.rb b/ci/travis.rb index 9029c3f41c..7e68993332 100755 --- a/ci/travis.rb +++ b/ci/travis.rb @@ -20,7 +20,8 @@ class Build 'am' => 'actionmailer', 'amo' => 'activemodel', 'as' => 'activesupport', - 'ar' => 'activerecord' + 'ar' => 'activerecord', + 'av' => 'actionview' } attr_reader :component, :options diff --git a/guides/CHANGELOG.md b/guides/CHANGELOG.md index 766f7f6f56..37257baeba 100644 --- a/guides/CHANGELOG.md +++ b/guides/CHANGELOG.md @@ -1,3 +1,5 @@ -* No changes. +* Removed repetitive th tags. Instead of them added one th tag with a colspan attribute. + + *Sıtkı Bağdat* Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/guides/CHANGELOG.md) for previous changes. diff --git a/guides/assets/images/edge_badge.png b/guides/assets/images/edge_badge.png Binary files differindex a35dc9f8ee..a3c1843d1d 100644 --- a/guides/assets/images/edge_badge.png +++ b/guides/assets/images/edge_badge.png diff --git a/guides/assets/images/feature_tile.gif b/guides/assets/images/feature_tile.gif Binary files differindex 75469361db..5268ef8373 100644 --- a/guides/assets/images/feature_tile.gif +++ b/guides/assets/images/feature_tile.gif diff --git a/guides/assets/images/footer_tile.gif b/guides/assets/images/footer_tile.gif Binary files differindex bb33fc1ff0..3fe21a8275 100644 --- a/guides/assets/images/footer_tile.gif +++ b/guides/assets/images/footer_tile.gif diff --git a/guides/assets/images/fxn.png b/guides/assets/images/fxn.png Binary files differindex 9b531ee584..733d380cba 100644 --- a/guides/assets/images/fxn.png +++ b/guides/assets/images/fxn.png diff --git a/guides/assets/images/getting_started/challenge.png b/guides/assets/images/getting_started/challenge.png Binary files differindex 30be3d7028..4a30e49e6d 100644 --- a/guides/assets/images/getting_started/challenge.png +++ b/guides/assets/images/getting_started/challenge.png diff --git a/guides/assets/images/getting_started/forbidden_attributes_for_new_post.png b/guides/assets/images/getting_started/forbidden_attributes_for_new_post.png Binary files differindex 500dfc2c02..6c78e52173 100644 --- a/guides/assets/images/getting_started/forbidden_attributes_for_new_post.png +++ b/guides/assets/images/getting_started/forbidden_attributes_for_new_post.png diff --git a/guides/assets/images/getting_started/new_post.png b/guides/assets/images/getting_started/new_post.png Binary files differindex b573cb164c..b20b0192d4 100644 --- a/guides/assets/images/getting_started/new_post.png +++ b/guides/assets/images/getting_started/new_post.png diff --git a/guides/assets/images/getting_started/routing_error_no_controller.png b/guides/assets/images/getting_started/routing_error_no_controller.png Binary files differindex 43ccd25252..35ee4f348f 100644 --- a/guides/assets/images/getting_started/routing_error_no_controller.png +++ b/guides/assets/images/getting_started/routing_error_no_controller.png diff --git a/guides/assets/images/getting_started/routing_error_no_route_matches.png b/guides/assets/images/getting_started/routing_error_no_route_matches.png Binary files differindex 1b8c0ea57e..1cbddfa0f1 100644 --- a/guides/assets/images/getting_started/routing_error_no_route_matches.png +++ b/guides/assets/images/getting_started/routing_error_no_route_matches.png diff --git a/guides/assets/images/getting_started/template_is_missing_posts_new.png b/guides/assets/images/getting_started/template_is_missing_posts_new.png Binary files differindex 75980432b2..f03db05fb8 100644 --- a/guides/assets/images/getting_started/template_is_missing_posts_new.png +++ b/guides/assets/images/getting_started/template_is_missing_posts_new.png diff --git a/guides/assets/images/getting_started/unknown_action_create_for_posts.png b/guides/assets/images/getting_started/unknown_action_create_for_posts.png Binary files differindex d60a30465f..8fdd4c574a 100644 --- a/guides/assets/images/getting_started/unknown_action_create_for_posts.png +++ b/guides/assets/images/getting_started/unknown_action_create_for_posts.png diff --git a/guides/assets/images/getting_started/unknown_action_new_for_posts.png b/guides/assets/images/getting_started/unknown_action_new_for_posts.png Binary files differindex f4b3eff9dc..7e72feee38 100644 --- a/guides/assets/images/getting_started/unknown_action_new_for_posts.png +++ b/guides/assets/images/getting_started/unknown_action_new_for_posts.png diff --git a/guides/assets/images/header_tile.gif b/guides/assets/images/header_tile.gif Binary files differindex e2c878d492..6b1af15eab 100644 --- a/guides/assets/images/header_tile.gif +++ b/guides/assets/images/header_tile.gif diff --git a/guides/assets/images/icons/callouts/11.png b/guides/assets/images/icons/callouts/11.png Binary files differindex 9244a1ac4b..3b7b9318e7 100644 --- a/guides/assets/images/icons/callouts/11.png +++ b/guides/assets/images/icons/callouts/11.png diff --git a/guides/assets/images/icons/callouts/12.png b/guides/assets/images/icons/callouts/12.png Binary files differindex ae56459f4c..7b95925e9d 100644 --- a/guides/assets/images/icons/callouts/12.png +++ b/guides/assets/images/icons/callouts/12.png diff --git a/guides/assets/images/icons/callouts/13.png b/guides/assets/images/icons/callouts/13.png Binary files differindex 1181f9f892..4b99fe8efc 100644 --- a/guides/assets/images/icons/callouts/13.png +++ b/guides/assets/images/icons/callouts/13.png diff --git a/guides/assets/images/icons/callouts/15.png b/guides/assets/images/icons/callouts/15.png Binary files differindex 39304de94f..70e4bba615 100644 --- a/guides/assets/images/icons/callouts/15.png +++ b/guides/assets/images/icons/callouts/15.png diff --git a/guides/assets/images/icons/caution.png b/guides/assets/images/icons/caution.png Binary files differindex 031e19c776..7227b54b32 100644 --- a/guides/assets/images/icons/caution.png +++ b/guides/assets/images/icons/caution.png diff --git a/guides/assets/images/icons/example.png b/guides/assets/images/icons/example.png Binary files differindex 1b0e482059..de23c0aa87 100644 --- a/guides/assets/images/icons/example.png +++ b/guides/assets/images/icons/example.png diff --git a/guides/assets/images/jaimeiniesta.jpg b/guides/assets/images/jaimeiniesta.jpg Binary files differdeleted file mode 100644 index 445f048d92..0000000000 --- a/guides/assets/images/jaimeiniesta.jpg +++ /dev/null diff --git a/guides/assets/images/radar.png b/guides/assets/images/radar.png Binary files differindex f61e08763f..421b62b623 100644 --- a/guides/assets/images/radar.png +++ b/guides/assets/images/radar.png diff --git a/guides/assets/images/rails4_features.png b/guides/assets/images/rails4_features.png Binary files differindex a979f02207..b3bd5ef69e 100644 --- a/guides/assets/images/rails4_features.png +++ b/guides/assets/images/rails4_features.png diff --git a/guides/assets/images/rails_guides_kindle_cover.jpg b/guides/assets/images/rails_guides_kindle_cover.jpg Binary files differindex 9eb16720a9..f068bd9a04 100644 --- a/guides/assets/images/rails_guides_kindle_cover.jpg +++ b/guides/assets/images/rails_guides_kindle_cover.jpg diff --git a/guides/assets/images/vijaydev.jpg b/guides/assets/images/vijaydev.jpg Binary files differindex e21d3cabfc..fe5e4f1cb4 100644 --- a/guides/assets/images/vijaydev.jpg +++ b/guides/assets/images/vijaydev.jpg diff --git a/guides/assets/stylesheets/main.css b/guides/assets/stylesheets/main.css index dd029e6314..ca319c91cf 100644 --- a/guides/assets/stylesheets/main.css +++ b/guides/assets/stylesheets/main.css @@ -244,7 +244,7 @@ body { #subCol { position: absolute; z-index: 0; - top: 0; + top: 21px; right: 0; background: #FFF; padding: 1em 1.5em 1em 1.25em; diff --git a/guides/code/getting_started/app/views/posts/_form.html.erb b/guides/code/getting_started/app/views/posts/_form.html.erb index c9fb74af9c..f2f83585e1 100644 --- a/guides/code/getting_started/app/views/posts/_form.html.erb +++ b/guides/code/getting_started/app/views/posts/_form.html.erb @@ -1,6 +1,6 @@ <%= form_for @post do |f| %> <% if @post.errors.any? %> - <div id="errorExplanation"> + <div id="error_explanation"> <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2> <ul> @@ -14,12 +14,12 @@ <%= f.label :title %><br> <%= f.text_field :title %> </p> - + <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> - + <p> <%= f.submit %> </p> diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md index 3c08f148cf..0f05cc6b85 100644 --- a/guides/source/2_3_release_notes.md +++ b/guides/source/2_3_release_notes.md @@ -40,7 +40,7 @@ Here's a summary of the rack-related changes: * `ActiveRecord::QueryCache` middleware is automatically inserted onto the middleware stack if `ActiveRecord` has been loaded. This middleware sets up and flushes the per-request Active Record query cache. * The Rails router and controller classes follow the Rack spec. You can call a controller directly with `SomeController.call(env)`. The router stores the routing parameters in `rack.routing_args`. * `ActionController::Request` inherits from `Rack::Request`. -* Instead of `config.action_controller.session = { :session_key => 'foo', ...` use `config.action_controller.session = { :key => 'foo', ...`. +* Instead of `config.action_controller.session = { :session_key => 'foo', ...` use `config.action_controller.session = { :key => 'foo', ...`. * Using the `ParamsParser` middleware preprocesses any XML, JSON, or YAML requests so they can be read normally with any `Rack::Request` object after it. ### Renewed Support for Rails Engines @@ -173,8 +173,8 @@ before_save :update_credit_rating, :if => :active, Rails now has a `:having` option on find (as well as on `has_many` and `has_and_belongs_to_many` associations) for filtering records in grouped finds. As those with heavy SQL backgrounds know, this allows filtering based on grouped results: ```ruby -developers = Developer.find(:all, :group => "salary", - :having => "sum(salary) > 10000", :select => "salary") +developers = Developer.find(:all, :group => "salary", + :having => "sum(salary) > 10000", :select => "salary") ``` * Lead Contributor: [Emilio Tagua](http://github.com/miloops) diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md index b9dbe820c8..6ebeeed0bf 100644 --- a/guides/source/4_0_release_notes.md +++ b/guides/source/4_0_release_notes.md @@ -83,7 +83,7 @@ Please refer to the [Changelog](https://github.com/rails/rails/blob/master/railt ### Notable changes -* New test locations `test/models`, `test/helpers`, `test/controllers`, and `test/mailers`. Corresponding rake tasks added as well. ([Pull Request](https://github.com/rails/rails/pull/7878)) +* New test locations `test/models`, `test/helpers`, `test/controllers`, and `test/mailers`. Corresponding rake tasks added as well. ([Pull Request](https://github.com/rails/rails/pull/7878)) * Your app's executables now live in the `bin/` directory. Run `rake rails:update:bin` to get `bin/bundle`, `bin/rails`, and `bin/rake`. @@ -111,10 +111,9 @@ Please refer to the [Changelog](https://github.com/rails/rails/blob/master/activ ### Notable changes -* Add `ActiveModel::ForbiddenAttributesProtection`, a simple module to protect attributes from mass assignment when non-permitted attributes are passed. +* Add `ActiveModel::ForbiddenAttributesProtection`, a simple module to protect attributes from mass assignment when non-permitted attributes are passed. -* Added `ActiveModel::Model`, a mixin to make Ruby objects work with - Action Pack out of box. +* Added `ActiveModel::Model`, a mixin to make Ruby objects work with Action Pack out of box. ### Deprecations @@ -125,27 +124,27 @@ Please refer to the [Changelog](https://github.com/rails/rails/blob/master/activ ### Notable changes -* Replace deprecated `memcache-client` gem with `dalli` in ActiveSupport::Cache::MemCacheStore. +* Replace deprecated `memcache-client` gem with `dalli` in ActiveSupport::Cache::MemCacheStore. -* Optimize ActiveSupport::Cache::Entry to reduce memory and processing overhead. +* Optimize ActiveSupport::Cache::Entry to reduce memory and processing overhead. -* Inflections can now be defined per locale. `singularize` and `pluralize` accept locale as an extra argument. +* Inflections can now be defined per locale. `singularize` and `pluralize` accept locale as an extra argument. -* `Object#try` will now return nil instead of raise a NoMethodError if the receiving object does not implement the method, but you can still get the old behavior by using the new `Object#try!`. +* `Object#try` will now return nil instead of raise a NoMethodError if the receiving object does not implement the method, but you can still get the old behavior by using the new `Object#try!`. ### Deprecations -* Deprecate `ActiveSupport::TestCase#pending` method, use `skip` from MiniTest instead. +* Deprecate `ActiveSupport::TestCase#pending` method, use `skip` from MiniTest instead. -* ActiveSupport::Benchmarkable#silence has been deprecated due to its lack of thread safety. It will be removed without replacement in Rails 4.1. +* ActiveSupport::Benchmarkable#silence has been deprecated due to its lack of thread safety. It will be removed without replacement in Rails 4.1. -* `ActiveSupport::JSON::Variable` is deprecated. Define your own `#as_json` and `#encode_json` methods for custom JSON string literals. +* `ActiveSupport::JSON::Variable` is deprecated. Define your own `#as_json` and `#encode_json` methods for custom JSON string literals. -* Deprecates the compatibility method Module#local_constant_names, use Module#local_constants instead (which returns symbols). +* Deprecates the compatibility method Module#local_constant_names, use Module#local_constants instead (which returns symbols). -* BufferedLogger is deprecated. Use ActiveSupport::Logger, or the logger from Ruby standard library. +* BufferedLogger is deprecated. Use ActiveSupport::Logger, or the logger from Ruby standard library. -* Deprecate `assert_present` and `assert_blank` in favor of `assert object.blank?` and `assert object.present?` +* Deprecate `assert_present` and `assert_blank` in favor of `assert object.blank?` and `assert object.present?` Action Pack ----------- @@ -166,7 +165,7 @@ Please refer to the [Changelog](https://github.com/rails/rails/blob/master/activ ### Notable changes -* Improve ways to write `change` migrations, making the old `up` & `down` methods no longer necessary. +* Improve ways to write `change` migrations, making the old `up` & `down` methods no longer necessary. * The methods `drop_table` and `remove_column` are now reversible, as long as the necessary information is given. The method `remove_column` used to accept multiple column names; instead use `remove_columns` (which is not revertible). @@ -179,36 +178,36 @@ Please refer to the [Changelog](https://github.com/rails/rails/blob/master/activ If migrating down, the given migration / block is run normally. See the [Guide on Migration](https://github.com/rails/rails/blob/master/guides/source/migrations.md#reverting-previous-migrations) -* Adds PostgreSQL array type support. Any datatype can be used to create an array column, with full migration and schema dumper support. +* Adds PostgreSQL array type support. Any datatype can be used to create an array column, with full migration and schema dumper support. -* Add `Relation#load` to explicitly load the record and return `self`. +* Add `Relation#load` to explicitly load the record and return `self`. -* `Model.all` now returns an `ActiveRecord::Relation`, rather than an array of records. Use `Relation#to_a` if you really want an array. In some specific cases, this may cause breakage when upgrading. +* `Model.all` now returns an `ActiveRecord::Relation`, rather than an array of records. Use `Relation#to_a` if you really want an array. In some specific cases, this may cause breakage when upgrading. -* Added `ActiveRecord::Migration.check_pending!` that raises an error if migrations are pending. +* Added `ActiveRecord::Migration.check_pending!` that raises an error if migrations are pending. -* Added custom coders support for `ActiveRecord::Store`. Now you can set your custom coder like this: +* Added custom coders support for `ActiveRecord::Store`. Now you can set your custom coder like this: store :settings, accessors: [ :color, :homepage ], coder: JSON -* `mysql` and `mysql2` connections will set `SQL_MODE=STRICT_ALL_TABLES` by default to avoid silent data loss. This can be disabled by specifying `strict: false` in your `database.yml`. +* `mysql` and `mysql2` connections will set `SQL_MODE=STRICT_ALL_TABLES` by default to avoid silent data loss. This can be disabled by specifying `strict: false` in your `database.yml`. -* Remove IdentityMap. +* Remove IdentityMap. -* Remove automatic execution of EXPLAIN queries. The option `active_record.auto_explain_threshold_in_seconds` is no longer used and should be removed. +* Remove automatic execution of EXPLAIN queries. The option `active_record.auto_explain_threshold_in_seconds` is no longer used and should be removed. -* Adds `ActiveRecord::NullRelation` and `ActiveRecord::Relation#none` implementing the null object pattern for the Relation class. +* Adds `ActiveRecord::NullRelation` and `ActiveRecord::Relation#none` implementing the null object pattern for the Relation class. -* Added `create_join_table` migration helper to create HABTM join tables. +* Added `create_join_table` migration helper to create HABTM join tables. -* Allows PostgreSQL hstore records to be created. +* Allows PostgreSQL hstore records to be created. ### Deprecations -* Deprecated the old-style hash based finder API. This means that methods which previously accepted "finder options" no longer do. +* Deprecated the old-style hash based finder API. This means that methods which previously accepted "finder options" no longer do. -* All dynamic methods except for `find_by_...` and `find_by_...!` are deprecated. Here's - how you can rewrite the code: +* All dynamic methods except for `find_by_...` and `find_by_...!` are deprecated. Here's + how you can rewrite the code: * `find_all_by_...` can be rewritten using `where(...)`. * `find_last_by_...` can be rewritten using `where(...).last`. diff --git a/guides/source/_welcome.html.erb b/guides/source/_welcome.html.erb index a50961a0c7..9210c40c17 100644 --- a/guides/source/_welcome.html.erb +++ b/guides/source/_welcome.html.erb @@ -10,10 +10,13 @@ </p> <% else %> <p> - These are the new guides for Rails 3.2 based on <a href="https://github.com/rails/rails/tree/<%= @version %>"><%= @version %></a>. + These are the new guides for Rails 4.0 based on <a href="https://github.com/rails/rails/tree/<%= @version %>"><%= @version %></a>. These guides are designed to make you immediately productive with Rails, and to help you understand how all of the pieces fit together. </p> <% end %> <p> + The guides for Rails 3.2.x are available at <a href="http://guides.rubyonrails.org/v3.2.13/">http://guides.rubyonrails.org/v3.2.13/</a>. +</p> +<p> The guides for Rails 2.3.x are available at <a href="http://guides.rubyonrails.org/v2.3.11/">http://guides.rubyonrails.org/v2.3.11/</a>. </p> diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index 28939f307f..2701f5bb72 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -257,7 +257,7 @@ params.require(:log_entry).permit! ``` This will mark the `:log_entry` parameters hash and any subhash of it -permitted. Extreme care should be taken when using `permit!` as it +permitted. Extreme care should be taken when using `permit!` as it will allow all current and future model attributes to be mass-assigned. diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md index c351339117..d1dd231cf6 100644 --- a/guides/source/action_mailer_basics.md +++ b/guides/source/action_mailer_basics.md @@ -496,7 +496,7 @@ end There may be cases in which you want to skip the template rendering step and supply the email body as a string. You can achieve this using the `:body` -option. In such cases don't forget to add the `:content_type` option. Rails +option. In such cases don't forget to add the `:content_type` option. Rails will default to `text/plain` otherwise. ```ruby @@ -623,7 +623,7 @@ files (environment.rb, production.rb, etc...) | Configuration | Description | |---------------|-------------| |`logger`|Generates information on the mailing run if available. Can be set to `nil` for no logging. Compatible with both Ruby's own `Logger` and `Log4r` loggers.| -|`smtp_settings`|Allows detailed configuration for `:smtp` delivery method:<ul><li>`:address` - Allows you to use a remote mail server. Just change it from its default "localhost" setting.</li><li>`:port` - On the off chance that your mail server doesn't run on port 25, you can change it.</li><li>`:domain` - If you need to specify a HELO domain, you can do it here.</li><li>`:user_name` - If your mail server requires authentication, set the username in this setting.</li><li>`:password` - If your mail server requires authentication, set the password in this setting.</li><li>`:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain`, `:login`, `:cram_md5`.</li><li>`:enable_starttls_auto` - Set this to `false` if there is a problem with your server certificate that you cannot resolve.</li></ul>| +|`smtp_settings`|Allows detailed configuration for `:smtp` delivery method:<ul><li>`:address` - Allows you to use a remote mail server. Just change it from its default "localhost" setting.</li><li>`:port` - On the off chance that your mail server doesn't run on port 25, you can change it.</li><li>`:domain` - If you need to specify a HELO domain, you can do it here.</li><li>`:user_name` - If your mail server requires authentication, set the username in this setting.</li><li>`:password` - If your mail server requires authentication, set the password in this setting.</li><li>`:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain`, `:login`, `:cram_md5`.</li><li>`:enable_starttls_auto` - Set this to `false` if there is a problem with your server certificate that you cannot resolve.</li></ul>| |`sendmail_settings`|Allows you to override options for the `:sendmail` delivery method.<ul><li>`:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`.</li><li>`:arguments` - The command line arguments to be passed to sendmail. Defaults to `-i -t`.</li></ul>| |`raise_delivery_errors`|Whether or not errors should be raised if the email fails to be delivered. This only works if the external email server is configured for immediate delivery.| |`delivery_method`|Defines a delivery method. Possible values are `:smtp` (default), `:sendmail`, `:file` and `:test`.| @@ -649,7 +649,7 @@ config.action_mailer.delivery_method = :sendmail # } config.action_mailer.perform_deliveries = true config.action_mailer.raise_delivery_errors = true -config.action_mailer.default_options = {from: 'no-replay@example.com'} +config.action_mailer.default_options = {from: 'no-reply@example.com'} ``` ### Action Mailer Configuration for Gmail diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md index dea1ddef71..187c910e37 100644 --- a/guides/source/action_view_overview.md +++ b/guides/source/action_view_overview.md @@ -1090,7 +1090,7 @@ Example object structure for use with this method: ```ruby class Post < ActiveRecord::Base - has_and_belongs_to_many :author + has_and_belongs_to_many :authors end class Author < ActiveRecord::Base diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md index fc8fac4651..1f25c6ae95 100644 --- a/guides/source/active_record_basics.md +++ b/guides/source/active_record_basics.md @@ -62,9 +62,9 @@ may be necessary to write a lot of configuration code. This is particularly true for ORM frameworks in general. However, if you follow the conventions adopted by Rails, you'll need to write very little configuration (in some case no configuration at all) when creating Active Record models. The idea is that if -you configure your applications in the very same way most of the times then this -should be the default way. In this cases, explicit configuration would be needed -only in those cases where you can't follow the conventions for any reason. +you configure your applications in the very same way most of the time then this +should be the default way. Thus, explicit configuration would be needed +only in those cases where you can't follow the standard convention. ### Naming Conventions diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index c4d69908ed..2555927d15 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -91,7 +91,7 @@ The primary operation of `Model.find(options)` can be summarized as: ### Retrieving a Single Object -Active Record provides five different ways of retrieving a single object. +Active Record provides several different ways of retrieving a single object. #### Using a Primary Key @@ -687,6 +687,10 @@ The SQL that would be executed: ```sql SELECT * FROM posts WHERE id > 10 LIMIT 20 + +# Original query without `except` +SELECT * FROM posts WHERE id > 10 ORDER BY id asc LIMIT 20 + ``` ### `unscope` @@ -722,6 +726,10 @@ The SQL that would be executed: ```sql SELECT * FROM posts WHERE id > 10 ORDER BY id DESC + +# Original query without `only` +SELECT "posts".* FROM "posts" WHERE (id > 10) ORDER BY id desc LIMIT 20 + ``` ### `reorder` @@ -1230,7 +1238,7 @@ One important caveat is that `default_scope` will be overridden by ```ruby class User < ActiveRecord::Base - default_scope { where state: 'pending' } + default_scope { where state: 'pending' } scope :active, -> { where state: 'active' } scope :inactive, -> { where state: 'inactive' } end diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md index 621d2222ff..37790c62b1 100644 --- a/guides/source/active_record_validations.md +++ b/guides/source/active_record_validations.md @@ -243,7 +243,7 @@ line of code you can add the same kind of validation to several attributes. All of them accept the `:on` and `:message` options, which define when the validation should be run and what message should be added to the `errors` collection if it fails, respectively. The `:on` option takes one of the values -`:save` (the default), `:create` or `:update`. There is a default error +`:save` (the default), `:create` or `:update`. There is a default error message for each one of the validation helpers. These messages are used when the `:message` option isn't specified. Let's take a look at each one of the available helpers. @@ -357,7 +357,7 @@ given regular expression, which is specified using the `:with` option. ```ruby class Product < ActiveRecord::Base validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/, - message: "Only letters allowed" } + message: "only allows letters" } end ``` @@ -677,13 +677,13 @@ class GoodnessValidator def initialize(person) @person = person end - + def validate if some_complex_condition_involving_ivars_and_private_methods? @person.errors[:base] << "This person is evil" end end - + # … end ``` @@ -736,8 +736,8 @@ class Topic < ActiveRecord::Base validates :title, length: { is: 5 }, allow_blank: true end -Topic.create("title" => "").valid? # => true -Topic.create("title" => nil).valid? # => true +Topic.create(title: "").valid? # => true +Topic.create(title: nil).valid? # => true ``` ### `:message` diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index c012ded888..7f65d920df 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -418,6 +418,14 @@ TIP: Since `with_options` forwards calls to its receiver they can be nested. Eac NOTE: Defined in `active_support/core_ext/object/with_options.rb`. +### JSON support + +Active Support provides a better implemention of `to_json` than the +json+ gem ordinarily provides for Ruby objects. This is because some classes, like +Hash+ and +OrderedHash+ needs special handling in order to provide a proper JSON representation. + +Active Support also provides an implementation of `as_json` for the <tt>Process::Status</tt> class. + +NOTE: Defined in `active_support/core_ext/object/to_json.rb`. + ### Instance Variables Active Support provides several methods to ease access to instance variables. @@ -439,6 +447,22 @@ C.new(0, 1).instance_values # => {"x" => 0, "y" => 1} NOTE: Defined in `active_support/core_ext/object/instance_variables.rb`. +#### `instance_variable_names` + +The method `instance_variable_names` returns an array. Each name includes the "@" sign. + +```ruby +class C + def initialize(x, y) + @x, @y = x, y + end +end + +C.new(0, 1).instance_variable_names # => ["@x", "@y"] +``` + +NOTE: Defined in `active_support/core_ext/object/instance_variables.rb`. + ### Silencing Warnings, Streams, and Exceptions The methods `silence_warnings` and `enable_warnings` change the value of `$VERBOSE` accordingly for the duration of their block, and reset it afterwards: @@ -1038,7 +1062,7 @@ For convenience `class_attribute` also defines an instance predicate which is th When `:instance_reader` is `false`, the instance predicate returns a `NoMethodError` just like the reader method. -If you do not want the instance predicate, pass `instance_predicate: false` and it will not be defined. +If you do not want the instance predicate, pass `instance_predicate: false` and it will not be defined. NOTE: Defined in `active_support/core_ext/class/attribute.rb` @@ -1423,7 +1447,7 @@ The method `pluralize` returns the plural of its receiver: As the previous example shows, Active Support knows some irregular plurals and uncountable nouns. Built-in rules can be extended in `config/initializers/inflections.rb`. That file is generated by the `rails` command and has instructions in comments. -`pluralize` can also take an optional `count` parameter. If `count == 1` the singular form will be returned. For any other value of `count` the plural form will be returned: +`pluralize` can also take an optional `count` parameter. If `count == 1` the singular form will be returned. For any other value of `count` the plural form will be returned: ```ruby "dude".pluralize(0) # => "dudes" @@ -2011,8 +2035,33 @@ NOTE: Defined in `active_support/core_ext/integer/inflections.rb`. Extensions to `BigDecimal` -------------------------- +### `to_s` -... +The method `to_s` is aliased to `to_formatted_s`. This provides a convenient way to display a BigDecimal value in floating-point notation: + +```ruby +BigDecimal.new(5.00, 6).to_s # => "5.0" +``` + +### `to_formatted_s` + +Te method `to_formatted_s` provides a default specifier of "F". This means that a simple call to `to_formatted_s` or `to_s` will result in floating point representation instead of engineering notation: + +```ruby +BigDecimal.new(5.00, 6).to_formatted_s # => "5.0" +``` + +and that symbol specifiers are also supported: + +```ruby +BigDecimal.new(5.00, 6).to_formatted_s(:db) # => "5.0" +``` + +Engineering notation is still supported: + +```ruby +BigDecimal.new(5.00, 6).to_formatted_s("e") # => "0.5E1" +``` Extensions to `Enumerable` -------------------------- diff --git a/guides/source/api_documentation_guidelines.md b/guides/source/api_documentation_guidelines.md index d0499878da..7e056d970c 100644 --- a/guides/source/api_documentation_guidelines.md +++ b/guides/source/api_documentation_guidelines.md @@ -25,7 +25,7 @@ Write in present tense: "Returns a hash that...", rather than "Returned a hash t Start comments in upper case. Follow regular punctuation rules: ```ruby -# Declares an attribute reader backed by an internally-named +# Declares an attribute reader backed by an internally-named # instance variable. def attr_internal_reader(*attrs) ... @@ -57,7 +57,7 @@ Use two spaces to indent chunks of code--that is, for markup purposes, two space Short docs do not need an explicit "Examples" label to introduce snippets; they just follow paragraphs: ```ruby -# Converts a collection of elements into a formatted string by +# Converts a collection of elements into a formatted string by # calling +to_s+ on all elements and joining them. # # Blog.all.to_formatted_s # => "First PostSecond PostThird Post" @@ -141,7 +141,7 @@ class Array end ``` -WARNING: Using a pair of `+...+` for fixed-width font only works with **words**; that is: anything matching `\A\w+\z`. For anything else use `<tt>...</tt>`, notably symbols, setters, inline snippets, etc. +WARNING: Using a pair of `+...+` for fixed-width font only works with **words**; that is: anything matching `\A\w+\z`. For anything else use `<tt>...</tt>`, notably symbols, setters, inline snippets, etc. ### Regular Font diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index 3b3707d9e5..b68c24acfd 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -419,17 +419,6 @@ The rake task is: $ RAILS_ENV=production bundle exec rake assets:precompile ``` -For faster asset precompiles, you can partially load your application by setting -`config.assets.initialize_on_precompile` to false in `config/application.rb`, though in that case templates -cannot see application objects or methods. **Heroku requires this to be false.** - -WARNING: If you set `config.assets.initialize_on_precompile` to false, be sure to -test `rake assets:precompile` locally before deploying. It may expose bugs where -your assets reference application objects or methods, since those are still -in scope in development mode regardless of the value of this flag. Changing this flag also affects -engines. Engines can define assets for precompilation as well. Since the complete environment is not loaded, -engines (or other gems) will not be loaded, which can cause missing assets. - Capistrano (v2.15.1 and above) includes a recipe to handle this in deployment. Add the following line to `Capfile`: ```ruby @@ -570,16 +559,8 @@ In `config/environments/development.rb`, place the following line: config.assets.prefix = "/dev-assets" ``` -You will also need this in application.rb: - -```ruby -config.assets.initialize_on_precompile = false -``` - The `prefix` change makes Rails use a different URL for serving assets in development mode, and pass all requests to Sprockets. The prefix is still set to `/assets` in the production environment. Without this change, the application would serve the precompiled assets from `public/assets` in development, and you would not see any local changes until you compile assets again. -The `initialize_on_precompile` change tells the precompile task to run without invoking Rails. This is because the precompile task runs in production mode by default, and will attempt to connect to your specified production database. Please note that you cannot have code in pipeline files that relies on Rails resources (such as the database) when compiling locally with this option. - You will also need to ensure that any compressors or minifiers are available on your development system. In practice, this will allow you to precompile locally, have those files in your working tree, and commit those files to source control when needed. Development mode will work as expected. diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index 16a5241319..d7277b487f 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -721,6 +721,7 @@ When you declare a `belongs_to` association, the declaring class automatically g * `association=(associate)` * `build_association(attributes = {})` * `create_association(attributes = {})` +* `create_association!(attributes = {})` In all of these methods, `association` is replaced with the symbol passed as the first argument to `belongs_to`. For example, given the declaration: @@ -737,6 +738,7 @@ customer customer= build_customer create_customer +create_customer! ``` NOTE: When initializing a new `has_one` or `belongs_to` association you must use the `build_` prefix to build the association, rather than the `association.build` method that would be used for `has_many` or `has_and_belongs_to_many` associations. To create one, use the `create_` prefix. @@ -777,6 +779,10 @@ The `create_association` method returns a new object of the associated type. Thi customer_name: "John Doe") ``` +##### `create_association!(attributes = {})` + +Does the same as <tt>create_association</tt> above, but raises <tt>ActiveRecord::RecordInvalid</tt> if the record is invalid. + #### Options for `belongs_to` @@ -1019,6 +1025,7 @@ When you declare a `has_one` association, the declaring class automatically gain * `association=(associate)` * `build_association(attributes = {})` * `create_association(attributes = {})` +* `create_association!(attributes = {})` In all of these methods, `association` is replaced with the symbol passed as the first argument to `has_one`. For example, given the declaration: @@ -1035,6 +1042,7 @@ account account= build_account create_account +create_account! ``` NOTE: When initializing a new `has_one` or `belongs_to` association you must use the `build_` prefix to build the association, rather than the `association.build` method that would be used for `has_many` or `has_and_belongs_to_many` associations. To create one, use the `create_` prefix. @@ -1073,6 +1081,10 @@ The `create_association` method returns a new object of the associated type. Thi @account = @supplier.create_account(terms: "Net 30") ``` +##### `create_association!(attributes = {})` + +Does the same as <tt>create_association</tt> above, but raises <tt>ActiveRecord::RecordInvalid</tt> if the record is invalid. + #### Options for `has_one` While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the `has_one` association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this association uses two such options: @@ -1285,6 +1297,7 @@ When you declare a `has_many` association, the declaring class automatically gai * `collection.exists?(...)` * `collection.build(attributes = {}, ...)` * `collection.create(attributes = {})` +* `collection.create!(attributes = {})` In all of these methods, `collection` is replaced with the symbol passed as the first argument to `has_many`, and `collection_singular` is replaced with the singularized version of that symbol. For example, given the declaration: @@ -1312,6 +1325,7 @@ orders.where(...) orders.exists?(...) orders.build(attributes = {}, ...) orders.create(attributes = {}) +orders.create!(attributes = {}) ``` ##### `collection(force_reload = false)` @@ -1427,6 +1441,10 @@ The `collection.create` method returns a new object of the associated type. This order_number: "A12345") ``` +##### `collection.create!(attributes = {})` + +Does the same as <tt>collection.create</tt> above, but raises <tt>ActiveRecord::RecordInvalid</tt> if the record is invalid. + #### Options for `has_many` While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the `has_many` association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this association uses two such options: @@ -1511,6 +1529,20 @@ end By convention, Rails assumes that the column used to hold the primary key of the association is `id`. You can override this and explicitly specify the primary key with the `:primary_key` option. +Let's say that `users` table has `id` as the primary_key but it also has +`guid` column. And the requirement is that `todos` table should hold +`guid` column value and not `id` value. This can be achieved like this + +```ruby +class User < ActiveRecord::Base + has_many :todos, primary_key: :guid +end +``` + +Now if we execute `@user.todos.create` then `@todo` record will have +`user_id` value as the `guid` value of `@user`. + + ##### `:source` The `:source` option specifies the source association name for a `has_many :through` association. You only need to use this option if the name of the source association cannot be automatically inferred from the association name. @@ -1678,7 +1710,7 @@ person.posts.inspect # => [#<Post id: 5, name: "a1">, #<Post id: 5, name: "a1">] Reading.all.inspect # => [#<Reading id: 12, person_id: 5, post_id: 5>, #<Reading id: 13, person_id: 5, post_id: 5>] ``` -In the above case there are two readings and `person.posts` brings out both of +In the above case there are two readings and `person.posts` brings out both of them even though these records are pointing to the same post. Now let's set `distinct`: @@ -1697,24 +1729,24 @@ person.posts.inspect # => [#<Post id: 7, name: "a1">] Reading.all.inspect # => [#<Reading id: 16, person_id: 7, post_id: 7>, #<Reading id: 17, person_id: 7, post_id: 7>] ``` -In the above case there are still two readings. However `person.posts` shows +In the above case there are still two readings. However `person.posts` shows only one post because the collection loads only unique records. -If you want to make sure that, upon insertion, all of the records in the -persisted association are distinct (so that you can be sure that when you -inspect the association that you will never find duplicate records), you should -add a unique index on the table itself. For example, if you have a table named -``person_posts`` and you want to make sure all the posts are unique, you could +If you want to make sure that, upon insertion, all of the records in the +persisted association are distinct (so that you can be sure that when you +inspect the association that you will never find duplicate records), you should +add a unique index on the table itself. For example, if you have a table named +``person_posts`` and you want to make sure all the posts are unique, you could add the following in a migration: ```ruby add_index :person_posts, :post, :unique => true ``` -Note that checking for uniqueness using something like ``include?`` is subject -to race conditions. Do not attempt to use ``include?`` to enforce distinctness -in an association. For instance, using the post example from above, the -following code would be racy because multiple users could be attempting this +Note that checking for uniqueness using something like ``include?`` is subject +to race conditions. Do not attempt to use ``include?`` to enforce distinctness +in an association. For instance, using the post example from above, the +following code would be racy because multiple users could be attempting this at the same time: ```ruby @@ -1754,6 +1786,7 @@ When you declare a `has_and_belongs_to_many` association, the declaring class au * `collection.exists?(...)` * `collection.build(attributes = {})` * `collection.create(attributes = {})` +* `collection.create!(attributes = {})` In all of these methods, `collection` is replaced with the symbol passed as the first argument to `has_and_belongs_to_many`, and `collection_singular` is replaced with the singularized version of that symbol. For example, given the declaration: @@ -1781,6 +1814,7 @@ assemblies.where(...) assemblies.exists?(...) assemblies.build(attributes = {}, ...) assemblies.create(attributes = {}) +assemblies.create!(attributes = {}) ``` ##### Additional Column Methods @@ -1900,6 +1934,10 @@ The `collection.create` method returns a new object of the associated type. This @assembly = @part.assemblies.create({assembly_name: "Transmission housing"}) ``` +##### `collection.create!(attributes = {})` + +Does the same as <tt>collection.create</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt> if the record is invalid. + #### Options for `has_and_belongs_to_many` While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the `has_and_belongs_to_many` association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this association uses two such options: @@ -1928,7 +1966,7 @@ TIP: The `:foreign_key` and `:association_foreign_key` options are useful when s ```ruby class User < ActiveRecord::Base - has_and_belongs_to_many :friends, + has_and_belongs_to_many :friends, class_name: "User", foreign_key: "this_user_id", association_foreign_key: "other_user_id" @@ -2161,4 +2199,4 @@ Extensions can refer to the internals of the association proxy using these three * `proxy_association.owner` returns the object that the association is a part of. * `proxy_association.reflection` returns the reflection object that describes the association. -* `proxy_association.target` returns the associated object for `belongs_to` or `has_one`, or the collection of associated objects for `has_many` or `has_and_belongs_to_many`. +* `proxy_association.target` returns the associated object for `belongs_to` or `has_one`, or the collection of associated objects for `has_many` or `has_and_belongs_to_many`.
\ No newline at end of file diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md index 456abaf612..1e196b0e42 100644 --- a/guides/source/caching_with_rails.md +++ b/guides/source/caching_with_rails.md @@ -104,6 +104,15 @@ This method generates a cache key that depends on all products and can be used i All available products: <% end %> ``` + +If you want to cache a fragment under certain condition you can use `cache_if` or `cache_unless` + +```erb +<% cache_if (condition, cache_key_for_products) do %> + All available products: +<% end %> +``` + You can also use an Active Record model as the cache key: ```erb @@ -236,7 +245,7 @@ config.cache_store = :ehcache_store When initializing the cache, you may use the `:ehcache_config` option to specify the Ehcache config file to use (where the default is "ehcache.xml" in your Rails config directory), and the :cache_name option to provide a custom name for your cache (the default is rails_cache). -In addition to the standard `:expires_in` option, the `write` method on this cache can also accept the additional `:unless_exist` option, which will cause the cache store to use Ehcache's `putIfAbsent` method instead of `put`, and therefore will not overwrite an existing entry. Additionally, the `write` method supports all of the properties exposed by the [Ehcache Element class](http://ehcache.org/apidocs/net/sf/ehcache/Element.html) , including: +In addition to the standard `:expires_in` option, the `write` method on this cache can also accept the additional `:unless_exist` option, which will cause the cache store to use Ehcache's `putIfAbsent` method instead of `put`, and therefore will not overwrite an existing entry. Additionally, the `write` method supports all of the properties exposed by the [Ehcache Element class](http://ehcache.org/apidocs/net/sf/ehcache/Element.html) , including: | Property | Argument Type | Description | | --------------------------- | ------------------- | ----------------------------------------------------------- | diff --git a/guides/source/command_line.md b/guides/source/command_line.md index e0b44bbf93..e00e70576f 100644 --- a/guides/source/command_line.md +++ b/guides/source/command_line.md @@ -64,7 +64,7 @@ With no further work, `rails server` will run our new shiny Rails app: $ cd commandsapp $ rails server => Booting WEBrick -=> Rails 3.2.3 application starting in development on http://0.0.0.0:3000 +=> Rails 4.0.0 application starting in development on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server [2012-05-28 00:39:41] INFO WEBrick 1.3.1 @@ -289,7 +289,7 @@ If you wish to test out some code without changing any data, you can do that by ```bash $ rails console --sandbox -Loading development environment in sandbox (Rails 3.2.3) +Loading development environment in sandbox (Rails 4.0.0) Any modifications you make will be rolled back on exit irb(main):001:0> ``` diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 9e40165d15..9bb5d621fc 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -30,10 +30,10 @@ Configuring Rails Components In general, the work of configuring Rails means configuring the components of Rails, as well as configuring Rails itself. The configuration file `config/application.rb` and environment-specific configuration files (such as `config/environments/production.rb`) allow you to specify the various settings that you want to pass down to all of the components. -For example, the default `config/application.rb` file includes this setting: +For example, the `config/application.rb` file includes this setting: ```ruby -config.filter_parameters += [:password] +config.autoload_paths += %W(#{config.root}/extras) ``` This is a setting for Rails itself. If you want to pass settings to individual Rails components, you can do so via the same `config` object in `config/application.rb`: @@ -97,7 +97,9 @@ These configuration methods are to be called on a `Rails::Railtie` object, such * `config.file_watcher` the class used to detect file updates in the filesystem when `config.reload_classes_only_on_change` is true. Must conform to `ActiveSupport::FileUpdateChecker` API. -* `config.filter_parameters` used for filtering out the parameters that you don't want shown in the logs, such as passwords or credit card numbers. +* `config.filter_parameters` used for filtering out the parameters that +you don't want shown in the logs, such as passwords or credit card +numbers. New applications filter out passwords by adding the following `config.filter_parameters+=[:password]` in `config/initializers/filter_parameter_logging.rb`. * `config.force_ssl` forces all requests to be under HTTPS protocol by using `ActionDispatch::SSL` middleware. @@ -131,7 +133,8 @@ These configuration methods are to be called on a `Rails::Railtie` object, such ### Configuring Assets -* `config.assets.enabled` a flag that controls whether the asset pipeline is enabled. It is explicitly initialized in `config/application.rb`. +* `config.assets.enabled` a flag that controls whether the asset +pipeline is enabled. It is set to true by default. * `config.assets.compress` a flag that enables the compression of compiled assets. It is explicitly set to true in `config/production.rb`. @@ -193,7 +196,7 @@ Every Rails application comes with a standard set of middleware which it uses in * `Rack::Lock` wraps the app in mutex so it can only be called by a single thread at a time. Only enabled when `config.cache_classes` is `false`. * `ActiveSupport::Cache::Strategy::LocalCache` serves as a basic memory backed cache. This cache is not thread safe and is intended only for serving as a temporary memory cache for a single thread. * `Rack::Runtime` sets an `X-Runtime` header, containing the time (in seconds) taken to execute the request. -* `Rails::Rack::Logger` notifies the logs that the request has began. After request is complete, flushes all the logs. +* `Rails::Rack::Logger` notifies the logs that the request has begun. After request is complete, flushes all the logs. * `ActionDispatch::ShowExceptions` rescues any exception returned by the application and renders nice exception pages if the request is local or if `config.consider_all_requests_local` is set to `true`. If `config.action_dispatch.show_exceptions` is set to `false`, exceptions will be raised regardless. * `ActionDispatch::RequestId` makes a unique X-Request-Id header available to the response and enables the `ActionDispatch::Request#uuid` method. * `ActionDispatch::RemoteIp` checks for IP spoofing attacks and gets valid `client_ip` from request headers. Configurable with the `config.action_dispatch.ip_spoofing_check`, and `config.action_dispatch.trusted_proxies` options. @@ -421,13 +424,13 @@ There are a few configuration options available in Active Support: ### Configuring a Database -Just about every Rails application will interact with a database. The database to use is specified in a configuration file called `config/database.yml`. If you open this file in a new Rails application, you'll see a default database configured to use SQLite3. The file contains sections for three different environments in which Rails can run by default: +Just about every Rails application will interact with a database. The database to use is specified in a configuration file called `config/database.yml`. If you open this file in a new Rails application, you'll see a default database configured to use SQLite3. The file contains sections for three different environments in which Rails can run by default: * The `development` environment is used on your development/local computer as you interact manually with the application. * The `test` environment is used when running automated tests. * The `production` environment is used when you deploy your application for the world to use. -TIP: You don't have to update the database configurations manually. If you look at the options of the application generator, you will see that one of the options is named `--database`. This option allows you to choose an adapter from a list of the most used relational databases. You can even run the generator repeatedly: `cd .. && rails new blog --database=mysql`. When you confirm the overwriting of the `config/database.yml` file, your application will be configured for MySQL instead of SQLite. Detailed examples of the common database connections are below. +TIP: You don't have to update the database configurations manually. If you look at the options of the application generator, you will see that one of the options is named `--database`. This option allows you to choose an adapter from a list of the most used relational databases. You can even run the generator repeatedly: `cd .. && rails new blog --database=mysql`. When you confirm the overwriting of the `config/database.yml` file, your application will be configured for MySQL instead of SQLite. Detailed examples of the common database connections are below. #### Configuring an SQLite3 Database @@ -527,7 +530,7 @@ By default Rails ships with three environments: "development", "test", and "prod Imagine you have a server which mirrors the production environment but is only used for testing. Such a server is commonly called a "staging server". To define an environment called "staging" for this server just by create a file called `config/environments/staging.rb`. Please use the contents of any existing file in `config/environments` as a starting point and make the necessary changes from there. -That environment is no different than the default ones, start a server with `rails server -e staging`, a console with `rails console staging`, `Rails.env.staging?` works, etc. +That environment is no different than the default ones, start a server with `rails server -e staging`, a console with `rails console staging`, `Rails.env.staging?` works, etc. Rails Environment Settings @@ -600,7 +603,7 @@ end The `initializer` method takes three arguments with the first being the name for the initializer and the second being an options hash (not shown here) and the third being a block. The `:before` key in the options hash can be specified to specify which initializer this new initializer must run before, and the `:after` key will specify which initializer to run this initializer _after_. -Initializers defined using the `initializer` method will be ran in the order they are defined in, with the exception of ones that use the `:before` or `:after` methods. +Initializers defined using the `initializer` method will be run in the order they are defined in, with the exception of ones that use the `:before` or `:after` methods. WARNING: You may put your initializer before or after any other initializer in the chain, as long as it is logical. Say you have 4 initializers called "one" through "four" (defined in that order) and you define "four" to go _before_ "four" but _after_ "three", that just isn't logical and Rails will not be able to determine your initializer order. @@ -702,7 +705,7 @@ Below is a comprehensive list of all the initializers found in Rails in the orde * `ensure_autoload_once_paths_as_subset` Ensures that the `config.autoload_once_paths` only contains paths from `config.autoload_paths`. If it contains extra paths, then an exception will be raised. -* `add_to_prepare_blocks` The block for every `config.to_prepare` call in the application, a railtie or engine is added to the `to_prepare` callbacks for Action Dispatch which will be ran per request in development, or before the first request in production. +* `add_to_prepare_blocks` The block for every `config.to_prepare` call in the application, a railtie or engine is added to the `to_prepare` callbacks for Action Dispatch which will be run per request in development, or before the first request in production. * `add_builtin_route` If the application is running under the development environment then this will append the route for `rails/info/properties` to the application routes. This route provides the detailed information such as Rails and Ruby version for `public/index.html` in a default Rails application. diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index 0be9bb1ced..0bfa646b81 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -182,9 +182,9 @@ Contributing to the Rails Documentation Ruby on Rails has two main sets of documentation: the guides help you in learning about Ruby on Rails, and the API is a reference. -You can help improve the Rails guides by making them more coherent, consistent or readable, adding missing information, correcting factual errors, fixing typos, or bringing it up to date with the latest edge Rails. To get involved in the translation of Rails guides, please see [Translating Rails Guides](https://wiki.github.com/lifo/docrails/translating-rails-guides). +You can help improve the Rails guides by making them more coherent, consistent or readable, adding missing information, correcting factual errors, fixing typos, or bringing it up to date with the latest edge Rails. To get involved in the translation of Rails guides, please see [Translating Rails Guides](https://wiki.github.com/rails/docrails/translating-rails-guides). -If you're confident about your changes, you can push them directly yourself via [docrails](https://github.com/lifo/docrails). Docrails is a branch with an **open commit policy** and public write access. Commits to docrails are still reviewed, but this happens after they are pushed. Docrails is merged with master regularly, so you are effectively editing the Ruby on Rails documentation. +If you're confident about your changes, you can push them directly yourself via [docrails](https://github.com/rails/docrails). Docrails is a branch with an **open commit policy** and public write access. Commits to docrails are still reviewed, but this happens after they are pushed. Docrails is merged with master regularly, so you are effectively editing the Ruby on Rails documentation. If you are unsure of the documentation changes, you can create an issue in the [Rails](https://github.com/rails/rails/issues) issues tracker on GitHub. diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md index 70055c1d7d..0860e3119d 100644 --- a/guides/source/debugging_rails_applications.md +++ b/guides/source/debugging_rails_applications.md @@ -248,7 +248,7 @@ Make sure you have started your web server with the option `--debugger`: ```bash $ rails server --debugger => Booting WEBrick -=> Rails 3.2.13 application starting on http://0.0.0.0:3000 +=> Rails 4.0.0 application starting on http://0.0.0.0:3000 => Debugger enabled ... ``` @@ -504,7 +504,7 @@ TIP: You can use the debugger while using `rails console`. Just remember to `req ``` $ rails console -Loading development environment (Rails 3.2.13) +Loading development environment (Rails 4.0.0) >> require "debugger" => [] >> author = Author.first diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md index a4dab39d55..7f37a298b1 100644 --- a/guides/source/form_helpers.md +++ b/guides/source/form_helpers.md @@ -568,7 +568,7 @@ NOTE: In many cases the built-in date pickers are clumsy as they do not aid the ### Individual Components -Occasionally you need to display just a single date component such as a year or a month. Rails provides a series of helpers for this, one for each component `select_year`, `select_month`, `select_day`, `select_hour`, `select_minute`, `select_second`. These helpers are fairly straightforward. By default they will generate an input field named after the time component (for example "year" for `select_year`, "month" for `select_month` etc.) although this can be overridden with the `:field_name` option. The `:prefix` option works in the same way that it does for `select_date` and `select_time` and has the same default value. +Occasionally you need to display just a single date component such as a year or a month. Rails provides a series of helpers for this, one for each component `select_year`, `select_month`, `select_day`, `select_hour`, `select_minute`, `select_second`. These helpers are fairly straightforward. By default they will generate an input field named after the time component (for example "year" for `select_year`, "month" for `select_month` etc.) although this can be overridden with the `:field_name` option. The `:prefix` option works in the same way that it does for `select_date` and `select_time` and has the same default value. The first parameter specifies which value should be selected and can either be an instance of a Date, Time or DateTime, in which case the relevant component will be extracted, or a numerical value. For example @@ -830,7 +830,7 @@ Many apps grow beyond simple forms editing a single object. For example when cre ### Configuring the Model -Active Record provides model level support via the `accepts_nested_attributes_for` method: +Active Record provides model level support via the `accepts_nested_attributes_for` method: ```ruby class Person < ActiveRecord::Base @@ -885,7 +885,7 @@ end :name => 'John Doe', :addresses_attributes => { '0' => { - :kind => 'Home', + :kind => 'Home', :street => '221b Baker Street', }, '1' => { @@ -973,4 +973,4 @@ As a convenience you can instead pass the symbol `:all_blank` which will create ### Adding Fields on the Fly -Rather than rendering multiple sets of fields ahead of time you may wish to add them only when a user clicks on an 'Add new child' button. Rails does not provide any builtin support for this. When generating new sets of fields you must ensure the the key of the associated array is unique - the current javascript date (milliseconds after the epoch) is a common choice. +Rather than rendering multiple sets of fields ahead of time you may wish to add them only when a user clicks on an 'Add new child' button. Rails does not provide any builtin support for this. When generating new sets of fields you must ensure the key of the associated array is unique - the current javascript date (milliseconds after the epoch) is a common choice. diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 599e47949d..a773519bba 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -64,7 +64,7 @@ Creating a New Rails Project The best way to use this guide is to follow each step as it happens, no code or step needed to make this example application has been left out, so you can literally follow along step by step. You can get the complete code -[here](https://github.com/lifo/docrails/tree/master/guides/code/getting_started). +[here](https://github.com/rails/docrails/tree/master/guides/code/getting_started). By following along with this guide, you'll create a Rails project called `blog`, a @@ -135,7 +135,7 @@ application. Most of the work in this tutorial will happen in the `app/` folder, | ----------- | ------- | |app/|Contains the controllers, models, views, helpers, mailers and assets for your application. You'll focus on this folder for the remainder of this guide.| |bin/|Contains the rails script that starts your app and can contain other scripts you use to deploy or run your application.| -|config/|Configure your application's runtime rules, routes, database, and more. This is covered in more detail in [Configuring Rails Applications](configuring.html)| +|config/|Configure your application's runtime rules, routes, database, and more. This is covered in more detail in [Configuring Rails Applications](configuring.html)| |config.ru|Rack configuration for Rack based servers used to start the application.| |db/|Contains your current database schema, as well as the database migrations.| |Gemfile<br />Gemfile.lock|These files allow you to specify what gem dependencies are needed for your Rails application. These files are used by the Bundler gem. For more information about Bundler, see [the Bundler website](http://gembundler.com) | @@ -264,7 +264,7 @@ Blog::Application.routes.draw do end ``` -If you run `rake routes`, you'll see that all the routes for the +If you run `rake routes`, you'll see that all the routes for the standard RESTful actions. ```bash @@ -288,7 +288,7 @@ It will look a little basic for now, but that's ok. We'll look at improving the ### Laying down the ground work -The first thing that you are going to need to create a new post within the application is a place to do that. A great place for that would be at `/posts/new`. With the route already defined, requests can now be made to `/posts/new` in the application. Navigate to <http://localhost:3000/posts/new> and you'll see a routing error: +The first thing that you are going to need to create a new post within the application is a place to do that. A great place for that would be at `/posts/new`. With the route already defined, requests can now be made to `/posts/new` in the application. Navigate to <http://localhost:3000/posts/new> and you'll see a routing error:  @@ -531,21 +531,28 @@ and change the `create` action to look like this: ```ruby def create - @post = Post.new(params[:post]) - + @post = Post.new(post_params) + @post.save - redirect_to @post + redirect_to @post end + +private + def post_params + params.require(:post).permit(:title, :text) + end ``` Here's what's going on: every Rails model can be initialized with its respective attributes, which are automatically mapped to the respective database columns. In the first line we do just that (remember that -`params[:post]` contains the attributes we're interested in). Then, +`post_params` contains the attributes we're interested in). Then, `@post.save` is responsible for saving the model in the database. Finally, we redirect the user to the `show` action, which we'll define later. +TIP: Note that `def post_params` is private. This new approach prevents an attacker from setting the model's attributes by manipulating the hash passed to the model. For more information, refer to [this blog post about Strong Parameters](http://weblog.rubyonrails.org/2012/3/21/strong-parameters/). + TIP: As we'll see later, `@post.save` returns a boolean indicating whether the model was saved or not. @@ -553,14 +560,14 @@ whether the model was saved or not. If you submit the form again now, Rails will complain about not finding the `show` action. That's not very useful though, so let's add the -`show` action before proceeding. +`show` action before proceeding. ```ruby post GET /posts/:id(.:format) posts#show ``` The special syntax `:id` tells rails that this route expects an `:id` -parameter, which in our case will be the id of the post. +parameter, which in our case will be the id of the post. As we did before, we need to add the `show` action in `app/controllers/posts_controller.rb` and its respective view. @@ -621,7 +628,7 @@ Visit <http://localhost:3000/posts/new> and give it a try! ### Listing all posts -We still need a way to list all our posts, so let's do that. +We still need a way to list all our posts, so let's do that. We'll use a specific route from `config/routes.rb`: ```ruby @@ -742,7 +749,7 @@ end ``` These changes will ensure that all posts have a title that is at least five -characters long. Rails can validate a variety of conditions in a model, +characters long. Rails can validate a variety of conditions in a model, including the presence or uniqueness of columns, their format, and the existence of associated objects. Validations are covered in detail in [Active Record Validations](active_record_validations.html) @@ -763,7 +770,7 @@ def create @post = Post.new(params[:post].permit(:title, :text)) if @post.save - redirect_to @post + redirect_to @post else render 'new' end @@ -786,7 +793,7 @@ something went wrong. To do that, you'll modify ```html+erb <%= form_for :post, url: posts_path do |f| %> <% if @post.errors.any? %> - <div id="errorExplanation"> + <div id="error_explanation"> <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2> <ul> @@ -855,7 +862,7 @@ it look as follows: <%= form_for :post, url: post_path(@post.id), method: :patch do |f| %> <% if @post.errors.any? %> - <div id="errorExplanation"> + <div id="error_explanation"> <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2> <ul> @@ -925,8 +932,7 @@ appear next to the "Show" link: <tr> <th>Title</th> <th>Text</th> - <th></th> - <th></th> + <th colspan="2"></th> </tr> <% @posts.each do |post| %> @@ -971,7 +977,7 @@ content: ```html+erb <%= form_for @post do |f| %> <% if @post.errors.any? %> - <div id="errorExplanation"> + <div id="error_explanation"> <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2> <ul> @@ -1066,9 +1072,7 @@ together. <tr> <th>Title</th> <th>Text</th> - <th></th> - <th></th> - <th></th> + <th colspan="3"></th> </tr> <% @posts.each do |post| %> @@ -1084,7 +1088,7 @@ together. </table> ``` -Here we're using `link_to` in a different way. We pass the named route as the first argument, +Here we're using `link_to` in a different way. We pass the named route as the first argument, and then the final two keys as another argument. The `:method` and `:'data-confirm'` options are used as HTML5 attributes so that when the link is clicked, Rails will first show a confirm dialog to the user, and then submit the link with method `delete`. @@ -1095,7 +1099,7 @@ generated the application. Without this file, the confirmation dialog box wouldn  Congratulations, you can now create, show, list, update and destroy -posts. +posts. TIP: In general, Rails encourages the use of resources objects in place of declaring routes manually. diff --git a/guides/source/i18n.md b/guides/source/i18n.md index 65a85efa69..9e5278c92b 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -174,7 +174,7 @@ end # in your /etc/hosts file to try this out locally def extract_locale_from_tld parsed_locale = request.host.split('.').last - I18n.available_locales.include?(parsed_locale.to_sym) ? parsed_locale : nil + I18n.available_locales.include?(parsed_locale.to_sym) ? parsed_locale : nil end ``` @@ -865,11 +865,11 @@ Rails uses fixed strings and other localizations, such as format strings and oth #### Action View Helper Methods -* `distance_of_time_in_words` translates and pluralizes its result and interpolates the number of seconds, minutes, hours, and so on. See [datetime.distance_in_words](https://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L51) translations. +* `distance_of_time_in_words` translates and pluralizes its result and interpolates the number of seconds, minutes, hours, and so on. See [datetime.distance_in_words](https://github.com/rails/rails/blob/master/actionview/lib/action_view/locale/en.yml#L51) translations. -* `datetime_select` and `select_month` use translated month names for populating the resulting select tag. See [date.month_names](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L15) for translations. `datetime_select` also looks up the order option from [date.order](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L18) (unless you pass the option explicitly). All date selection helpers translate the prompt using the translations in the [datetime.prompts](https://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L83) scope if applicable. +* `datetime_select` and `select_month` use translated month names for populating the resulting select tag. See [date.month_names](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L15) for translations. `datetime_select` also looks up the order option from [date.order](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L18) (unless you pass the option explicitly). All date selection helpers translate the prompt using the translations in the [datetime.prompts](https://github.com/rails/rails/blob/master/actionview/lib/action_view/locale/en.yml#L83) scope if applicable. -* The `number_to_currency`, `number_with_precision`, `number_to_percentage`, `number_with_delimiter`, and `number_to_human_size` helpers use the number format settings located in the [number](https://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L2) scope. +* The `number_to_currency`, `number_with_precision`, `number_to_percentage`, `number_with_delimiter`, and `number_to_human_size` helpers use the number format settings located in the [number](https://github.com/rails/rails/blob/master/actionview/lib/action_view/locale/en.yml#L2) scope. #### Active Model Methods diff --git a/guides/source/initialization.md b/guides/source/initialization.md index 9fcd530183..738591659d 100644 --- a/guides/source/initialization.md +++ b/guides/source/initialization.md @@ -36,8 +36,8 @@ This file is as follows: ```ruby #!/usr/bin/env ruby -APP_PATH = File.expand_path('../../config/application', __FILE__) -require File.expand_path('../../config/boot', __FILE__) +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) require 'rails/commands' ``` @@ -373,7 +373,7 @@ The `options[:config]` value defaults to `config.ru` which contains this: ```ruby # This file is used by Rack-based servers to start the application. -require ::File.expand_path('../config/environment', __FILE__) +require ::File.expand_path('../config/environment', __FILE__) run <%= app_const %> ``` @@ -388,7 +388,7 @@ app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app", The `initialize` method of `Rack::Builder` will take the block here and execute it within an instance of `Rack::Builder`. This is where the majority of the initialization process of Rails happens. The `require` line for `config/environment.rb` in `config.ru` is the first to run: ```ruby -require ::File.expand_path('../config/environment', __FILE__) +require ::File.expand_path('../config/environment', __FILE__) ``` ### `config/environment.rb` @@ -546,7 +546,7 @@ def self.run(app, options={}) else server.register('/', Rack::Handler::Mongrel.new(app)) end - yield server if block_given? + yield server if block_given? server.run.join end ``` diff --git a/guides/source/layout.html.erb b/guides/source/layout.html.erb index 397dd62638..1dcf383b92 100644 --- a/guides/source/layout.html.erb +++ b/guides/source/layout.html.erb @@ -102,11 +102,11 @@ </p> <p> If you see any typos or factual errors you are confident to - patch, please clone <%= link_to 'docrails', 'https://github.com/lifo/docrails' %> - and push the change yourself. That branch of Rails has public write access. - Commits are still reviewed, but that happens after you've submitted your - contribution. <%= link_to 'docrails', 'https://github.com/lifo/docrails' %> is - cross-merged with master periodically. + patch, please clone the <%= link_to 'rails', 'https://github.com/rails/rails' %> + repository and open a new pull request. You can also ask for commit rights on + <%= link_to 'docrails', 'https://github.com/rails/docrails' %> if you plan to submit + several patches. Commits are reviewed, but that happens after you've submitted your + contribution. This repository is cross-merged with master periodically. </p> <p> You may also find incomplete content, or stuff that is not up to date. diff --git a/guides/source/migrations.md b/guides/source/migrations.md index 550f8fdc3c..508e52a77c 100644 --- a/guides/source/migrations.md +++ b/guides/source/migrations.md @@ -366,34 +366,32 @@ create_join_table :products, :categories which creates a `categories_products` table with two columns called `category_id` and `product_id`. These columns have the option `:null` set to -`false` by default. - -You can pass the option `:table_name` with you want to customize the table -name. For example, +`false` by default. This can be overridden by specifying the `:column_options` +option. ```ruby -create_join_table :products, :categories, table_name: :categorization +create_join_table :products, :categories, column_options: {null: true} ``` -will create a `categorization` table. +will create the `product_id` and `category_id` with the `:null` option as +`true`. -By default, `create_join_table` will create two columns with no options, but -you can specify these options using the `:column_options` option. For example, +You can pass the option `:table_name` with you want to customize the table +name. For example, ```ruby -create_join_table :products, :categories, column_options: {null: true} +create_join_table :products, :categories, table_name: :categorization ``` -will create the `product_id` and `category_id` with the `:null` option as -`true`. +will create a `categorization` table. `create_join_table` also accepts a block, which you can use to add indices (which are not created by default) or additional columns: ```ruby create_join_table :products, :categories do |t| - t.index :products - t.index :categories + t.index :product_id + t.index :category_id end ``` @@ -448,7 +446,7 @@ definitions: * `create_table` * `create_join_table` * `drop_table` (must supply a block) -* `drop_join_table` (must supply a block) +* `drop_join_table` (must supply a block) * `remove_timestamps` * `rename_column` * `rename_index` @@ -877,7 +875,7 @@ end # app/models/product.rb class Product < ActiveRecord::Base - validates :flag, inclusion: { in: [true, false] } + validates :flag, inclusion: { in: [true, false] } validates :fuzz, presence: true end ``` diff --git a/guides/source/rails_application_templates.md b/guides/source/rails_application_templates.md index b548eaede8..f8062a1f7c 100644 --- a/guides/source/rails_application_templates.md +++ b/guides/source/rails_application_templates.md @@ -91,7 +91,7 @@ Adds a line inside the `Application` class for `config/application.rb`. If `options[:env]` is specified, the line is appended to the corresponding file in `config/environments`. ```ruby -environment 'config.action_mailer.default_url_options = {host: 'http://yourwebsite.example.com'}, env: 'production' +environment 'config.action_mailer.default_url_options = {host: "http://yourwebsite.example.com"}', env: 'production' ``` A block can be used in place of the `data` argument. diff --git a/guides/source/rails_on_rack.md b/guides/source/rails_on_rack.md index de8f3f483f..d144fba762 100644 --- a/guides/source/rails_on_rack.md +++ b/guides/source/rails_on_rack.md @@ -82,7 +82,7 @@ To use `rackup` instead of Rails' `rails server`, you can put the following insi ```ruby # Rails.root/config.ru -require ::File.expand_path('../config/environment', __FILE__) +require ::File.expand_path('../config/environment', __FILE__) use Rack::Debugger use Rack::ContentLength @@ -131,6 +131,7 @@ use ActionDispatch::DebugExceptions use ActionDispatch::RemoteIp use ActionDispatch::Reloader use ActionDispatch::Callbacks +use ActiveRecord::Migration::CheckPending use ActiveRecord::ConnectionAdapters::ConnectionManagement use ActiveRecord::QueryCache use ActionDispatch::Cookies @@ -272,6 +273,10 @@ Much of Action Controller's functionality is implemented as Middlewares. The fol * Runs the prepare callbacks before serving the request. + **`ActiveRecord::Migration::CheckPending`** + +* Checks pending migrations and raises `ActiveRecord::PendingMigrationError` if any migrations are pending. + **`ActiveRecord::ConnectionAdapters::ConnectionManagement`** * Cleans active connections after each request, unless the `rack.test` key in the request environment is set to `true`. diff --git a/guides/source/routing.md b/guides/source/routing.md index c26a827172..592429952a 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -36,7 +36,7 @@ the request is dispatched to the `patients` controller's `show` action with `{ i ### Generating Paths and URLs from Code -You can also generate paths and URLs. If the route above is modified to be: +You can also generate paths and URLs. If the route above is modified to be: ```ruby get '/patients/:id', to: 'patients#show', as: 'patient' @@ -767,11 +767,11 @@ You can also reuse dynamic segments from the match in the path to redirect to: get '/stories/:name', to: redirect('/posts/%{name}') ``` -You can also provide a block to redirect, which receives the params and the request object: +You can also provide a block to redirect, which receives the symbolized path parameters and the request object: ```ruby -get '/stories/:name', to: redirect {|params, req| "/posts/#{params[:name].pluralize}" } -get '/stories', to: redirect {|p, req| "/posts/#{req.subdomain}" } +get '/stories/:name', to: redirect {|path_params, req| "/posts/#{path_params[:name].pluralize}" } +get '/stories', to: redirect {|path_params, req| "/posts/#{req.subdomain}" } ``` Please note that this redirection is a 301 "Moved Permanently" redirect. Keep in mind that some web browsers or proxy servers will cache this type of redirect, making the old page inaccessible. @@ -803,7 +803,7 @@ You should put the `root` route at the top of the file, because it is the most p NOTE: The `root` route only routes `GET` requests to the action. -You can also use root inside namespaces and scopes as well. For example: +You can also use root inside namespaces and scopes as well. For example: ```ruby namespace :admin do diff --git a/guides/source/ruby_on_rails_guides_guidelines.md b/guides/source/ruby_on_rails_guides_guidelines.md index d5d1ee0a38..5564b0648b 100644 --- a/guides/source/ruby_on_rails_guides_guidelines.md +++ b/guides/source/ruby_on_rails_guides_guidelines.md @@ -63,7 +63,7 @@ Those guidelines apply also to guides. HTML Guides ----------- -Before generating the guides, make sure that you have the latest version of Bundler installed on your system. As of this writing, you must install Bundler 1.3.5 on your device. +Before generating the guides, make sure that you have the latest version of Bundler installed on your system. As of this writing, you must install Bundler 1.3.5 on your device. To install the latest version of Bundler, simply run the `gem install bundler` command diff --git a/guides/source/security.md b/guides/source/security.md index f04129acdb..ad0546810d 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -346,13 +346,13 @@ Intranet and administration interfaces are popular attack targets, because they In 2007 there was the first tailor-made trojan which stole information from an Intranet, namely the "Monster for employers" web site of Monster.com, an online recruitment web application. Tailor-made Trojans are very rare, so far, and the risk is quite low, but it is certainly a possibility and an example of how the security of the client host is important, too. However, the highest threat to Intranet and Admin applications are XSS and CSRF.
-**XSS** If your application re-displays malicious user input from the extranet, the application will be vulnerable to XSS. User names, comments, spam reports, order addresses are just a few uncommon examples, where there can be XSS. +**XSS** If your application re-displays malicious user input from the extranet, the application will be vulnerable to XSS. User names, comments, spam reports, order addresses are just a few uncommon examples, where there can be XSS. Having one single place in the admin interface or Intranet, where the input has not been sanitized, makes the entire application vulnerable. Possible exploits include stealing the privileged administrator's cookie, injecting an iframe to steal the administrator's password or installing malicious software through browser security holes to take over the administrator's computer. Refer to the Injection section for countermeasures against XSS. It is _recommended to use the SafeErb plugin_ also in an Intranet or administration interface. -**CSRF** Cross-Site Reference Forgery (CSRF) is a gigantic attack method, it allows the attacker to do everything the administrator or Intranet user may do. As you have already seen above how CSRF works, here are a few examples of what attackers can do in the Intranet or admin interface. +**CSRF** Cross-Site Reference Forgery (CSRF) is a gigantic attack method, it allows the attacker to do everything the administrator or Intranet user may do. As you have already seen above how CSRF works, here are a few examples of what attackers can do in the Intranet or admin interface. A real-world example is a [router reconfiguration by CSRF](http://www.h-online.com/security/Symantec-reports-first-active-attack-on-a-DSL-router--/news/102352). The attackers sent a malicious e-mail, with CSRF in it, to Mexican users. The e-mail claimed there was an e-card waiting for them, but it also contained an image tag that resulted in a HTTP-GET request to reconfigure the user's router (which is a popular model in Mexico). The request changed the DNS-settings so that requests to a Mexico-based banking site would be mapped to the attacker's site. Everyone who accessed the banking site through that router saw the attacker's fake web site and had his credentials stolen. diff --git a/guides/source/testing.md b/guides/source/testing.md index b02d0b663c..416a8b592f 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -64,7 +64,7 @@ YAML-formatted fixtures are a very human-friendly way to describe your sample da Here's a sample YAML fixture file: ```yaml -# lo & behold! I am a YAML comment! +# lo & behold! I am a YAML comment! david: name: David Heinemeier Hansson birthday: 1979-10-15 @@ -159,7 +159,7 @@ class PostTest < ActiveSupport::TestCase The `PostTest` class defines a _test case_ because it inherits from `ActiveSupport::TestCase`. `PostTest` thus has all the methods available from `ActiveSupport::TestCase`. You'll see those methods a little later in this guide. -Any method defined within a class inherited from `MiniTest::Unit::TestCase` +Any method defined within a class inherited from `MiniTest::Unit::TestCase` (which is the superclass of `ActiveSupport::TestCase`) that begins with `test` (case sensitive) is simply called a test. So, `test_password`, `test_valid_password` and `testValidPassword` all are legal test names and are run automatically when the test case is run. Rails adds a `test` method that takes a test name and a block. It generates a normal `MiniTest::Unit` test with method names prefixed with `test_`. So, @@ -396,7 +396,7 @@ Rails adds some custom assertions of its own to the `test/unit` framework: | `assert_no_difference(expressions, message = nil, &block)` | Asserts that the numeric result of evaluating an expression is not changed before and after invoking the passed in block.| | `assert_recognizes(expected_options, path, extras={}, message=nil)` | Asserts that the routing of the given path was handled correctly and that the parsed options (given in the expected_options hash) match path. Basically, it asserts that Rails recognizes the route given by expected_options.| | `assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)` | Asserts that the provided options can be used to generate the provided path. This is the inverse of assert_recognizes. The extras parameter is used to tell the request the names and values of additional request parameters that would be in a query string. The message parameter allows you to specify a custom error message for assertion failures.| -| `assert_response(type, message = nil)` | Asserts that the response comes with a specific status code. You can specify `:success` to indicate 200-299, `:redirect` to indicate 300-399, `:missing` to indicate 404, or `:error` to match the 500-599 range| +| `assert_response(type, message = nil)` | Asserts that the response comes with a specific status code. You can specify `:success` to indicate 200-299, `:redirect` to indicate 300-399, `:missing` to indicate 404, or `:error` to match the 500-599 range| | `assert_redirected_to(options = {}, message=nil)` | Assert that the redirection options passed in match those of the redirect called in the latest action. This match can be partial, such that `assert_redirected_to(controller: "weblog")` will also match the redirection of `redirect_to(controller: "weblog", action: "show")` and so on.| | `assert_template(expected = nil, message=nil)` | Asserts that the request was rendered with the appropriate template file.| @@ -622,11 +622,11 @@ The `assert_select` assertion is quite powerful. For more advanced usage, refer There are more assertions that are primarily used in testing views: -| Assertion | Purpose | -| ---------------------------------------------------------- | ------- | -| `assert_select_email` | Allows you to make assertions on the body of an e-mail. | -| `assert_select_encoded` | Allows you to make assertions on encoded HTML. It does this by un-encoding the contents of each element and then calling the block with all the un-encoded elements.| -| `css_select(selector)` or `css_select(element, selector)` | Returns an array of all the elements selected by the _selector_. In the second variant it first matches the base _element_ and tries to match the _selector_ expression on any of its children. If there are no matches both variants return an empty array.| +| Assertion | Purpose | +| --------------------------------------------------------- | ------- | +| `assert_select_email` | Allows you to make assertions on the body of an e-mail. | +| `assert_select_encoded` | Allows you to make assertions on encoded HTML. It does this by un-encoding the contents of each element and then calling the block with all the un-encoded elements.| +| `css_select(selector)` or `css_select(element, selector)` | Returns an array of all the elements selected by the _selector_. In the second variant it first matches the base _element_ and tries to match the _selector_ expression on any of its children. If there are no matches both variants return an empty array.| Here's an example of using `assert_select_email`: @@ -767,8 +767,8 @@ Rake Tasks for Running your Tests You don't need to set up and run your tests by hand on a test-by-test basis. Rails comes with a number of commands to help in testing. The table below lists all commands that come along in the default Rakefile when you initiate a Rails project. -| Tasks | Description | -| ------------------------ | ----------- | +| Tasks | Description | +| ----------------------- | ----------- | | `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake test` as Rails will run all the tests by default| | `rake test:controllers` | Runs all the controller tests from `test/controllers`| | `rake test:functionals` | Runs all the functional tests from `test/controllers`, `test/mailers`, and `test/functional`| @@ -778,13 +778,6 @@ You don't need to set up and run your tests by hand on a test-by-test basis. Rai | `rake test:models` | Runs all the model tests from `test/models`| | `rake test:units` | Runs all the unit tests from `test/models`, `test/helpers`, and `test/unit`| -There're also some test commands which you can initiate by running rake tasks: - -| Tasks | Description | -| ------------------------ | ----------- | -| `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake` as the _test_ target is the default.| -| `rake test:recent` | Tests recent changes| -| `rake test:uncommitted` | Runs all the tests which are uncommitted. Supports Subversion and Git| Brief Note About `MiniTest` ----------------------------- diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 6c3e763f53..35a9617b80 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -24,22 +24,67 @@ TIP: Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterp ### HTTP PATCH -Rails 4 now uses `PATCH` as the primary HTTP verb for updates. When a resource -is declared in `config/routes.rb`: +Rails 4 now uses `PATCH` as the primary HTTP verb for updates when a RESTful +resource is declared in `config/routes.rb`. The `update` action is still used, +and `PUT` requests will continue to be routed to the `update` action as well. +So, if you're using only the standard RESTful routes, no changes need to be made: ```ruby resources :users ``` -the action in `UsersController` to update a user is still `update`. +```erb +<%= form_for @user do |f| %> +``` + +```ruby +class UsersController < ApplicationController + def update + # No change needed; PATCH will be preferred, and PUT will still work. + end +end +``` + +However, you will need to make a change if you are using `form_for` to update +a resource in conjunction with a custom route using the `PUT` HTTP method: + +```ruby +resources :users, do + put :update_name, on: :member +end +``` + +```erb +<%= form_for [ :update_name, @user ] do |f| %> +``` + +```ruby +class UsersController < ApplicationController + def update_name + # Change needed; form_for will try to use a non-existant PATCH route. + end +end +``` + +If the action is not being used in a public API and you are free to change the +HTTP method, you can update your route to use `patch` instead of `put`: `PUT` requests to `/users/:id` in Rails 4 get routed to `update` as they are -today. So, if you have an API that gets real PUT requests it is going to work. +today. So, if you have an API that gets real PUT requests it is going to work. The router also routes `PATCH` requests to `/users/:id` to the `update` action. -So, in Rails 4 both `PUT` and `PATCH` are routed to update. We recommend -switching to `PATCH` as part of your upgrade process if possible, as it's more -likely what you want. +```ruby +resources :users do + patch :update_name, on: :member +end +``` + +If the action is being used in a public API and you can't change to HTTP method +being used, you can update your form to use the `PUT` method instead: + +```erb +<%= form_for [ :update_name, @user ], method: :put do |f| %> +``` For more on PATCH and why this change was made, see [this post](http://weblog.rubyonrails.org/2012/2/25/edge-rails-patch-is-the-new-primary-http-method-for-updates/) on the Rails blog. diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md index ddefaf6ff8..22a59cdfec 100644 --- a/guides/source/working_with_javascript_in_rails.md +++ b/guides/source/working_with_javascript_in_rails.md @@ -394,4 +394,4 @@ Here are some helpful links to help you learn even more: * [jquery-ujs list of external articles](https://github.com/rails/jquery-ujs/wiki/External-articles) * [Rails 3 Remote Links and Forms: A Definitive Guide](http://www.alfajango.com/blog/rails-3-remote-links-and-forms/) * [Railscasts: Unobtrusive JavaScript](http://railscasts.com/episodes/205-unobtrusive-javascript) -* [Railscasts: Turbolinks](http://railscasts.com/episodes/390-turbolinks)
\ No newline at end of file +* [Railscasts: Turbolinks](http://railscasts.com/episodes/390-turbolinks) diff --git a/rails.gemspec b/rails.gemspec index 1993467455..b426faf0e8 100644 --- a/rails.gemspec +++ b/rails.gemspec @@ -20,10 +20,11 @@ Gem::Specification.new do |s| s.add_dependency 'activesupport', version s.add_dependency 'actionpack', version + s.add_dependency 'actionview', version s.add_dependency 'activerecord', version s.add_dependency 'actionmailer', version s.add_dependency 'railties', version s.add_dependency 'bundler', '>= 1.3.0', '< 2.0' - s.add_dependency 'sprockets-rails', '~> 2.0.0.rc4' + s.add_dependency 'sprockets-rails', '~> 2.0.0' end diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index d11b0b7e85..ae4bfc2447 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,7 @@ +* Clearing autoloaded constants triggers routes reloading [Fixes #10685]. + + *Xavier Noria* + * Fixes bug with scaffold generator with `--assets=false --resource-route=false`. Fixes #9525. @@ -8,5 +12,9 @@ moved to class methods in Railtie and the Railtie has been made abstract. *John Wang* + +* Changes repetitive th tags to use colspan attribute in `index.html.erb` template. + + *Sıtkı Bağdat* Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/railties/CHANGELOG.md) for previous changes. diff --git a/railties/Rakefile b/railties/Rakefile index 4789f41ad4..5728c774bd 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -54,7 +54,7 @@ end # Publishing ------------------------------------------------------- -desc "Release to gemcutter" +desc "Release to rubygems" task :release => :package do require 'rake/gemcutter' Rake::Gemcutter::Tasks.new(spec).define diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index bb98bbe5bf..3a3c11d8b3 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -3,7 +3,9 @@ require 'rails/ruby_version_check' require 'pathname' require 'active_support' +require 'active_support/dependencies/autoload' require 'active_support/core_ext/kernel/reporting' +require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/array/extract_options' require 'rails/application' @@ -20,26 +22,22 @@ silence_warnings do end module Rails - autoload :Info, 'rails/info' - autoload :InfoController, 'rails/info_controller' - autoload :WelcomeController, 'rails/welcome_controller' + extend ActiveSupport::Autoload + + autoload :Info + autoload :InfoController + autoload :WelcomeController class << self attr_accessor :application, :cache, :logger + delegate :initialize!, :initialized?, to: :application + # The Configuration instance used to configure the Rails environment def configuration application.config end - def initialize! - application.initialize! - end - - def initialized? - application.initialized? - end - def backtrace_cleaner @backtrace_cleaner ||= begin # Relies on Active Support, so we have to lazy load to postpone definition until AS has been loaded @@ -76,7 +74,7 @@ module Rails env = Rails.env groups.unshift(:default, env) groups.concat ENV["RAILS_GROUPS"].to_s.split(",") - groups.concat hash.map { |k,v| k if v.map(&:to_s).include?(env) } + groups.concat hash.map { |k, v| k if v.map(&:to_s).include?(env) } groups.compact! groups.uniq! groups diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 914e4393c4..b5c5a6191f 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -52,11 +52,12 @@ module Rails # 11) Run config.after_initialize callbacks # class Application < Engine - autoload :Bootstrap, 'rails/application/bootstrap' - autoload :Configuration, 'rails/application/configuration' - autoload :Finisher, 'rails/application/finisher' - autoload :Railties, 'rails/engine/railties' - autoload :RoutesReloader, 'rails/application/routes_reloader' + autoload :Bootstrap, 'rails/application/bootstrap' + autoload :Configuration, 'rails/application/configuration' + autoload :DefaultMiddlewareStack, 'rails/application/default_middleware_stack' + autoload :Finisher, 'rails/application/finisher' + autoload :Railties, 'rails/engine/railties' + autoload :RoutesReloader, 'rails/application/routes_reloader' class << self def inherited(base) @@ -102,7 +103,6 @@ module Rails routes_reloader.reload! end - # Return the application's KeyGenerator def key_generator # number of iterations selected based on consultation with the google security @@ -119,32 +119,9 @@ module Rails # Stores some of the Rails initial environment parameters which # will be used by middlewares and engines to configure themselves. - # Currently stores: - # - # * "action_dispatch.parameter_filter" => config.filter_parameters - # * "action_dispatch.redirect_filter" => config.filter_redirect - # * "action_dispatch.secret_token" => config.secret_token - # * "action_dispatch.secret_key_base" => config.secret_key_base - # * "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions - # * "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local - # * "action_dispatch.logger" => Rails.logger - # * "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner - # * "action_dispatch.key_generator" => key_generator - # * "action_dispatch.http_auth_salt" => config.action_dispatch.http_auth_salt - # * "action_dispatch.signed_cookie_salt" => config.action_dispatch.signed_cookie_salt - # * "action_dispatch.encrypted_cookie_salt" => config.action_dispatch.encrypted_cookie_salt - # * "action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt - # def env_config @app_env_config ||= begin - if config.secret_key_base.blank? - ActiveSupport::Deprecation.warn "You didn't set config.secret_key_base. " + - "Read the upgrade documentation to learn more about this new config option." - - if config.secret_token.blank? - raise "You must set config.secret_key_base in your app's config." - end - end + validate_secret_key_config! super.merge({ "action_dispatch.parameter_filter" => config.filter_parameters, @@ -207,9 +184,7 @@ module Rails end # Initialize the application passing the given group. By default, the - # group is :default but sprockets precompilation passes group equals - # to assets if initialize_on_precompile is false to avoid booting the - # whole app. + # group is :default def initialize!(group=:default) #:nodoc: raise "Application has been already initialized." if @initialized run_initializers(group, self) @@ -300,96 +275,9 @@ module Rails initializers end - def reload_dependencies? #:nodoc: - config.reload_classes_only_on_change != true || reloaders.map(&:updated?).any? - end - def default_middleware_stack #:nodoc: - ActionDispatch::MiddlewareStack.new.tap do |middleware| - app = self - - if rack_cache = load_rack_cache - require "action_dispatch/http/rack_cache" - middleware.use ::Rack::Cache, rack_cache - end - - if config.force_ssl - middleware.use ::ActionDispatch::SSL, config.ssl_options - end - - if config.action_dispatch.x_sendfile_header.present? - middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header - end - - if config.serve_static_assets - middleware.use ::ActionDispatch::Static, paths["public"].first, config.static_cache_control - end - - middleware.use ::Rack::Lock unless allow_concurrency? - middleware.use ::Rack::Runtime - middleware.use ::Rack::MethodOverride - middleware.use ::ActionDispatch::RequestId - - # Must come after Rack::MethodOverride to properly log overridden methods - middleware.use ::Rails::Rack::Logger, config.log_tags - middleware.use ::ActionDispatch::ShowExceptions, show_exceptions_app - middleware.use ::ActionDispatch::DebugExceptions, app - middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies - - unless config.cache_classes - middleware.use ::ActionDispatch::Reloader, lambda { app.reload_dependencies? } - end - - middleware.use ::ActionDispatch::Callbacks - middleware.use ::ActionDispatch::Cookies - - if config.session_store - if config.force_ssl && !config.session_options.key?(:secure) - config.session_options[:secure] = true - end - middleware.use config.session_store, config.session_options - middleware.use ::ActionDispatch::Flash - end - - middleware.use ::ActionDispatch::ParamsParser - middleware.use ::Rack::Head - middleware.use ::Rack::ConditionalGet - middleware.use ::Rack::ETag, "no-cache" - end - end - - def allow_concurrency? - if config.allow_concurrency.nil? - config.cache_classes - else - config.allow_concurrency - end - end - - def load_rack_cache - rack_cache = config.action_dispatch.rack_cache - return unless rack_cache - - begin - require 'rack/cache' - rescue LoadError => error - error.message << ' Be sure to add rack-cache to your Gemfile' - raise - end - - if rack_cache == true - { - metastore: "rails:/", - entitystore: "rails:/", - verbose: false - } - else - rack_cache - end - end - - def show_exceptions_app - config.exceptions_app || ActionDispatch::PublicExceptions.new(Rails.public_path) + default_stack = DefaultMiddlewareStack.new(self, config, paths) + default_stack.build_stack end def build_original_fullpath(env) #:nodoc: @@ -403,5 +291,11 @@ module Rails "#{script_name}#{path_info}" end end + + def validate_secret_key_config! #:nodoc: + if config.secret_key_base.blank? && config.secret_token.blank? + raise "You must set config.secret_key_base in your app's config." + end + end end end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 31fc80e544..644893d9e1 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -61,7 +61,6 @@ module Rails @assets.cache_store = [ :file_store, "#{root}/tmp/cache/assets/#{Rails.env}/" ] @assets.js_compressor = nil @assets.css_compressor = nil - @assets.initialize_on_precompile = true @assets.logger = nil end diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb new file mode 100644 index 0000000000..370c906086 --- /dev/null +++ b/railties/lib/rails/application/default_middleware_stack.rb @@ -0,0 +1,101 @@ +module Rails + class Application + class DefaultMiddlewareStack + attr_reader :config, :paths, :app + + def initialize(app, config, paths) + @app = app + @config = config + @paths = paths + end + + def build_stack + ActionDispatch::MiddlewareStack.new.tap do |middleware| + if rack_cache = load_rack_cache + require "action_dispatch/http/rack_cache" + middleware.use ::Rack::Cache, rack_cache + end + + if config.force_ssl + middleware.use ::ActionDispatch::SSL, config.ssl_options + end + + if config.action_dispatch.x_sendfile_header.present? + middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header + end + + if config.serve_static_assets + middleware.use ::ActionDispatch::Static, paths["public"].first, config.static_cache_control + end + + middleware.use ::Rack::Lock unless allow_concurrency? + middleware.use ::Rack::Runtime + middleware.use ::Rack::MethodOverride + middleware.use ::ActionDispatch::RequestId + + # Must come after Rack::MethodOverride to properly log overridden methods + middleware.use ::Rails::Rack::Logger, config.log_tags + middleware.use ::ActionDispatch::ShowExceptions, show_exceptions_app + middleware.use ::ActionDispatch::DebugExceptions, app + middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies + + unless config.cache_classes + middleware.use ::ActionDispatch::Reloader, lambda { reload_dependencies? } + end + + middleware.use ::ActionDispatch::Callbacks + middleware.use ::ActionDispatch::Cookies + + if config.session_store + if config.force_ssl && !config.session_options.key?(:secure) + config.session_options[:secure] = true + end + middleware.use config.session_store, config.session_options + middleware.use ::ActionDispatch::Flash + end + + middleware.use ::ActionDispatch::ParamsParser + middleware.use ::Rack::Head + middleware.use ::Rack::ConditionalGet + middleware.use ::Rack::ETag, "no-cache" + end + end + + private + + def reload_dependencies? + config.reload_classes_only_on_change != true || app.reloaders.map(&:updated?).any? + end + + def allow_concurrency? + config.allow_concurrency.nil? ? config.cache_classes : config.allow_concurrency + end + + def load_rack_cache + rack_cache = config.action_dispatch.rack_cache + return unless rack_cache + + begin + require 'rack/cache' + rescue LoadError => error + error.message << ' Be sure to add rack-cache to your Gemfile' + raise + end + + if rack_cache == true + { + metastore: "rails:/", + entitystore: "rails:/", + verbose: false + } + else + rack_cache + end + end + + def show_exceptions_app + config.exceptions_app || ActionDispatch::PublicExceptions.new(Rails.public_path) + end + end + end +end diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 3ae60312c5..7a1bb1e25c 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -62,17 +62,28 @@ module Rails ActiveSupport.run_load_hooks(:after_initialize, self) end - # Set app reload just after the finisher hook to ensure - # routes added in the hook are still loaded. + # Set routes reload after the finisher hook to ensure routes added in + # the hook are taken into account. initializer :set_routes_reloader_hook do reloader = routes_reloader reloader.execute_if_updated self.reloaders << reloader - ActionDispatch::Reloader.to_prepare { reloader.execute_if_updated } + ActionDispatch::Reloader.to_prepare do + # We configure #execute rather than #execute_if_updated because if + # autoloaded constants are cleared we need to reload routes also in + # case any was used there, as in + # + # mount MailPreview => 'mail_view' + # + # This means routes are also reloaded if i18n is updated, which + # might not be necessary, but in order to be more precise we need + # some sort of reloaders dependency support, to be added. + reloader.execute + end end - # Set app reload just after the finisher hook to ensure - # paths added in the hook are still loaded. + # Set clearing dependencies after the finisher hook to ensure paths + # added in the hook are taken into account. initializer :set_clear_dependencies_hook, group: :all do callback = lambda do ActiveSupport::DescendantsTracker.clear @@ -82,9 +93,17 @@ module Rails if config.reload_classes_only_on_change reloader = config.file_watcher.new(*watchable_args, &callback) self.reloaders << reloader - # We need to set a to_prepare callback regardless of the reloader result, i.e. - # models should be reloaded if any of the reloaders (i18n, routes) were updated. - ActionDispatch::Reloader.to_prepare(prepend: true){ reloader.execute } + + # Prepend this callback to have autoloaded constants cleared before + # any other possible reloading, in case they need to autoload fresh + # constants. + ActionDispatch::Reloader.to_prepare(prepend: true) do + # In addition to changes detected by the file watcher, if routes + # or i18n have been updated we also need to clear constants, + # that's why we run #execute rather than #execute_if_updated, this + # callback has to clear autoloaded constants after any update. + reloader.execute + end else ActionDispatch::Reloader.to_cleanup(&callback) end diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index e8c42b149b..48007dd2ab 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -5,7 +5,6 @@ aliases = { "d" => "destroy", "c" => "console", "s" => "server", - "t" => "test", "db" => "dbconsole", "r" => "runner" } @@ -17,7 +16,6 @@ The most common rails commands are: generate Generate new code (short-cut alias: "g") console Start the Rails console (short-cut alias: "c") server Start the Rails server (short-cut alias: "s") - test Running the test file (short-cut alias: "t") dbconsole Start a console for the database specified in config/database.yml (short-cut alias: "db") new Create a new Rails application. "rails new my_app" creates a diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb index 5914c9e4ae..3e4cc787c4 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole.rb @@ -44,7 +44,7 @@ module Rails find_cmd_and_exec(['mysql', 'mysql5'], *args) - when "postgresql", "postgres" + when "postgresql", "postgres", "postgis" ENV['PGUSER'] = config["username"] if config["username"] ENV['PGHOST'] = config["host"] if config["host"] ENV['PGPORT'] = config["port"].to_s if config["port"] diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb index c4622d6a2d..2b77d5d387 100644 --- a/railties/lib/rails/commands/runner.rb +++ b/railties/lib/rails/commands/runner.rb @@ -48,7 +48,7 @@ if code_or_file.nil? exit 1 elsif File.exist?(code_or_file) $0 = code_or_file - eval(File.read(code_or_file), nil, code_or_file) + Kernel.load code_or_file else eval(code_or_file) end diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index e3119ecf22..87d6505ed5 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -63,6 +63,9 @@ module Rails puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}" puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}" puts "=> Run `rails server -h` for more startup options" + if options[:Host].to_s.match(/0\.0\.0\.0/) + puts "=> Notice: server is listening on all interfaces (#{options[:Host]}). Consider using 127.0.0.1 (--binding option)" + end trap(:INT) { exit } puts "=> Ctrl-C to shutdown server" unless options[:daemonize] diff --git a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb index 9d778642f2..814d6fdb0e 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb @@ -6,9 +6,7 @@ <% attributes.reject(&:password_digest?).each do |attribute| -%> <th><%= attribute.human_name %></th> <% end -%> - <th></th> - <th></th> - <th></th> + <th colspan="3"></th> </tr> </thead> diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt index 6899dfe9c9..8b91313e51 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt @@ -7,7 +7,8 @@ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // compiled file. // -// stub path allows dependency to be excluded from the asset bundle. +// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details +// about supported directives. // <% unless options[:skip_javascript] -%> //= require <%= options[:javascript] %> diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/javascripts.js b/railties/lib/rails/generators/rails/plugin_new/templates/rails/javascripts.js index f84de00fd3..5bc2e1c8b5 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/rails/javascripts.js +++ b/railties/lib/rails/generators/rails/plugin_new/templates/rails/javascripts.js @@ -7,6 +7,7 @@ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // compiled file. // -// stub path allows dependency to be excluded from the asset bundle. +// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details +// about supported directives. // //= require_tree . diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake index 2116330b45..76a95304c3 100644 --- a/railties/lib/rails/tasks/framework.rake +++ b/railties/lib/rails/tasks/framework.rake @@ -47,7 +47,7 @@ namespace :rails do gen = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: Rails.root File.exists?(Rails.root.join("config", "application.rb")) ? - gen.send(:app_const) : gen.send(:valid_app_const?) + gen.send(:app_const) : gen.send(:valid_const?) gen end end diff --git a/railties/lib/rails/test_unit/railtie.rb b/railties/lib/rails/test_unit/railtie.rb index ab1ebe1f8c..75180ff978 100644 --- a/railties/lib/rails/test_unit/railtie.rb +++ b/railties/lib/rails/test_unit/railtie.rb @@ -1,4 +1,4 @@ -if defined?(Rake) && Rake.application.top_level_tasks.grep(/^(default$|test(:|$))/).any? +if defined?(Rake.application) && Rake.application.top_level_tasks.grep(/^(default$|test(:|$))/).any? ENV['RAILS_ENV'] ||= 'test' end diff --git a/railties/test/application/asset_debugging_test.rb b/railties/test/application/asset_debugging_test.rb index b3b40448c0..9a571fac3a 100644 --- a/railties/test/application/asset_debugging_test.rb +++ b/railties/test/application/asset_debugging_test.rb @@ -14,7 +14,7 @@ module ApplicationTests app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'application' %>" app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/posts', to: "posts#index" end RUBY diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 34432eac3a..633d864dac 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -45,7 +45,7 @@ module ApplicationTests app_file "app/assets/javascripts/demo.js.erb", "a = <%= image_path('rails.png').inspect %>;" app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '*path', to: lambda { |env| [200, { "Content-Type" => "text/html" }, ["Not an asset"]] } end RUBY @@ -165,6 +165,29 @@ module ApplicationTests assert_file_exists("#{app_path}/public/assets/something-*.js") end + test 'precompile use assets defined in app env config' do + add_to_env_config 'production', 'config.assets.precompile = [ "something.js" ]' + + app_file 'app/assets/javascripts/something.js.erb', 'alert();' + + precompile! 'RAILS_ENV=production' + + assert_file_exists("#{app_path}/public/assets/something-*.js") + end + + test 'precompile use assets defined in app config and reassigned in app env config' do + add_to_config 'config.assets.precompile = [ "something.js" ]' + add_to_env_config 'production', 'config.assets.precompile += [ "another.js" ]' + + app_file 'app/assets/javascripts/something.js.erb', 'alert();' + app_file 'app/assets/javascripts/another.js.erb', 'alert();' + + precompile! 'RAILS_ENV=production' + + assert_file_exists("#{app_path}/public/assets/something-*.js") + assert_file_exists("#{app_path}/public/assets/another-*.js") + end + test "asset pipeline should use a Sprockets::Index when config.assets.digest is true" do add_to_config "config.assets.digest = true" add_to_config "config.action_controller.perform_caching = false" @@ -313,7 +336,7 @@ module ApplicationTests app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();" app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/omg', :to => "omg#index" end RUBY @@ -376,18 +399,6 @@ module ApplicationTests assert_equal "Post;\n", File.read(Dir["#{app_path}/public/assets/application-*.js"].first) end - test "assets can't access model information when precompiling if not initializing the app" do - app_file "app/models/post.rb", "class Post; end" - app_file "app/assets/javascripts/application.js", "//= require_tree ." - app_file "app/assets/javascripts/xmlhr.js.erb", "<%= defined?(Post) || :NoPost %>" - - add_to_config "config.assets.digest = false" - add_to_config "config.assets.initialize_on_precompile = false" - - precompile! - assert_equal "NoPost;\n", File.read(Dir["#{app_path}/public/assets/application-*.js"].first) - end - test "initialization on the assets group should set assets_dir" do require "#{app_path}/config/application" Rails.application.initialize!(:assets) @@ -475,7 +486,7 @@ module ApplicationTests app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'application' %>" app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/posts', :to => "posts#index" end RUBY diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 1acf03f35a..28839a9c4b 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -62,6 +62,7 @@ module ApplicationTests require "#{app_path}/config/environment" ActiveRecord::Migrator.stubs(:needs_migration?).returns(true) + ActiveRecord::NullMigration.any_instance.stubs(:mtime).returns(1) get "/foo" assert_equal 500, last_response.status @@ -158,12 +159,12 @@ module ApplicationTests RUBY require "#{app_path}/config/application" - assert AppTemplate::Application.initialize! + assert Rails.application.initialize! end test "application is always added to eager_load namespaces" do require "#{app_path}/config/application" - assert AppTemplate::Application, AppTemplate::Application.config.eager_load_namespaces + assert Rails.application, Rails.application.config.eager_load_namespaces end test "the application can be eager loaded even when there are no frameworks" do diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index bc794e1602..33659db927 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -41,7 +41,7 @@ module ApplicationTests test "allows me to configure default url options for ActionMailer" do app_file "config/environments/development.rb", <<-RUBY - AppTemplate::Application.configure do + Rails.application.configure do config.action_mailer.default_url_options = { :host => "test.rails" } end RUBY @@ -52,7 +52,7 @@ module ApplicationTests test "does not include url helpers as action methods" do app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get "/foo", :to => lambda { |env| [200, {}, []] }, :as => :foo end RUBY @@ -115,7 +115,7 @@ module ApplicationTests RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get "/:controller(/:action)" end RUBY diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb index 17d0b10b70..97df073ec7 100644 --- a/railties/test/application/initializers/i18n_test.rb +++ b/railties/test/application/initializers/i18n_test.rb @@ -84,7 +84,7 @@ en: RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/i18n', :to => lambda { |env| [200, {}, [Foo.instance_variable_get('@foo')]] } end RUBY @@ -108,7 +108,7 @@ en: YAML app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/i18n', :to => lambda { |env| [200, {}, [I18n.t(:foo)]] } end RUBY diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb index 0c66213caa..b36628ee37 100644 --- a/railties/test/application/initializers/load_path_test.rb +++ b/railties/test/application/initializers/load_path_test.rb @@ -75,7 +75,7 @@ module ApplicationTests $initialize_test_set_from_env = nil app_file "config/environments/development.rb", <<-RUBY $initialize_test_set_from_env = 'success' - AppTemplate::Application.configure do + Rails.application.configure do config.cache_classes = true config.time_zone = "Brasilia" end @@ -89,8 +89,8 @@ module ApplicationTests require "#{app_path}/config/environment" assert_equal "success", $initialize_test_set_from_env - assert AppTemplate::Application.config.cache_classes - assert_equal "Brasilia", AppTemplate::Application.config.time_zone + assert Rails.application.config.cache_classes + assert_equal "Brasilia", Rails.application.config.time_zone end end end diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb index ad7172c514..f05eade81f 100644 --- a/railties/test/application/loading_test.rb +++ b/railties/test/application/loading_test.rb @@ -48,7 +48,7 @@ class LoadingTest < ActiveSupport::TestCase test "load config/environments/environment before Bootstrap initializers" do app_file "config/environments/development.rb", <<-RUBY - AppTemplate::Application.configure do + Rails.application.configure do config.development_environment_loaded = true end RUBY @@ -60,7 +60,7 @@ class LoadingTest < ActiveSupport::TestCase RUBY require "#{app_path}/config/environment" - assert ::AppTemplate::Application.config.loaded + assert ::Rails.application.config.loaded end test "descendants loaded after framework initialization are cleaned on each request without cache classes" do @@ -75,7 +75,7 @@ class LoadingTest < ActiveSupport::TestCase MODEL app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/load', to: lambda { |env| [200, {}, Post.all] } get '/unload', to: lambda { |env| [200, {}, []] } end @@ -96,7 +96,7 @@ class LoadingTest < ActiveSupport::TestCase test "initialize cant be called twice" do require "#{app_path}/config/environment" - assert_raise(RuntimeError) { ::AppTemplate::Application.initialize! } + assert_raise(RuntimeError) { Rails.application.initialize! } end test "reload constants on development" do @@ -105,7 +105,7 @@ class LoadingTest < ActiveSupport::TestCase RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/c', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] } end RUBY @@ -144,7 +144,7 @@ class LoadingTest < ActiveSupport::TestCase RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/c', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] } end RUBY @@ -179,8 +179,8 @@ class LoadingTest < ActiveSupport::TestCase RUBY app_file 'config/routes.rb', <<-RUBY - $counter = 0 - AppTemplate::Application.routes.draw do + $counter ||= 0 + Rails.application.routes.draw do get '/c', to: lambda { |env| User; [200, {"Content-Type" => "text/plain"}, [$counter.to_s]] } end RUBY @@ -205,13 +205,46 @@ class LoadingTest < ActiveSupport::TestCase assert_equal "2", last_response.body end + test "dependencies reloading is followed by routes reloading" do + add_to_config <<-RUBY + config.cache_classes = false + RUBY + + app_file 'config/routes.rb', <<-RUBY + $counter ||= 1 + $counter *= 2 + Rails.application.routes.draw do + get '/c', to: lambda { |env| User; [200, {"Content-Type" => "text/plain"}, [$counter.to_s]] } + end + RUBY + + app_file "app/models/user.rb", <<-MODEL + class User + $counter += 1 + end + MODEL + + require 'rack/test' + extend Rack::Test::Methods + + require "#{rails_root}/config/environment" + + get "/c" + assert_equal "3", last_response.body + + app_file "db/schema.rb", "" + + get "/c" + assert_equal "7", last_response.body + end + test "columns migrations also trigger reloading" do add_to_config <<-RUBY config.cache_classes = false RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/title', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.title]] } get '/body', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.body]] } end @@ -270,7 +303,7 @@ class LoadingTest < ActiveSupport::TestCase RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get "/:controller(/:action)" end RUBY @@ -288,10 +321,10 @@ class LoadingTest < ActiveSupport::TestCase require "#{app_path}/config/application" assert !Rails.initialized? - assert !AppTemplate::Application.initialized? + assert !Rails.application.initialized? Rails.initialize! assert Rails.initialized? - assert AppTemplate::Application.initialized? + assert Rails.application.initialized? end protected diff --git a/railties/test/application/middleware/cache_test.rb b/railties/test/application/middleware/cache_test.rb index b8e0c9be60..b4db840e68 100644 --- a/railties/test/application/middleware/cache_test.rb +++ b/railties/test/application/middleware/cache_test.rb @@ -45,7 +45,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' end RUBY diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb index 8cb0dfeb63..14a56176f5 100644 --- a/railties/test/application/middleware/session_test.rb +++ b/railties/test/application/middleware/session_test.rb @@ -49,7 +49,7 @@ module ApplicationTests test "session is empty and isn't saved on unverified request when using :null_session protect method" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' post ':controller(/:action)' end @@ -90,7 +90,7 @@ module ApplicationTests test "cookie jar is empty and isn't saved on unverified request when using :null_session protect method" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' post ':controller(/:action)' end @@ -131,7 +131,7 @@ module ApplicationTests test "session using encrypted cookie store" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' end RUBY @@ -176,7 +176,7 @@ module ApplicationTests test "session upgrading signature to encryption cookie store works the same way as encrypted cookie store" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' end RUBY @@ -225,7 +225,7 @@ module ApplicationTests test "session upgrading signature to encryption cookie store upgrades session to encrypted mode" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' end RUBY @@ -284,7 +284,7 @@ module ApplicationTests test "session upgrading legacy signed cookies to new signed cookies" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' end RUBY diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index d8076c7151..251fe02bc5 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -69,6 +69,14 @@ module ApplicationTests assert_equal "Rack::Cache", middleware.first end + test "ActiveRecord::Migration::CheckPending is present when active_record.migration_error is set to :page_load" do + add_to_config "config.active_record.migration_error = :page_load" + + boot! + + assert middleware.include?("ActiveRecord::Migration::CheckPending") + end + test "ActionDispatch::SSL is present when force_ssl is set" do add_to_config "config.force_ssl = true" boot! @@ -80,7 +88,7 @@ module ApplicationTests add_to_config "config.ssl_options = { host: 'example.com' }" boot! - assert_equal AppTemplate::Application.middleware.first.args, [{host: 'example.com'}] + assert_equal Rails.application.middleware.first.args, [{host: 'example.com'}] end test "removing Active Record omits its middleware" do @@ -217,7 +225,7 @@ module ApplicationTests end def middleware - AppTemplate::Application.middleware.map(&:klass).map(&:name) + Rails.application.middleware.map(&:klass).map(&:name) end end end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index 6703f8df51..746ebdaa35 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -30,11 +30,11 @@ module ApplicationTests app_file "config/environment.rb", <<-RUBY SuperMiddleware = Struct.new(:app) - AppTemplate::Application.configure do + Rails.application.configure do config.middleware.use SuperMiddleware end - AppTemplate::Application.initialize! + Rails.application.initialize! RUBY assert_match("SuperMiddleware", Dir.chdir(app_path){ `rake middleware` }) @@ -142,7 +142,7 @@ module ApplicationTests def test_rake_routes_calls_the_route_inspector app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/cart', to: 'cart#show' end RUBY @@ -151,9 +151,22 @@ module ApplicationTests assert_equal "Prefix Verb URI Pattern Controller#Action\ncart GET /cart(.:format) cart#show\n", output end + def test_rake_routes_with_controller_environment + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + get '/cart', to: 'cart#show' + get '/basketball', to: 'basketball#index' + end + RUBY + + ENV['CONTROLLER'] = 'cart' + output = Dir.chdir(app_path){ `rake routes` } + assert_equal "Prefix Verb URI Pattern Controller#Action\ncart GET /cart(.:format) cart#show\n", output + end + def test_rake_routes_displays_message_when_no_routes_are_defined app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do end RUBY diff --git a/railties/test/application/rendering_test.rb b/railties/test/application/rendering_test.rb index 588d64dde9..b01febd768 100644 --- a/railties/test/application/rendering_test.rb +++ b/railties/test/application/rendering_test.rb @@ -17,7 +17,7 @@ module ApplicationTests test "Unknown format falls back to HTML template" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'pages/:id', to: 'pages#show' end RUBY diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb index 25372d0a50..1a4e2d4123 100644 --- a/railties/test/application/routing_test.rb +++ b/railties/test/application/routing_test.rb @@ -48,7 +48,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do root to: "foo#index" end RUBY @@ -100,7 +100,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' end RUBY @@ -111,7 +111,7 @@ module ApplicationTests test "mount rack app" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do mount lambda { |env| [200, {}, [env["PATH_INFO"]]] }, at: "/blog" # The line below is required because mount sometimes # fails when a resource route is added. @@ -141,7 +141,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' end RUBY @@ -173,7 +173,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'admin/foo', to: 'admin/foo#index' get 'foo', to: 'foo#index' end @@ -188,7 +188,7 @@ module ApplicationTests test "routes appending blocks" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller/:action' end RUBY @@ -205,7 +205,7 @@ module ApplicationTests assert_equal 'WIN', last_response.body app_file 'config/routes.rb', <<-R - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'lol' => 'hello#index' end R @@ -229,7 +229,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'foo', to: 'foo#bar' end RUBY @@ -240,7 +240,7 @@ module ApplicationTests assert_equal 'bar', last_response.body app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'foo', to: 'foo#baz' end RUBY @@ -261,7 +261,7 @@ module ApplicationTests end app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'foo', to: ::InitializeRackApp end RUBY @@ -289,7 +289,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'foo', :to => 'foo#index' root :to => 'foo#index' end @@ -321,7 +321,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'foo', to: 'foo#index' end RUBY @@ -337,7 +337,7 @@ module ApplicationTests end app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'foo', to: 'foo#index' get 'bar', to: 'bar#index' end @@ -354,7 +354,7 @@ module ApplicationTests assert_equal '/bar', Rails.application.routes.url_helpers.bar_path app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'foo', to: 'foo#index' end RUBY @@ -380,7 +380,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do resources :yazilar end RUBY diff --git a/railties/test/application/url_generation_test.rb b/railties/test/application/url_generation_test.rb index 0905757442..2767779719 100644 --- a/railties/test/application/url_generation_test.rb +++ b/railties/test/application/url_generation_test.rb @@ -20,7 +20,7 @@ module ApplicationTests config.eager_load = false end - MyApp.initialize! + Rails.application.initialize! class ::ApplicationController < ActionController::Base end diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index 68d96bae94..a3295a6e69 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -163,7 +163,7 @@ module TestHelpers RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' end RUBY diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 0948ae59c0..50253fe2bc 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -270,7 +270,7 @@ module RailtiesTest RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'foo', :to => 'foo#index' end RUBY @@ -345,7 +345,7 @@ YAML #{RAILS_FRAMEWORK_ROOT}/activesupport/lib/active_support/locale/en.yml #{RAILS_FRAMEWORK_ROOT}/activemodel/lib/active_model/locale/en.yml #{RAILS_FRAMEWORK_ROOT}/activerecord/lib/active_record/locale/en.yml - #{RAILS_FRAMEWORK_ROOT}/actionpack/lib/action_view/locale/en.yml + #{RAILS_FRAMEWORK_ROOT}/actionview/lib/action_view/locale/en.yml #{@plugin.path}/config/locales/en.yml #{app_path}/config/locales/en.yml #{app_path}/app/locales/en.yml @@ -467,7 +467,7 @@ YAML RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do mount(Bukkits::Engine => "/bukkits") end RUBY @@ -602,7 +602,7 @@ YAML RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get "/bar" => "bar#index", as: "bar" mount Bukkits::Engine => "/bukkits", as: "bukkits" end @@ -720,7 +720,7 @@ YAML RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do mount Bukkits::Engine => "/bukkits", as: "bukkits" end RUBY @@ -764,7 +764,7 @@ YAML RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do mount Bukkits::Awesome::Engine => "/bukkits", :as => "bukkits" end RUBY @@ -828,7 +828,7 @@ YAML add_to_config "isolate_namespace AppTemplate" app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do end + Rails.application.routes.draw do end RUBY boot_rails @@ -1206,7 +1206,7 @@ YAML RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/bar' => 'bar#index', :as => 'bar' mount Bukkits::Engine => "/bukkits", :as => "bukkits" end diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb index c94937f964..0ef2ff2e2e 100644 --- a/railties/test/railties/mounted_engine_test.rb +++ b/railties/test/railties/mounted_engine_test.rb @@ -16,7 +16,7 @@ module ApplicationTests @metrics_plugin = engine "metrics" app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do mount Weblog::Engine, :at => '/', :as => 'weblog' resources :posts get "/engine_route" => "application_generating#engine_route" diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index 520a855c90..4cbd4822be 100644 --- a/railties/test/railties/railtie_test.rb +++ b/railties/test/railties/railtie_test.rb @@ -26,7 +26,7 @@ module RailtiesTest test "Railtie provides railtie_name" do begin class ::FooBarBaz < Rails::Railtie ; end - assert_equal "foo_bar_baz", ::FooBarBaz.railtie_name + assert_equal "foo_bar_baz", FooBarBaz.railtie_name ensure Object.send(:remove_const, :"FooBarBaz") end @@ -58,7 +58,7 @@ module RailtiesTest config.foo.greetings = "hello" end require "#{app_path}/config/application" - assert_equal "hello", AppTemplate::Application.config.foo.greetings + assert_equal "hello", Rails.application.config.foo.greetings end test "railtie can add to_prepare callbacks" do @@ -96,7 +96,7 @@ module RailtiesTest require 'rake/testtask' require 'rdoc/task' - AppTemplate::Application.load_tasks + Rails.application.load_tasks assert $ran_block end @@ -120,7 +120,7 @@ module RailtiesTest require 'rake/testtask' require 'rdoc/task' - AppTemplate::Application.load_tasks + Rails.application.load_tasks assert $ran_block.include?("my_tie") end @@ -136,7 +136,7 @@ module RailtiesTest require "#{app_path}/config/environment" assert !$ran_block - AppTemplate::Application.load_generators + Rails.application.load_generators assert $ran_block end @@ -152,7 +152,7 @@ module RailtiesTest require "#{app_path}/config/environment" assert !$ran_block - AppTemplate::Application.load_console + Rails.application.load_console assert $ran_block end @@ -168,7 +168,7 @@ module RailtiesTest require "#{app_path}/config/environment" assert !$ran_block - AppTemplate::Application.load_runner + Rails.application.load_runner assert $ran_block end |