Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of git://github.com/rails/rails

  • Loading branch information...
commit 84eece0a823e9c601ea99a8709f24605a19bcbfd 2 parents 1996540 + c495bfc
@dmitry dmitry authored
Showing with 686 additions and 374 deletions.
  1. +3 −0  Gemfile
  2. +11 −11 actionpack/actionpack.gemspec
  3. +2 −1  actionpack/lib/abstract_controller/asset_paths.rb
  4. +2 −2 actionpack/lib/abstract_controller/rendering.rb
  5. +15 −5 actionpack/lib/action_controller/test_case.rb
  6. +6 −4 actionpack/lib/action_dispatch/http/url.rb
  7. +3 −2 actionpack/lib/action_dispatch/routing/url_for.rb
  8. +1 −6 actionpack/lib/action_dispatch/testing/test_process.rb
  9. +4 −17 actionpack/lib/action_view/asset_paths.rb
  10. +1 −1  actionpack/lib/action_view/test_case.rb
  11. +71 −36 actionpack/lib/sprockets/assets.rake
  12. +2 −1  actionpack/lib/sprockets/helpers.rb
  13. +13 −0 actionpack/lib/sprockets/helpers/isolated_helper.rb
  14. +0 −3  actionpack/lib/sprockets/helpers/rails_helper.rb
  15. +5 −3 actionpack/lib/sprockets/railtie.rb
  16. +29 −20 actionpack/lib/sprockets/static_compiler.rb
  17. +36 −0 actionpack/test/controller/test_test.rb
  18. +14 −0 actionpack/test/controller/url_for_test.rb
  19. +1 −0  actionpack/test/dispatch/request_test.rb
  20. +1 −2  actionpack/test/template/compressors_test.rb
  21. +13 −8 actionpack/test/template/sprockets_helper_test.rb
  22. +3 −3 activemodel/lib/active_model/attribute_methods.rb
  23. +2 −2 activemodel/lib/active_model/serializers/json.rb
  24. +7 −0 activerecord/lib/active_record/attribute_methods/primary_key.rb
  25. +3 −3 activerecord/lib/active_record/attribute_methods/read.rb
  26. +1 −1  activerecord/lib/active_record/attribute_methods/write.rb
  27. +5 −4 activerecord/lib/active_record/base.rb
  28. +14 −0 activerecord/lib/active_record/errors.rb
  29. +1 −1  activerecord/lib/active_record/fixtures.rb
  30. +1 −1  activerecord/lib/active_record/persistence.rb
  31. +1 −1  activerecord/lib/active_record/railties/databases.rake
  32. +3 −3 activerecord/lib/active_record/relation.rb
  33. +1 −1  activerecord/lib/active_record/transactions.rb
  34. +4 −0 activerecord/test/cases/attribute_methods/read_test.rb
  35. +0 −4 activerecord/test/cases/base_test.rb
  36. +14 −0 activerecord/test/cases/primary_keys_test.rb
  37. +2 −0  activerecord/test/config.example.yml
  38. +1 −0  activesupport/lib/active_support/cache/file_store.rb
  39. +1 −1  activesupport/lib/active_support/core_ext/range/conversions.rb
  40. +13 −11 activesupport/lib/active_support/core_ext/string/output_safety.rb
  41. +1 −1  activesupport/lib/active_support/core_ext/time/calculations.rb
  42. +8 −0 activesupport/test/caching_test.rb
  43. +3 −0  activesupport/test/core_ext/time_ext_test.rb
  44. +1 −1  activesupport/test/rescuable_test.rb
  45. +4 −1 railties/CHANGELOG
  46. +29 −28 railties/guides/source/active_record_basics.textile
  47. +1 −1  railties/guides/source/active_record_querying.textile
  48. +67 −54 railties/guides/source/active_record_validations_callbacks.textile
  49. +9 −0 railties/guides/source/asset_pipeline.textile
  50. +9 −9 railties/guides/source/configuring.textile
  51. +36 −0 railties/guides/source/engines.textile
  52. +63 −61 railties/guides/source/getting_started.textile
  53. +30 −32 railties/guides/source/migrations.textile
  54. +1 −1  railties/lib/rails/application.rb
  55. +14 −13 railties/lib/rails/application/configuration.rb
  56. +8 −0 railties/lib/rails/commands/application.rb
  57. +1 −1  railties/lib/rails/engine.rb
  58. +6 −0 railties/lib/rails/generators/rails/app/USAGE
  59. +3 −2 railties/lib/rails/initializable.rb
  60. +66 −9 railties/test/application/assets_test.rb
  61. +14 −0 railties/test/application/middleware/cache_test.rb
  62. +2 −2 railties/test/initializable_test.rb
View
3  Gemfile
@@ -99,3 +99,6 @@ if ENV['ORACLE_ENHANCED_PATH'] || ENV['ORACLE_ENHANCED']
gem "activerecord-oracle_enhanced-adapter", :git => "git://github.com/rsim/oracle-enhanced.git"
end
end
+
+# A gem necessary for ActiveRecord tests with IBM DB
+gem "ibm_db" if ENV['IBM_DB']
View
22 actionpack/actionpack.gemspec
@@ -16,16 +16,16 @@ Gem::Specification.new do |s|
s.require_path = 'lib'
s.requirements << 'none'
- s.add_dependency('activesupport', version)
- s.add_dependency('activemodel', version)
- s.add_dependency('rack-cache', '~> 1.0.3')
- s.add_dependency('builder', '~> 3.0.0')
- s.add_dependency('i18n', '~> 0.6')
- s.add_dependency('rack', '~> 1.3.2')
- s.add_dependency('rack-test', '~> 0.6.1')
- s.add_dependency('journey', '~> 1.0.0')
- s.add_dependency('sprockets', '~> 2.0.0')
- s.add_dependency('erubis', '~> 2.7.0')
+ s.add_dependency('activesupport', version)
+ s.add_dependency('activemodel', version)
+ s.add_dependency('rack-cache', '~> 1.1')
+ s.add_dependency('builder', '~> 3.0.0')
+ s.add_dependency('i18n', '~> 0.6')
+ s.add_dependency('rack', '~> 1.3.2')
+ s.add_dependency('rack-test', '~> 0.6.1')
+ s.add_dependency('journey', '~> 1.0.0')
+ s.add_dependency('sprockets', '~> 2.0.2')
+ s.add_dependency('erubis', '~> 2.7.0')
- s.add_development_dependency('tzinfo', '~> 0.3.29')
+ s.add_development_dependency('tzinfo', '~> 0.3.29')
end
View
3  actionpack/lib/abstract_controller/asset_paths.rb
@@ -3,7 +3,8 @@ module AssetPaths
extend ActiveSupport::Concern
included do
- config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir, :stylesheets_dir
+ config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir,
+ :stylesheets_dir, :default_asset_host_protocol
end
end
end
View
4 actionpack/lib/abstract_controller/rendering.rb
@@ -120,8 +120,6 @@ def _render_template(options) #:nodoc:
view_renderer.render(view_context, options)
end
- private
-
DEFAULT_PROTECTED_INSTANCE_VARIABLES = %w(
@_action_name @_response_body @_formats @_prefixes @_config
@_view_context_class @_view_renderer @_lookup_context
@@ -139,6 +137,8 @@ def view_assigns
hash
end
+ private
+
# Normalize args and options.
# :api: private
def _normalize_render(*args, &block)
View
20 actionpack/lib/action_controller/test_case.rb
@@ -333,9 +333,21 @@ module Behavior
module ClassMethods
# Sets the controller class name. Useful if the name can't be inferred from test class.
- # Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
+ # Normalizes +controller_class+ before using. Examples:
+ #
+ # tests WidgetController
+ # tests :widget
+ # tests 'widget'
+ #
def tests(controller_class)
- self.controller_class = controller_class
+ case controller_class
+ when String, Symbol
+ self.controller_class = "#{controller_class.to_s.underscore}_controller".camelize.constantize
+ when Class
+ self.controller_class = controller_class
+ else
+ raise ArgumentError, "controller class must be a String, Symbol, or Class"
+ end
end
def controller_class=(new_class)
@@ -352,9 +364,7 @@ def controller_class
end
def determine_default_controller_class(name)
- name.sub(/Test$/, '').constantize
- rescue NameError
- nil
+ name.sub(/Test$/, '').safe_constantize
end
def prepare_controller_class(new_class)
View
10 actionpack/lib/action_dispatch/http/url.rb
@@ -64,14 +64,16 @@ def rewrite_authentication(options)
end
def host_or_subdomain_and_domain(options)
- return options[:host] unless options[:subdomain] || options[:domain]
+ return options[:host] if options[:subdomain].nil? && options[:domain].nil?
tld_length = options[:tld_length] || @@tld_length
host = ""
- host << (options[:subdomain] || extract_subdomain(options[:host], tld_length))
- host << "."
- host << (options[:domain] || extract_domain(options[:host], tld_length))
+ unless options[:subdomain] == false
+ host << (options[:subdomain] || extract_subdomain(options[:host], tld_length))
+ host << "."
+ end
+ host << (options[:domain] || extract_domain(options[:host], tld_length))
host
end
end
View
5 actionpack/lib/action_dispatch/routing/url_for.rb
@@ -116,9 +116,10 @@ def url_options
# If <tt>:only_path</tt> is false, this option must be
# provided either explicitly, or via +default_url_options+.
# * <tt>:subdomain</tt> - Specifies the subdomain of the link, using the +tld_length+
- # to split the domain from the host.
- # * <tt>:domain</tt> - Specifies the domain of the link, using the +tld_length+
# to split the subdomain from the host.
+ # If false, removes all subdomains from the host part of the link.
+ # * <tt>:domain</tt> - Specifies the domain of the link, using the +tld_length+
+ # to split the domain from the host.
# * <tt>:tld_length</tt> - Number of labels the TLD id composed of, only used if
# <tt>:subdomain</tt> or <tt>:domain</tt> are supplied. Defaults to
# <tt>ActionDispatch::Http::URL.tld_length</tt>, which in turn defaults to 1.
View
7 actionpack/lib/action_dispatch/testing/test_process.rb
@@ -5,12 +5,7 @@
module ActionDispatch
module TestProcess
def assigns(key = nil)
- assigns = {}.with_indifferent_access
- @controller.instance_variable_names.each do |ivar|
- next if ActionController::Base.protected_instance_variables.include?(ivar)
- assigns[ivar[1..-1]] = @controller.instance_variable_get(ivar)
- end
-
+ assigns = @controller.view_assigns.with_indifferent_access
key.nil? ? assigns : assigns[key]
end
View
21 actionpack/lib/action_view/asset_paths.rb
@@ -16,8 +16,6 @@ def initialize(config, controller = nil)
# roots. Rewrite the asset path for cache-busting asset ids. Include
# asset host, if configured, with the correct request protocol.
#
- # When include_host is true and the asset host does not specify the protocol
- # the protocol parameter specifies how the protocol will be added.
# When :relative (default), the protocol will be determined by the client using current protocol
# When :request, the protocol will be the request protocol
# Otherwise, the protocol is used (E.g. :http, :https, etc)
@@ -25,11 +23,10 @@ def compute_public_path(source, dir, options = {})
source = source.to_s
return source if is_uri?(source)
- options[:include_host] ||= true
source = rewrite_extension(source, dir, options[:ext]) if options[:ext]
source = rewrite_asset_path(source, dir, options)
source = rewrite_relative_url_root(source, relative_url_root)
- source = rewrite_host_and_protocol(source, options[:protocol]) if options[:include_host]
+ source = rewrite_host_and_protocol(source, options[:protocol])
source
end
@@ -89,9 +86,7 @@ def compute_protocol(protocol)
end
def default_protocol
- protocol = @config.action_controller.default_asset_host_protocol if @config.action_controller.present?
- protocol ||= @config.default_asset_host_protocol
- protocol || (has_request? ? :request : :relative)
+ @config.default_asset_host_protocol || (has_request? ? :request : :relative)
end
def invalid_asset_host!(help_message)
@@ -120,19 +115,11 @@ def compute_asset_host(source)
end
def relative_url_root
- if config.action_controller.present?
- config.action_controller.relative_url_root
- else
- config.relative_url_root
- end
+ config.relative_url_root
end
def asset_host_config
- if config.action_controller.present?
- config.action_controller.asset_host
- else
- config.asset_host
- end
+ config.asset_host
end
# Returns the current request if one exists.
View
2  actionpack/lib/action_view/test_case.rb
@@ -63,7 +63,7 @@ def helper_method(*methods)
methods.flatten.each do |method|
_helpers.module_eval <<-end_eval
def #{method}(*args, &block) # def current_user(*args, &block)
- _test_case.send(%(#{method}), *args, &block) # test_case.send(%(current_user), *args, &block)
+ _test_case.send(%(#{method}), *args, &block) # _test_case.send(%(current_user), *args, &block)
end # end
end_eval
end
View
107 actionpack/lib/sprockets/assets.rake
@@ -1,60 +1,95 @@
+require "fileutils"
+
namespace :assets do
+ def ruby_rake_task(task)
+ env = ENV['RAILS_ENV'] || 'production'
+ groups = ENV['RAILS_GROUPS'] || 'assets'
+ args = [$0, task,"RAILS_ENV=#{env}","RAILS_GROUPS=#{groups}"]
+ args << "--trace" if Rake.application.options.trace
+ ruby *args
+ end
+
+ # We are currently running with no explicit bundler group
+ # and/or no explicit environment - we have to reinvoke rake to
+ # execute this task.
+ def invoke_or_reboot_rake_task(task)
+ if ENV['RAILS_GROUPS'].to_s.empty? || ENV['RAILS_ENV'].to_s.empty?
+ ruby_rake_task task
+ else
+ Rake::Task[task].invoke
+ end
+ end
+
desc "Compile all the assets named in config.assets.precompile"
task :precompile do
- # We need to do this dance because RAILS_GROUPS is used
- # too early in the boot process and changing here is already too late.
- if ENV["RAILS_GROUPS"].to_s.empty? || ENV["RAILS_ENV"].to_s.empty?
- ENV["RAILS_GROUPS"] ||= "assets"
- ENV["RAILS_ENV"] ||= "production"
- ruby $0, *ARGV
- else
- require "fileutils"
- Rake::Task["tmp:cache:clear"].invoke
- Rake::Task["assets:environment"].invoke
+ invoke_or_reboot_rake_task "assets:precompile:all"
+ end
+ namespace :precompile do
+ def internal_precompile(digest=nil)
unless Rails.application.config.assets.enabled
- raise "Cannot precompile assets if sprockets is disabled. Please set config.assets.enabled to true"
+ warn "Cannot precompile assets if sprockets is disabled. Please set config.assets.enabled to true"
+ exit
end
- # Ensure that action view is loaded and the appropriate sprockets hooks get executed
+ # Ensure that action view is loaded and the appropriate
+ # sprockets hooks get executed
_ = ActionView::Base
config = Rails.application.config
config.assets.compile = true
- config.assets.digest = false if ENV["RAILS_ASSETS_NONDIGEST"]
-
- env = Rails.application.assets
-
- # Always compile files and avoid use of existing precompiled assets
- config.assets.compile = true
+ config.assets.digest = digest unless digest.nil?
config.assets.digests = {}
- target = File.join(Rails.public_path, config.assets.prefix)
- static_compiler = Sprockets::StaticCompiler.new(env, target, :digest => config.assets.digest)
+ env = Rails.application.assets
+ target = File.join(Rails.public_path, config.assets.prefix)
+ compiler = Sprockets::StaticCompiler.new(env,
+ target,
+ config.assets.precompile,
+ :manifest_path => config.assets.manifest,
+ :digest => config.assets.digest,
+ :manifest => digest.nil?)
+ compiler.compile
+ end
- manifest = static_compiler.precompile(config.assets.precompile)
- manifest_path = config.assets.manifest || target
- FileUtils.mkdir_p(manifest_path)
+ task :all do
+ Rake::Task["assets:precompile:primary"].invoke
+ # We need to reinvoke in order to run the secondary digestless
+ # asset compilation run - a fresh Sprockets environment is
+ # required in order to compile digestless assets as the
+ # environment has already cached the assets on the primary
+ # run.
+ ruby_rake_task "assets:precompile:nondigest" if Rails.application.config.assets.digest
+ end
- unless ENV["RAILS_ASSETS_NONDIGEST"]
- File.open("#{manifest_path}/manifest.yml", 'wb') do |f|
- YAML.dump(manifest, f)
- end
- ENV["RAILS_ASSETS_NONDIGEST"] = "true"
- ruby $0, *ARGV
- end
+ task :primary => ["assets:environment", "tmp:cache:clear"] do
+ internal_precompile
+ end
+
+ task :nondigest => ["assets:environment", "tmp:cache:clear"] do
+ internal_precompile(false)
end
end
desc "Remove compiled assets"
- task :clean => ['assets:environment', 'tmp:cache:clear'] do
- config = Rails.application.config
- public_asset_path = File.join(Rails.public_path, config.assets.prefix)
- rm_rf public_asset_path, :secure => true
+ task :clean do
+ invoke_or_reboot_rake_task "assets:clean:all"
+ end
+
+ namespace :clean do
+ task :all => ["assets:environment", "tmp:cache:clear"] do
+ config = Rails.application.config
+ public_asset_path = File.join(Rails.public_path, config.assets.prefix)
+ rm_rf public_asset_path, :secure => true
+ end
end
task :environment do
- Rails.application.initialize!(:assets)
- Sprockets::Bootstrap.new(Rails.application).run
+ if Rails.application.config.assets.initialize_on_precompile
+ Rake::Task["environment"].invoke
+ else
+ Rails.application.initialize!(:assets)
+ Sprockets::Bootstrap.new(Rails.application).run
+ end
end
end
View
3  actionpack/lib/sprockets/helpers.rb
@@ -1,5 +1,6 @@
module Sprockets
module Helpers
- autoload :RailsHelper, "sprockets/helpers/rails_helper"
+ autoload :RailsHelper, "sprockets/helpers/rails_helper"
+ autoload :IsolatedHelper, "sprockets/helpers/isolated_helper"
end
end
View
13 actionpack/lib/sprockets/helpers/isolated_helper.rb
@@ -0,0 +1,13 @@
+module Sprockets
+ module Helpers
+ module IsolatedHelper
+ def controller
+ nil
+ end
+
+ def config
+ Rails.application.config.action_controller
+ end
+ end
+ end
+end
View
3  actionpack/lib/sprockets/helpers/rails_helper.rb
@@ -8,9 +8,6 @@ module RailsHelper
def asset_paths
@asset_paths ||= begin
- config = self.config if respond_to?(:config)
- config ||= Rails.application.config
- controller = self.controller if respond_to?(:controller)
paths = RailsHelper::AssetPaths.new(config, controller)
paths.asset_environment = asset_environment
paths.asset_digests = asset_digests
View
8 actionpack/lib/sprockets/railtie.rb
@@ -1,3 +1,5 @@
+require "action_controller/railtie"
+
module Sprockets
autoload :Bootstrap, "sprockets/bootstrap"
autoload :Helpers, "sprockets/helpers"
@@ -8,13 +10,13 @@ module Sprockets
# TODO: Get rid of config.assets.enabled
class Railtie < ::Rails::Railtie
- config.default_asset_host_protocol = :relative
+ config.action_controller.default_asset_host_protocol = :relative
rake_tasks do
load "sprockets/assets.rake"
end
- initializer "sprockets.environment", :group => :assets do |app|
+ initializer "sprockets.environment", :group => :all do |app|
config = app.config
next unless config.assets.enabled
@@ -41,8 +43,8 @@ class Railtie < ::Rails::Railtie
ActiveSupport.on_load(:action_view) do
include ::Sprockets::Helpers::RailsHelper
-
app.assets.context_class.instance_eval do
+ include ::Sprockets::Helpers::IsolatedHelper
include ::Sprockets::Helpers::RailsHelper
end
end
View
49 actionpack/lib/sprockets/static_compiler.rb
@@ -2,41 +2,50 @@
module Sprockets
class StaticCompiler
- attr_accessor :env, :target, :digest
+ attr_accessor :env, :target, :paths
- def initialize(env, target, options = {})
+ def initialize(env, target, paths, options = {})
@env = env
@target = target
+ @paths = paths
@digest = options.key?(:digest) ? options.delete(:digest) : true
+ @manifest = options.key?(:manifest) ? options.delete(:manifest) : true
+ @manifest_path = options.delete(:manifest_path) || target
end
- def precompile(paths)
- Rails.application.config.assets.digest = digest
+ def compile
manifest = {}
-
env.each_logical_path do |logical_path|
- next unless precompile_path?(logical_path, paths)
+ next unless compile_path?(logical_path)
if asset = env.find_asset(logical_path)
- manifest[logical_path] = compile(asset)
+ manifest[logical_path] = write_asset(asset)
end
end
- manifest
+ write_manifest(manifest) if @manifest
end
- def compile(asset)
- asset_path = digest_asset(asset)
- filename = File.join(target, asset_path)
- FileUtils.mkdir_p File.dirname(filename)
- asset.write_to(filename)
- asset.write_to("#{filename}.gz") if filename.to_s =~ /\.(css|js)$/
- asset_path
+ def write_manifest(manifest)
+ FileUtils.mkdir_p(@manifest_path)
+ File.open("#{@manifest_path}/manifest.yml", 'wb') do |f|
+ YAML.dump(manifest, f)
+ end
+ end
+
+ def write_asset(asset)
+ path_for(asset).tap do |path|
+ filename = File.join(target, path)
+ FileUtils.mkdir_p File.dirname(filename)
+ asset.write_to(filename)
+ asset.write_to("#{filename}.gz") if filename.to_s =~ /\.(css|js)$/
+ end
end
- def precompile_path?(logical_path, paths)
+ def compile_path?(logical_path)
paths.each do |path|
- if path.is_a?(Regexp)
+ case path
+ when Regexp
return true if path.match(logical_path)
- elsif path.is_a?(Proc)
+ when Proc
return true if path.call(logical_path)
else
return true if File.fnmatch(path.to_s, logical_path)
@@ -45,8 +54,8 @@ def precompile_path?(logical_path, paths)
false
end
- def digest_asset(asset)
- digest ? asset.digest_path : asset.logical_path
+ def path_for(asset)
+ @digest ? asset.digest_path : asset.logical_path
end
end
end
View
36 actionpack/test/controller/test_test.rb
@@ -146,6 +146,17 @@ def setup
end
end
+ class ViewAssignsController < ActionController::Base
+ def test_assigns
+ @foo = "foo"
+ render :nothing => true
+ end
+
+ def view_assigns
+ { "bar" => "bar" }
+ end
+ end
+
def test_raw_post_handling
params = ActiveSupport::OrderedHash[:page, {:name => 'page name'}, 'some key', 123]
post :render_raw_post, params.dup
@@ -256,6 +267,15 @@ def test_assigns
assert_equal "foo", assigns["foo"]
end
+ def test_view_assigns
+ @controller = ViewAssignsController.new
+ process :test_assigns
+ assert_equal nil, assigns(:foo)
+ assert_equal nil, assigns[:foo]
+ assert_equal "bar", assigns(:bar)
+ assert_equal "bar", assigns[:bar]
+ end
+
def test_assert_tag_tag
process :test_html_output
@@ -754,6 +774,22 @@ def test_controller_class_can_be_set_manually_not_just_inferred
end
end
+class CrazySymbolNameTest < ActionController::TestCase
+ tests :content
+
+ def test_set_controller_class_using_symbol
+ assert_equal ContentController, self.class.controller_class
+ end
+end
+
+class CrazyStringNameTest < ActionController::TestCase
+ tests 'content'
+
+ def test_set_controller_class_using_string
+ assert_equal ContentController, self.class.controller_class
+ end
+end
+
class NamedRoutesControllerTest < ActionController::TestCase
tests ContentController
View
14 actionpack/test/controller/url_for_test.rb
@@ -67,6 +67,20 @@ def test_subdomain_may_be_changed
)
end
+ def test_subdomain_may_be_removed
+ add_host!
+ assert_equal('http://basecamphq.com/c/a/i',
+ W.new.url_for(:subdomain => false, :controller => 'c', :action => 'a', :id => 'i')
+ )
+ end
+
+ def test_multiple_subdomains_may_be_removed
+ W.default_url_options[:host] = 'mobile.www.api.basecamphq.com'
+ assert_equal('http://basecamphq.com/c/a/i',
+ W.new.url_for(:subdomain => false, :controller => 'c', :action => 'a', :id => 'i')
+ )
+ end
+
def test_domain_may_be_changed
add_host!
assert_equal('http://www.37signals.com/c/a/i',
View
1  actionpack/test/dispatch/request_test.rb
@@ -15,6 +15,7 @@ def url_for(options = {})
assert_equal 'http://www.example.com', url_for
assert_equal 'http://api.example.com', url_for(:subdomain => 'api')
+ assert_equal 'http://example.com', url_for(:subdomain => false)
assert_equal 'http://www.ror.com', url_for(:domain => 'ror.com')
assert_equal 'http://api.ror.co.uk', url_for(:host => 'www.ror.co.uk', :subdomain => 'api', :tld_length => 2)
assert_equal 'http://www.example.com:8080', url_for(:port => 8080)
View
3  actionpack/test/template/compressors_test.rb
@@ -1,6 +1,5 @@
require 'abstract_unit'
-require 'rails/railtie'
-require 'sprockets/railtie'
+require 'sprockets/compressors'
class CompressorsTest < ActiveSupport::TestCase
def test_register_css_compressor
View
21 actionpack/test/template/sprockets_helper_test.rb
@@ -28,7 +28,6 @@ def setup
application = Struct.new(:config, :assets).new(config, @assets)
Rails.stubs(:application).returns(application)
@config = config
- @config.action_controller ||= ActiveSupport::InheritableOptions.new
@config.perform_caching = true
@config.assets.digest = true
@config.assets.compile = true
@@ -38,6 +37,10 @@ def url_for(*args)
"http://www.example.com"
end
+ def config
+ @controller ? @controller.config : @config
+ end
+
test "asset_path" do
assert_match %r{/assets/logo-[0-9a-f]+.png},
asset_path("logo.png")
@@ -75,8 +78,9 @@ def url_for(*args)
end
test "with a simple asset host the url should default to protocol relative" do
+ @controller.config.default_asset_host_protocol = :relative
@controller.config.asset_host = "assets-%d.example.com"
- assert_match %r{//assets-\d.example.com/assets/logo-[0-9a-f]+.png},
+ assert_match %r{^//assets-\d.example.com/assets/logo-[0-9a-f]+.png},
asset_path("logo.png")
end
@@ -88,10 +92,11 @@ def url_for(*args)
end
test "With a proc asset host that returns no protocol the url should be protocol relative" do
+ @controller.config.default_asset_host_protocol = :relative
@controller.config.asset_host = Proc.new do |asset|
"assets-999.example.com"
end
- assert_match %r{//assets-999.example.com/assets/logo-[0-9a-f]+.png},
+ assert_match %r{^//assets-999.example.com/assets/logo-[0-9a-f]+.png},
asset_path("logo.png")
end
@@ -114,7 +119,7 @@ def url_for(*args)
test "stylesheets served without a controller in scope cannot access the request" do
@controller = nil
- @config.action_controller.asset_host = Proc.new do |asset, request|
+ @config.asset_host = Proc.new do |asset, request|
fail "This should not have been called."
end
assert_raises ActionController::RoutingError do
@@ -152,9 +157,9 @@ def url_for(*args)
test "stylesheets served without a controller in do not use asset hosts when the default protocol is :request" do
@controller = nil
- @config.action_controller.asset_host = "assets-%d.example.com"
- @config.action_controller.default_asset_host_protocol = :request
- @config.action_controller.perform_caching = true
+ @config.asset_host = "assets-%d.example.com"
+ @config.default_asset_host_protocol = :request
+ @config.perform_caching = true
assert_match %r{/assets/logo-[0-9a-f]+.png},
asset_path("logo.png")
@@ -168,7 +173,7 @@ def url_for(*args)
test "asset path with relative url root when controller isn't present but relative_url_root is" do
@controller = nil
- @config.action_controller.relative_url_root = "/collaboration/hieraki"
+ @config.relative_url_root = "/collaboration/hieraki"
assert_equal "/collaboration/hieraki/images/logo.gif",
asset_path("/images/logo.gif")
end
View
6 activemodel/lib/active_model/attribute_methods.rb
@@ -93,10 +93,10 @@ module ClassMethods
#
# Provides you with:
#
- # AttributePerson.primary_key
+ # Person.primary_key
# # => "sysid"
- # AttributePerson.inheritance_column = 'address'
- # AttributePerson.inheritance_column
+ # Person.inheritance_column = 'address'
+ # Person.inheritance_column
# # => 'address_id'
def define_attr_method(name, value=nil, &block)
sing = singleton_class
View
4 activemodel/lib/active_model/serializers/json.rb
@@ -15,7 +15,7 @@ module JSON
self.include_root_in_json = true
end
- # Returns a JSON string representing the model. Some configuration can be
+ # Returns a hash representing the model. Some configuration can be
# passed through +options+.
#
# The option <tt>include_root_in_json</tt> controls the top-level behavior
@@ -42,7 +42,7 @@ module JSON
# The remainder of the examples in this section assume include_root_in_json is set to
# <tt>false</tt>.
#
- # Without any +options+, the returned JSON string will include all the model's
+ # Without any +options+, the returned Hash will include all the model's
# attributes. For example:
#
# user = User.find(1)
View
7 activerecord/lib/active_record/attribute_methods/primary_key.rb
@@ -14,6 +14,8 @@ module ClassMethods
# primary_key_prefix_type setting, though.
def primary_key
@primary_key ||= reset_primary_key
+ raise ActiveRecord::UnknownPrimaryKey.new(self) unless @primary_key
+ @primary_key
end
# Returns a quoted version of the primary key name, used to construct SQL statements.
@@ -29,6 +31,11 @@ def reset_primary_key #:nodoc:
key
end
+ def primary_key? #:nodoc:
+ @primary_key ||= reset_primary_key
+ !@primary_key.nil?
+ end
+
def get_primary_key(base_name) #:nodoc:
return 'id' unless base_name && !base_name.blank?
View
6 activerecord/lib/active_record/attribute_methods/read.rb
@@ -40,7 +40,7 @@ def define_method_attribute(attr_name)
define_read_method(attr_name, attr_name, columns_hash[attr_name])
end
- if attr_name == primary_key && attr_name != "id"
+ if primary_key? && attr_name == primary_key && attr_name != "id"
define_read_method('id', attr_name, columns_hash[attr_name])
end
end
@@ -63,7 +63,7 @@ def define_read_method(method_name, attr_name, column)
cast_code = column.type_cast_code('v')
access_code = "(v=@attributes['#{attr_name}']) && #{cast_code}"
- unless attr_name.to_s == self.primary_key.to_s
+ unless primary_key? && attr_name.to_s == primary_key.to_s
access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless @attributes.has_key?('#{attr_name}'); ")
end
@@ -107,7 +107,7 @@ def read_attribute(attr_name)
def _read_attribute(attr_name)
attr_name = attr_name.to_s
- attr_name = self.class.primary_key if attr_name == 'id'
+ attr_name = self.class.primary_key? && self.class.primary_key if attr_name == 'id'
value = @attributes[attr_name]
unless value.nil?
if column = column_for_attribute(attr_name)
View
2  activerecord/lib/active_record/attribute_methods/write.rb
@@ -18,7 +18,7 @@ def define_method_attribute=(attr_name)
end
end
- if attr_name == primary_key && attr_name != "id"
+ if primary_key? && attr_name == primary_key && attr_name != "id"
generated_attribute_methods.module_eval("alias :id= :'#{primary_key}='")
end
end
View
9 activerecord/lib/active_record/base.rb
@@ -708,7 +708,7 @@ def table_exists?
# Returns an array of column objects for the table associated with this class.
def columns
if defined?(@primary_key)
- connection_pool.primary_keys[table_name] ||= primary_key
+ connection_pool.primary_keys[table_name] ||= @primary_key
end
connection_pool.columns[table_name]
@@ -953,7 +953,7 @@ def before_remove_const #:nodoc:
# objects of different types from the same table.
def instantiate(record)
sti_class = find_sti_class(record[inheritance_column])
- record_id = sti_class.primary_key && record[sti_class.primary_key]
+ record_id = sti_class.primary_key? && record[sti_class.primary_key]
if ActiveRecord::IdentityMap.enabled? && record_id
if (column = sti_class.columns_hash[sti_class.primary_key]) && column.number?
@@ -1941,8 +1941,9 @@ def ensure_proper_type
# The primary key and inheritance column can never be set by mass-assignment for security reasons.
def self.attributes_protected_by_default
- default = [ primary_key, inheritance_column ]
- default << 'id' unless primary_key.eql? 'id'
+ default = [ inheritance_column ]
+ default << primary_key if primary_key?
+ default << 'id' unless primary_key? && primary_key == 'id'
default
end
View
14 activerecord/lib/active_record/errors.rb
@@ -169,4 +169,18 @@ def initialize(errors)
@errors = errors
end
end
+
+ # Raised when a model attempts to fetch its primary key from the database, but the table
+ # has no primary key declared.
+ class UnknownPrimaryKey < ActiveRecordError
+ attr_reader :model
+
+ def initialize(model)
+ @model = model
+ end
+
+ def message
+ "Unknown primary key for table #{model.table_name} in model #{model}."
+ end
+ end
end
View
2  activerecord/lib/active_record/fixtures.rb
@@ -622,7 +622,7 @@ def table_rows
private
def primary_key_name
- @primary_key_name ||= model_class && model_class.primary_key
+ @primary_key_name ||= model_class && model_class.primary_key? && model_class.primary_key
end
def has_primary_key_column?
View
2  activerecord/lib/active_record/persistence.rb
@@ -314,7 +314,7 @@ def create
new_id = self.class.unscoped.insert attributes_values
- self.id ||= new_id if self.class.primary_key
+ self.id ||= new_id if self.class.primary_key?
IdentityMap.add(self) if IdentityMap.enabled?
@new_record = false
View
2  activerecord/lib/active_record/railties/databases.rake
@@ -341,7 +341,7 @@ db_namespace = namespace :db do
namespace :schema do
desc 'Create a db/schema.rb file that can be portably used against any DB supported by AR'
- task :dump => :load_config do
+ task :dump => [:environment, :load_config] do
require 'active_record/schema_dumper'
filename = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
File.open(filename, "w:utf-8") do |file|
View
6 activerecord/lib/active_record/relation.rb
@@ -13,7 +13,7 @@ class Relation
# These are explicitly delegated to improve performance (avoids method_missing)
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to => :to_a
- delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key, :connection, :column_hash,:to => :klass
+ delegate :table_name, :quoted_table_name, :primary_key, :primary_key?, :quoted_primary_key, :connection, :column_hash,:to => :klass
attr_reader :table, :klass, :loaded
attr_accessor :extensions, :default_scoped
@@ -36,7 +36,7 @@ def initialize(klass, table)
def insert(values)
primary_key_value = nil
- if primary_key && Hash === values
+ if primary_key? && Hash === values
primary_key_value = values[values.keys.find { |k|
k.name == primary_key
}]
@@ -70,7 +70,7 @@ def insert(values)
conn.insert(
im,
'SQL',
- primary_key,
+ primary_key? && primary_key,
primary_key_value,
nil,
binds)
View
2  activerecord/lib/active_record/transactions.rb
@@ -303,7 +303,7 @@ def with_transaction_returning_status
# Save the new record state and id of a record so it can be restored later if a transaction fails.
def remember_transaction_record_state #:nodoc
@_start_transaction_state ||= {}
- @_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key)
+ @_start_transaction_state[:id] = id if self.class.primary_key?
unless @_start_transaction_state.include?(:new_record)
@_start_transaction_state[:new_record] = @new_record
end
View
4 activerecord/test/cases/attribute_methods/read_test.rb
@@ -24,6 +24,10 @@ def self.column_names
def self.primary_key
end
+ def self.primary_key?
+ false
+ end
+
def self.columns
column_names.map { FakeColumn.new(name) }
end
View
4 activerecord/test/cases/base_test.rb
@@ -97,10 +97,6 @@ def test_columns_should_obey_set_primary_key
assert pk.primary, 'nick should be primary key'
end
- def test_primary_key_with_no_id
- assert_nil Edge.primary_key
- end
-
unless current_adapter?(:PostgreSQLAdapter,:OracleAdapter,:SQLServerAdapter)
def test_limit_with_comma
assert_nothing_raised do
View
14 activerecord/test/cases/primary_keys_test.rb
@@ -5,6 +5,7 @@
require 'models/movie'
require 'models/keyboard'
require 'models/mixed_case_monkey'
+require 'models/edge'
class PrimaryKeysTest < ActiveRecord::TestCase
fixtures :topics, :subscribers, :movies, :mixed_case_monkeys
@@ -161,4 +162,17 @@ def test_set_primary_key_with_no_connection
assert_equal 'foo', model.primary_key
end
+
+ def test_no_primary_key_raises
+ assert_raises(ActiveRecord::UnknownPrimaryKey) do
+ Edge.primary_key
+ end
+
+ begin
+ Edge.primary_key
+ rescue ActiveRecord::UnknownPrimaryKey => e
+ assert e.message.include?('edges')
+ assert e.message.include?('Edge')
+ end
+ end
end
View
2  activerecord/test/config.example.yml
@@ -37,11 +37,13 @@ connections:
db2:
arunit:
+ adapter: ibm_db
host: localhost
username: arunit
password: arunit
database: arunit
arunit2:
+ adapter: ibm_db
host: localhost
username: arunit
password: arunit
View
1  activesupport/lib/active_support/cache/file_store.rb
@@ -161,6 +161,7 @@ def ensure_cache_path(path)
end
def search_dir(dir, &callback)
+ return if !File.exist?(dir)
Dir.foreach(dir) do |d|
next if d == "." || d == ".."
name = File.join(dir, d)
View
2  activesupport/lib/active_support/core_ext/range/conversions.rb
@@ -7,7 +7,7 @@ class Range
#
# ==== Example
#
- # [1..100].to_formatted_s # => "1..100"
+ # (1..100).to_formatted_s # => "1..100"
def to_formatted_s(format = :default)
if formatter = RANGE_FORMATS[format]
formatter.call(first, last)
View
24 activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -75,7 +75,7 @@ def html_safe?
module ActiveSupport #:nodoc:
class SafeBuffer < String
- UNSAFE_STRING_METHODS = ["capitalize", "chomp", "chop", "delete", "downcase", "gsub", "lstrip", "next", "reverse", "rstrip", "slice", "squeeze", "strip", "sub", "succ", "swapcase", "tr", "tr_s", "upcase"].freeze
+ UNSAFE_STRING_METHODS = ["capitalize", "chomp", "chop", "delete", "downcase", "gsub", "lstrip", "next", "reverse", "rstrip", "slice", "squeeze", "strip", "sub", "succ", "swapcase", "tr", "tr_s", "upcase", "prepend"].freeze
alias_method :original_concat, :concat
private :original_concat
@@ -142,16 +142,18 @@ def to_yaml(*args)
end
UNSAFE_STRING_METHODS.each do |unsafe_method|
- class_eval <<-EOT, __FILE__, __LINE__ + 1
- def #{unsafe_method}(*args, &block) # def capitalize(*args, &block)
- to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)
- end # end
-
- def #{unsafe_method}!(*args) # def capitalize!(*args)
- @dirty = true # @dirty = true
- super # super
- end # end
- EOT
+ if 'String'.respond_to?(unsafe_method)
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
+ def #{unsafe_method}(*args, &block) # def capitalize(*args, &block)
+ to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)
+ end # end
+
+ def #{unsafe_method}!(*args) # def capitalize!(*args)
+ @dirty = true # @dirty = true
+ super # super
+ end # end
+ EOT
+ end
end
protected
View
2  activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -9,7 +9,7 @@ class Time
class << self
# Overriding case equality method so that it returns true for ActiveSupport::TimeWithZone instances
def ===(other)
- other.is_a?(::Time)
+ super || (self == Time && other.is_a?(ActiveSupport::TimeWithZone))
end
# Return the number of days in the given month.
View
8 activesupport/test/caching_test.rb
@@ -566,6 +566,14 @@ def test_key_transformation_max_filename_size
assert path.split('/').all? { |dir_name| dir_name.size <= ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE}
assert_equal 'B', File.basename(path)
end
+
+ # If nothing has been stored in the cache, there is a chance the cache directory does not yet exist
+ # Ensure delete_matched gracefully handles this case
+ def test_delete_matched_when_cache_directory_does_not_exist
+ assert_nothing_raised(Exception) do
+ ActiveSupport::Cache::FileStore.new('/test/cache/directory').delete_matched(/does_not_exist/)
+ end
+ end
end
class MemoryStoreTest < ActiveSupport::TestCase
View
3  activesupport/test/core_ext/time_ext_test.rb
@@ -764,7 +764,10 @@ def test_time_created_with_local_constructor_cannot_represent_times_during_hour_
def test_case_equality
assert Time === Time.utc(2000)
assert Time === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC'])
+ assert Time === Class.new(Time).utc(2000)
assert_equal false, Time === DateTime.civil(2000)
+ assert_equal false, Class.new(Time) === Time.utc(2000)
+ assert_equal false, Class.new(Time) === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC'])
end
def test_all_day
View
2  activesupport/test/rescuable_test.rb
@@ -70,7 +70,7 @@ def sos_cool_error
end
-class RescueableTest < Test::Unit::TestCase
+class RescuableTest < Test::Unit::TestCase
def setup
@stargate = Stargate.new
@cool_stargate = CoolStargate.new
View
5 railties/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.2.0 (unreleased)*
+* Default options to `rails new` can be set in ~/.railsrc [Guillermo Iguaran]
+
* Added destroy alias to Rails engines. [Guillermo Iguaran]
* Added destroy alias for Rails command line. This allows the following: `rails d model post`. [Andrey Ognevsky]
@@ -15,7 +17,8 @@
* Add jquery-rails to Gemfile of plugins, test/dummy app needs it. Closes #3091. [Santiago Pastorino]
-* `rake assets:precompile` loads the application but does not initialize it.
+* Add config.assets.initialize_on_precompile which, when set to false, forces
+ `rake assets:precompile` to load the application but does not initialize it.
To the app developer, this means configuration add in
config/initializers/* will not be executed.
View
57 railties/guides/source/active_record_basics.textile
@@ -38,47 +38,48 @@ When writing applications using other programming languages or frameworks, it ma
h4. Naming Conventions
-By default, Active Record uses some naming conventions to find out how the mapping between models and database tables should be created. Rails will pluralize your class names to find the respective database table. So, for a class +Book+, you should have a database table called *books*. The Rails pluralization mechanisms are very powerful, being capable to pluralize (and singularize) both regular and irregular words. When using class names composed of two or more words, the model class name should follow the Ruby conventions, using the camelCase form, while the table name must contain the words separated by underscores. Examples:
+By default, Active Record uses some naming conventions to find out how the mapping between models and database tables should be created. Rails will pluralize your class names to find the respective database table. So, for a class +Book+, you should have a database table called *books*. The Rails pluralization mechanisms are very powerful, being capable to pluralize (and singularize) both regular and irregular words. When using class names composed of two or more words, the model class name should follow the Ruby conventions, using the CamelCase form, while the table name must contain the words separated by underscores. Examples:
-* Database Table - Plural with underscores separating words (e.g., book_clubs)
-* Model Class - Singular with the first letter of each word capitalized (e.g., BookClub)
+* Database Table - Plural with underscores separating words (e.g., +book_clubs+)
+* Model Class - Singular with the first letter of each word capitalized (e.g., +BookClub+)
|_.Model / Class |_.Table / Schema |
-|Post |posts|
-|LineItem |line_items|
-|Deer |deer|
-|Mouse |mice|
-|Person |people|
+|+Post+ |+posts+|
+|+LineItem+ |+line_items+|
+|+Deer+ |+deer+|
+|+Mouse+ |+mice+|
+|+Person+ |+people+|
h4. Schema Conventions
Active Record uses naming conventions for the columns in database tables, depending on the purpose of these columns.
-* *Foreign keys* - These fields should be named following the pattern table_id (e.g., item_id, order_id). These are the fields that Active Record will look for when you create associations between your models.
-* *Primary keys* - By default, Active Record will use an integer column named "id" as the table's primary key. When using "Rails Migrations":migrations.html to create your tables, this column will be automatically created.
+* *Foreign keys* - These fields should be named following the pattern +singularized_table_name_id+ (e.g., +item_id+, +order_id+). These are the fields that Active Record will look for when you create associations between your models.
+* *Primary keys* - By default, Active Record will use an integer column named +id+ as the table's primary key. When using "Rails Migrations":migrations.html to create your tables, this column will be automatically created.
There are also some optional column names that will create additional features to Active Record instances:
-* *created_at* - Automatically gets set to the current date and time when the record is first created.
-* *created_on* - Automatically gets set to the current date when the record is first created.
-* *updated_at* - Automatically gets set to the current date and time whenever the record is updated.
-* *updated_on* - Automatically gets set to the current date whenever the record is updated.
-* *lock_version* - Adds "optimistic locking":http://api.rubyonrails.org/classes/ActiveRecord/Locking.html to a model.
-* *type* - Specifies that the model uses "Single Table Inheritance":http://api.rubyonrails.org/classes/ActiveRecord/Base.html
-* *(table_name)_count* - Used to cache the number of belonging objects on associations. For example, a +comments_count+ column in a +Post+ class that has many instances of +Comment+ will cache the number of existent comments for each post.
+* +created_at+ - Automatically gets set to the current date and time when the record is first created.
+* +created_on+ - Automatically gets set to the current date when the record is first created.
+* +updated_at+ - Automatically gets set to the current date and time whenever the record is updated.
+* +updated_on+ - Automatically gets set to the current date whenever the record is updated.
+* +lock_version+ - Adds "optimistic locking":http://api.rubyonrails.org/classes/ActiveRecord/Locking.html to a model.
+* +type+ - Specifies that the model uses "Single Table Inheritance":http://api.rubyonrails.org/classes/ActiveRecord/Base.html
+* +(table_name)_count+ - Used to cache the number of belonging objects on associations. For example, a +comments_count+ column in a +Post+ class that has many instances of +Comment+ will cache the number of existent comments for each post.
-NOTE: While these column names are optional they are in fact reserved by Active Record. Steer clear of reserved keywords unless you want the extra functionality. For example, "type" is a reserved keyword used to designate a table using Single Table Inheritance. If you are not using STI, try an analogous keyword like "context", that may still accurately describe the data you are modeling.
+NOTE: While these column names are optional, they are in fact reserved by Active Record. Steer clear of reserved keywords unless you want the extra functionality. For example, +type+ is a reserved keyword used to designate a table using Single Table Inheritance (STI). If you are not using STI, try an analogous keyword like "context", that may still accurately describe the data you are modeling.
h3. Creating Active Record Models
-It's very easy to create Active Record models. All you have to do is to subclass the +ActiveRecord::Base+ class and you're good to go:
+It is very easy to create Active Record models. All you have to do is to subclass the +ActiveRecord::Base+ class and you're good to go:
<ruby>
-class Product < ActiveRecord::Base; end
+class Product < ActiveRecord::Base
+end
</ruby>
-This will create a +Product+ model, mapped to a *products* table at the database. By doing this you'll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. So, suppose that the *products* table was created using an SQL sentence like:
+This will create a +Product+ model, mapped to a +products+ table at the database. By doing this you'll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. Suppose that the +products+ table was created using an SQL sentence like:
<sql>
CREATE TABLE products (
@@ -126,21 +127,21 @@ class Product < ActiveRecord::Base
end
</ruby>
-h3. Reading and Writing Data
+h3. CRUD: Reading and Writing Data
CRUD is an acronym for the four verbs we use to operate on data: *C*reate, *R*ead, *U*pdate and *D*elete. Active Record automatically creates methods to allow an application to read and manipulate data stored within its tables.
h4. Create
-Active Record objects can be created from a hash, a block or have its attributes manually set after creation. The _new_ method will return a new object while _create_ will return the object and save it to the database.
+Active Record objects can be created from a hash, a block or have their attributes manually set after creation. The +new+ method will return a new object while +create+ will return the object and save it to the database.
-For example, given a model +User+ with attributes of +name+ and +occupation+, the _create_ method call will create and save a new record into the database:
+For example, given a model +User+ with attributes of +name+ and +occupation+, the +create+ method call will create and save a new record into the database:
<ruby>
user = User.create(:name => "David", :occupation => "Code Artist")
</ruby>
-Using the _new_ method, an object can be created without being saved:
+Using the +new+ method, an object can be created without being saved:
<ruby>
user = User.new
@@ -148,9 +149,9 @@ Using the _new_ method, an object can be created without being saved:
user.occupation = "Code Artist"
</ruby>
-A call to _user.save_ will commit the record to the database.
+A call to +user.save+ will commit the record to the database.
-Finally, passing a block to either create or new will return a new User object:
+Finally, if a block is provided, both +create+ and +new+ will yield the new object to that block for initialization:
<ruby>
user = User.new do |u|
@@ -164,7 +165,7 @@ h4. Read
Active Record provides a rich API for accessing data within a database. Below are a few examples of different data access methods provided by Active Record.
<ruby>
- # return all records
+ # return array with all records
users = User.all
</ruby>
View
2  railties/guides/source/active_record_querying.textile
@@ -616,7 +616,7 @@ c1.first_name = "Michael"
c1.save
c2.name = "should fail"
-c2.save # Raises a ActiveRecord::StaleObjectError
+c2.save # Raises an ActiveRecord::StaleObjectError
</ruby>
You're then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging, or otherwise apply the business logic needed to resolve the conflict.
View
121 railties/guides/source/active_record_validations_callbacks.textile
@@ -28,7 +28,7 @@ h4. Why Use Validations?
Validations are used to ensure that only valid data is saved into your database. For example, it may be important to your application to ensure that every user provides a valid email address and mailing address.
-There are several ways to validate data before it is saved into your database, including native database constraints, client-side validations, controller-level validations, and model-level validations.
+There are several ways to validate data before it is saved into your database, including native database constraints, client-side validations, controller-level validations, and model-level validations:
* Database constraints and/or stored procedures make the validation mechanisms database-dependent and can make testing and maintenance more difficult. However, if your database is used by other applications, it may be a good idea to use some constraints at the database level. Additionally, database-level validations can safely handle some things (such as uniqueness in heavily-used tables) that can be difficult to implement otherwise.
* Client-side validations can be useful, but are generally unreliable if used alone. If they are implemented using JavaScript, they may be bypassed if JavaScript is turned off in the user's browser. However, if combined with other techniques, client-side validation can be a convenient way to provide users with immediate feedback as they use your site.
@@ -94,7 +94,7 @@ Note that +save+ also has the ability to skip validations if passed +:validate =
h4. +valid?+ and +invalid?+
-To verify whether or not an object is valid, Rails uses the +valid?+ method. You can also use this method on your own. +valid?+ triggers your validations and returns true if no errors were added to the object, and false otherwise.
+To verify whether or not an object is valid, Rails uses the +valid?+ method. You can also use this method on your own. +valid?+ triggers your validations and returns true if no errors were found in the object, and false otherwise.
<ruby>
class Person < ActiveRecord::Base
@@ -105,7 +105,7 @@ Person.create(:name => "John Doe").valid? # => true
Person.create(:name => nil).valid? # => false
</ruby>
-When Active Record is performing validations, any errors found can be accessed through the +errors+ instance method. By definition an object is valid if this collection is empty after running validations.
+After Active Record has performed validations, any errors found can be accessed through the +errors+ instance method, which returns a collection of errors. By definition, an object is valid if this collection is empty after running validations.
Note that an object instantiated with +new+ will not report errors even if it's technically invalid, because validations are not run when using +new+.
@@ -139,7 +139,7 @@ end
=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
</ruby>
-+invalid?+ is simply the inverse of +valid?+. +invalid?+ triggers your validations and returns true if any errors were added to the object, and false otherwise.
++invalid?+ is simply the inverse of +valid?+. +invalid?+ triggers your validations, returning true if any errors were found in the object, and false otherwise.
h4(#validations_overview-errors). +errors[]+
@@ -160,7 +160,7 @@ We'll cover validation errors in greater depth in the "Working with Validation E
h3. Validation Helpers
-Active Record offers many pre-defined validation helpers that you can use directly inside your class definitions. These helpers provide common validation rules. Every time a validation fails, an error message is added to the object's +errors+ collection, and this message is associated with the field being validated.
+Active Record offers many pre-defined validation helpers that you can use directly inside your class definitions. These helpers provide common validation rules. Every time a validation fails, an error message is added to the object's +errors+ collection, and this message is associated with the attribute being validated.
Each helper accepts an arbitrary number of attribute names, so with a single line of code you can add the same kind of validation to several attributes.
@@ -428,6 +428,8 @@ class GoodnessValidator < ActiveModel::Validator
end
</ruby>
+NOTE: Errors added to +record.errors[:base]+ relate to the state of the record as a whole, and not to a specific attribute.
+
The +validates_with+ helper takes a class, or a list of classes to use for validation. There is no default error message for +validates_with+. You must manually add errors to the record's errors collection in the validator class.
To implement the validate method, you must have a +record+ parameter defined, which is the record to be validated.
@@ -454,13 +456,13 @@ This helper validates attributes against a block. It doesn't have a predefined v
<ruby>
class Person < ActiveRecord::Base
- validates_each :name, :surname do |model, attr, value|
- model.errors.add(attr, 'must start with upper case') if value =~ /\A[a-z]/
+ validates_each :name, :surname do |record, attr, value|
+ record.errors.add(attr, 'must start with upper case') if value =~ /\A[a-z]/
end
end
</ruby>
-The block receives the model, the attribute's name and the attribute's value. You can do anything you like to check for valid data within the block. If your validation fails, you can add an error message to the model, therefore making it invalid.
+The block receives the record, the attribute's name and the attribute's value. You can do anything you like to check for valid data within the block. If your validation fails, you should add an error message to the model, therefore making it invalid.
h3. Common Validation Options
@@ -580,7 +582,7 @@ Custom validators are classes that extend <tt>ActiveModel::Validator</tt>. These
<ruby>
class MyValidator < ActiveModel::Validator
def validate(record)
- if record.name.starts_with? 'X'
+ unless record.name.starts_with? 'X'
record.errors[:name] << 'Need a name starting with X please!'
end
end
@@ -661,7 +663,7 @@ The following is a list of the most commonly used methods. Please refer to the +
h4(#working_with_validation_errors-errors). +errors+
-Returns an OrderedHash with all errors. Each key is the attribute name and the value is an array of strings with all errors.
+Returns an instance of the class +ActiveModel::Errors+ (which behaves like an ordered hash) containing all errors. Each key is the attribute name and the value is an array of strings with all errors.
<ruby>
class Person < ActiveRecord::Base
@@ -741,7 +743,7 @@ Another way to do this is using +[]=+ setter
h4. +errors[:base]+
-You can add error messages that are related to the object's state as a whole, instead of being related to a specific attribute. You can use this method when you want to say that the object is invalid, no matter the values of its attributes. Since +errors[:base]+ is an array, you can simply add a string to the array and uses it as the error message.
+You can add error messages that are related to the object's state as a whole, instead of being related to a specific attribute. You can use this method when you want to say that the object is invalid, no matter the values of its attributes. Since +errors[:base]+ is an array, you can simply add a string to it and it will be used as an error message.
<ruby>
class Person < ActiveRecord::Base
@@ -785,7 +787,7 @@ end
person = Person.new
person.valid? # => false
-person.errors.size # => 3
+person.errors.size # => 2
person = Person.new(:name => "Andrea", :email => "andrea@example.com")
person.valid? # => true
@@ -794,7 +796,7 @@ person.errors.size # => 0
h3. Displaying Validation Errors in the View
-Rails maintains an official plugin that provides helpers to display the error messages of your models in your view templates. You can install it as a plugin or as a Gem.
+Rails maintains an official plugin, DynamicForm, that provides helpers to display the error messages of your models in your view templates. You can install it as a plugin or as a Gem.
h4. Installing as a plugin
@@ -810,7 +812,7 @@ Add this line in your Gemfile:
gem "dynamic_form"
</ruby>
-Now you will have access to these two methods in your view templates.
+Now you will have access to the two helper methods +error_messages+ and +error_messages_for+ in your view templates.
h4. +error_messages+ and +error_messages_for+
@@ -840,11 +842,13 @@ end
<% end %>
</erb>
-To get the idea, if you submit the form with empty fields you typically get this back, though styles are indeed missing by default:
+If you submit the form with empty fields, the result will be similar to the one shown below:
!images/error_messages.png(Error messages)!
-You can also use the +error_messages_for+ helper to display the error messages of a model assigned to a view template. It's very similar to the previous example and will achieve exactly the same result.
+NOTE: The appearance of the generated HTML will be different from the one shown, unless you have used scaffolding. See "Customizing the Error Messages CSS":#customizing-error-messages-css.
+
+You can also use the +error_messages_for+ helper to display the error messages of a model assigned to a view template. It is very similar to the previous example and will achieve exactly the same result.
<erb>
<%= error_messages_for :product %>
@@ -852,7 +856,7 @@ You can also use the +error_messages_for+ helper to display the error messages o
The displayed text for each error message will always be formed by the capitalized name of the attribute that holds the error, followed by the error message itself.
-Both the +form.error_messages+ and the +error_messages_for+ helpers accept options that let you customize the +div+ element that holds the messages, changing the header text, the message below the header text and the tag used for the element that defines the header.
+Both the +form.error_messages+ and the +error_messages_for+ helpers accept options that let you customize the +div+ element that holds the messages, change the header text, change the message below the header, and specify the tag used for the header element. For example,
<erb>
<%= f.error_messages :header_message => "Invalid product!",
@@ -860,23 +864,23 @@ Both the +form.error_messages+ and the +error_messages_for+ helpers accept optio
:header_tag => :h3 %>
</erb>
-Which results in the following content:
+results in:
!images/customized_error_messages.png(Customized error messages)!
-If you pass +nil+ to any of these options, it will get rid of the respective section of the +div+.
+If you pass +nil+ in any of these options, the corresponding section of the +div+ will be discarded.
-h4. Customizing the Error Messages CSS
+h4(#customizing-error-messages-css). Customizing the Error Messages CSS
-The selectors to customize the style of error messages are:
+The selectors used to customize the style of error messages are:
* +.field_with_errors+ - Style for the form fields and labels with errors.
-* +#errorExplanation+ - Style for the +div+ element with the error messages.
-* +#errorExplanation h2+ - Style for the header of the +div+ element.
-* +#errorExplanation p+ - Style for the paragraph that holds the message that appears right below the header of the +div+ element.
-* +#errorExplanation ul li+ - Style for the list items with individual error messages.
+* +#error_explanation+ - Style for the +div+ element with the error messages.
+* +#error_explanation h2+ - Style for the header of the +div+ element.
+* +#error_explanation p+ - Style for the paragraph holding the message that appears right below the header of the +div+ element.
+* +#error_explanation ul li+ - Style for the list items with individual error messages.
-Scaffolding for example generates +app/assets/stylesheets/scaffold.css.scss+, which later compiles to +app/assets/stylesheets/scaffold.css+ and defines the red-based style you saw above.
+If scaffolding was used, file +app/assets/stylesheets/scaffold.css.scss+ (which later compiles to +app/assets/stylesheets/scaffold.css+), will have been generated automatically. This file defines the red-based styles you saw in the examples above.
The name of the class and the id can be changed with the +:class+ and +:id+ options, accepted by both helpers.
@@ -889,7 +893,7 @@ The way form fields with errors are treated is defined by +ActionView::Base.fiel
* A string with the HTML tag
* An instance of +ActionView::Helpers::InstanceTag+.
-Here is a simple example where we change the Rails behavior to always display the error messages in front of each of the form fields with errors. The error messages will be enclosed by a +span+ element with a +validation-error+ CSS class. There will be no +div+ element enclosing the +input+ element, so we get rid of that red border around the text field. You can use the +validation-error+ CSS class to style it anyway you want.
+Below is a simple example where we change the Rails behavior to always display the error messages in front of each of the form fields in error. The error messages will be enclosed by a +span+ element with a +validation-error+ CSS class. There will be no +div+ element enclosing the +input+ element, so we get rid of that red border around the text field. You can use the +validation-error+ CSS class to style it anyway you want.
<ruby>
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
@@ -903,17 +907,17 @@ ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
end
</ruby>
-This will result in something like the following:
+The result looks like the following:
!images/validation_error_messages.png(Validation error messages)!
h3. Callbacks Overview
-Callbacks are methods that get called at certain moments of an object's life cycle. With callbacks it's possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database.
+Callbacks are methods that get called at certain moments of an object's life cycle. With callbacks it is possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database.
h4. Callback Registration
-In order to use the available callbacks, you need to register them. You can do that by implementing them as ordinary methods, and then using a macro-style class method to register them as callbacks.
+In order to use the available callbacks, you need to register them. You can implement the callbacks as ordinary methods and use a macro-style class method to register them as callbacks:
<ruby>
class User < ActiveRecord::Base
@@ -930,7 +934,7 @@ class User < ActiveRecord::Base
end
</ruby>
-The macro-style class methods can also receive a block. Consider using this style if the code inside your block is so short that it fits in just one line.
+The macro-style class methods can also receive a block. Consider using this style if the code inside your block is so short that it fits in a single line:
<ruby>
class User < ActiveRecord::Base
@@ -942,7 +946,7 @@ class User < ActiveRecord::Base
end
</ruby>
-It's considered good practice to declare callback methods as being protected or private. If left public, they can be called from outside of the model and violate the principle of object encapsulation.
+It is considered good practice to declare callback methods as protected or private. If left public, they can be called from outside of the model and violate the principle of object encapsulation.
h3. Available Callbacks
@@ -982,7 +986,7 @@ The +after_initialize+ callback will be called whenever an Active Record object
The +after_find+ callback will be called whenever Active Record loads a record from the database. +after_find+ is called before +after_initialize+ if both are defined.
-The +after_initialize+ and +after_find+ callbacks are a bit different from the others. They have no +before_*+ counterparts, and the only way to register them is by defining them as regular methods. If you try to register +after_initialize+ or +after_find+ using macro-style class methods, they will just be ignored. This behavior is due to performance reasons, since +after_initialize+ and +after_find+ will both be called for each record found in the database, significantly slowing down the queries.
+The +after_initialize+ and +after_find+ callbacks are a bit different from the others. They have no +before_*+ counterparts, and they are registered simply by defining them as regular methods with predefined names. If you try to register +after_initialize+ or +after_find+ using macro-style class methods, they will just be ignored. This behavior is due to performance reasons, since +after_initialize+ and +after_find+ will both be called for each record found in the database, which would otherwise significantly slow down the queries.
<ruby>
class User < ActiveRecord::Base
@@ -1039,7 +1043,7 @@ The +after_initialize+ callback is triggered every time a new object of the clas
h3. Skipping Callbacks
-Just as with validations, it's also possible to skip callbacks. These methods should be used with caution, however, because important business rules and application logic may be kept in callbacks. Bypassing them without understanding the potential implications may lead to invalid data.
+Just as with validations, it is also possible to skip callbacks. These methods should be used with caution, however, because important business rules and application logic may be kept in callbacks. Bypassing them without understanding the potential implications may lead to invalid data.
* +decrement+
* +decrement_counter+
@@ -1058,13 +1062,13 @@ h3. Halting Execution
As you start registering new callbacks for your models, they will be queued for execution. This queue will include all your model's validations, the registered callbacks, and the database operation to be executed.
-The whole callback chain is wrapped in a transaction. If any <em>before</em> callback method returns exactly +false+ or raises an exception the execution chain gets halted and a ROLLBACK is issued; <em>after</em> callbacks can only accomplish that by raising an exception.
+The whole callback chain is wrapped in a transaction. If any <em>before</em> callback method returns exactly +false+ or raises an exception, the execution chain gets halted and a ROLLBACK is issued; <em>after</em> callbacks can only accomplish that by raising an exception.
-WARNING. Raising an arbitrary exception may break code that expects +save+ and friends not to fail like that. The +ActiveRecord::Rollback+ exception is thought precisely to tell Active Record a rollback is going on. That one is internally captured but not reraised.
+WARNING. Raising an arbitrary exception may break code that expects +save+ and its friends not to fail like that. The +ActiveRecord::Rollback+ exception is thought precisely to tell Active Record a rollback is going on. That one is internally captured but not reraised.
h3. Relational Callbacks
-Callbacks work through model relationships, and can even be defined by them. Let's take an example where a user has many posts. In our example, a user's posts should be destroyed if the user is destroyed. So, we'll add an +after_destroy+ callback to the +User+ model by way of its relationship to the +Post+ model.
+Callbacks work through model relationships, and can even be defined by them. Suppose an example where a user has many posts. A user's posts should be destroyed if the user is destroyed. Let's add an +after_destroy+ callback to the +User+ model by way of its relationship to the +Post+ model:
<ruby>
class User < ActiveRecord::Base
@@ -1090,11 +1094,11 @@ Post destroyed
h3. Conditional Callbacks
-Like in validations, we can also make our callbacks conditional, calling them only when a given predicate is satisfied. You can do that by using the +:if+ and +:unless+ options, which can take a symbol, a string or a +Proc+. You may use the +:if+ option when you want to specify when the callback *should* get called. If you want to specify when the callback *should not* be called, then you may use the +:unless+ option.
+As with validations, we can also make the calling of a callback method conditional on the satisfaction of a given predicate. We can do this using the +:if+ and +:unless+ options, which can take a symbol, a string or a +Proc+. You may use the +:if+ option when you want to specify under which conditions the callback *should* be called. If you want to specify the conditions under which the callback *should not* be called, then you may use the +:unless+ option.
-h4. Using +:if+ and +:unless+ with a Symbol
+h4. Using +:if+ and +:unless+ with a +Symbol+
-You can associate the +:if+ and +:unless+ options with a symbol corresponding to the name of a method that will get called right before the callback. When using the +:if+ option, the callback won't be executed if the method returns false; when using the +:unless+ option, the callback won't be executed if the method returns true. This is the most common option. Using this form of registration it's also possible to register several different methods that should be called to check if the callback should be executed.
+You can associate the +:if+ and +:unless+ options with a symbol corresponding to the name of a predicate method that will get called right before the callback. When using the +:if+ option, the callback won't be executed if the predicate method returns false; when using the +:unless+ option, the callback won't be executed if the predicate method returns true. This is the most common option. Using this form of registration it is also possible to register several different predicates that should be called to check if the callback should be executed.
<ruby>
class Order < ActiveRecord::Base
@@ -1104,7 +1108,7 @@ end
h4. Using +:if+ and +:unless+ with a String
-You can also use a string that will be evaluated using +eval+ and needs to contain valid Ruby code. You should use this option only when the string represents a really short condition.
+You can also use a string that will be evaluated using +eval+ and hence needs to contain valid Ruby code. You should use this option only when the string represents a really short condition:
<ruby>
class Order < ActiveRecord::Base
@@ -1112,9 +1116,9 @@ class Order < ActiveRecord::Base
end
</ruby>
-h4. Using +:if+ and +:unless+ with a Proc
+h4. Using +:if+ and +:unless+ with a +Proc+
-Finally, it's possible to associate +:if+ and +:unless+ with a +Proc+ object. This option is best suited when writing short validation methods, usually one-liners.
+Finally, it is possible to associate +:if+ and +:unless+ with a +Proc+ object. This option is best suited when writing short validation methods, usually one-liners:
<ruby>
class Order < ActiveRecord::Base
@@ -1125,7 +1129,7 @@ end
h4. Multiple Conditions for Callbacks
-When writing conditional callbacks, it's possible to mix both +:if+ and +:unless+ in the same callback declaration.
+When writing conditional callbacks, it is possible to mix both +:if+ and +:unless+ in the same callback declaration:
<ruby>
class Comment < ActiveRecord::Base
@@ -1138,7 +1142,7 @@ h3. Callback Classes
Sometimes the callback methods that you'll write will be useful enough to be reused by other models. Active Record makes it possible to create classes that encapsulate the callback methods, so it becomes very easy to reuse them.
-Here's an example where we create a class with an +after_destroy+ callback for a +PictureFile+ model.
+Here's an example where we create a class with an +after_destroy+ callback for a +PictureFile+ model:
<ruby>
class PictureFileCallbacks
@@ -1150,7 +1154,7 @@ class PictureFileCallbacks
end
</ruby>
-When declared inside a class the callback method will receive the model object as a parameter. We can now use it this way:
+When declared inside a class, as above, the callback methods will receive the model object as a parameter. We can now use the callback class in the model:
<ruby>
class PictureFile < ActiveRecord::Base
@@ -1158,7 +1162,7 @@ class PictureFile < ActiveRecord::Base
end
</ruby>
-Note that we needed to instantiate a new +PictureFileCallbacks+ object, since we declared our callback as an instance method. Sometimes it will make more sense to have it as a class method.
+Note that we needed to instantiate a new +PictureFileCallbacks+ object, since we declared our callback as an instance method. This is particularly useful if the callbacks make use of the state of instantiated object. Often, however, it will make more sense to declare the callbacks as class methods:
<ruby>
class PictureFileCallbacks
@@ -1182,16 +1186,25 @@ You can declare as many callbacks as you want inside your callback classes.
h3. Observers
-Observers are similar to callbacks, but with important differences. Whereas callbacks can pollute a model with code that isn't directly related to its purpose, observers allow you to add the same functionality outside of a model. For example, it could be argued that a +User+ model should not include code to send registration confirmation emails. Whenever you use callbacks with code that isn't directly related to your model, you may want to consider creating an observer instead.
+Observers are similar to callbacks, but with important differences. Whereas callbacks can pollute a model with code that isn't directly related to its purpose, observers allow you to add the same functionality without changing the code of the model. For example, it could be argued that a +User+ model should not include code to send registration confirmation emails. Whenever you use callbacks with code that isn't directly related to your model, you may want to consider creating an observer instead.
h4. Creating Observers
-For example, imagine a +User+ model where we want to send an email every time a new user is created. Because sending emails is not directly related to our model's purpose, we could create an observer to contain this functionality.
+For example, imagine a +User+ model where we want to send an email every time a new user is created. Because sending emails is not directly related to our model's purpose, we should create an observer to contain the code implementing this functionality.
<shell>
$ rails generate observer User
</shell>
+generates +app/models/user_observer.rb+ containing the observer class +UserObserver+:
+
+<ruby>
+class UserObserver < ActiveRecord::Observer
+end
+</ruby>
+
+You may now add methods to be called at the desired occasions:
+
<ruby>
class UserObserver < ActiveRecord::Observer
def after_create(model)
@@ -1207,7 +1220,7 @@ h4. Registering Observers
Observers are conventionally placed inside of your +app/models+ directory and registered in your application's +config/application.rb+ file. For example, the +UserObserver+ above would be saved as +app/models/user_observer.rb+ and registered in +config/application.rb+ this way:
<ruby>
-# Activate observers that should always be running
+# Activate observers that should always be running.
config.active_record.observers = :user_observer
</ruby>
@@ -1215,7 +1228,7 @@ As usual, settings in +config/environments+ take precedence over those in +confi
h4. Sharing Observers
-By default, Rails will simply strip "Observer" from an observer's name to find the model it should observe. However, observers can also be used to add behavior to more than one model, and so it's possible to manually specify the models that our observer should observe.
+By default, Rails will simply strip "Observer" from an observer's name to find the model it should observe. However, observers can also be used to add behavior to more than one model, and thus it is possible to explicitly specify the models that our observer should observe:
<ruby>
class MailerObserver < ActiveRecord::Observer
@@ -1227,10 +1240,10 @@ class MailerObserver < ActiveRecord::Observer
end
</ruby>
-In this example, the +after_create+ method would be called whenever a +Registration+ or +User+ was created. Note that this new +MailerObserver+ would also need to be registered in +config/application.rb+ in order to take effect.
+In this example, the +after_create+ method will be called whenever a +Registration+ or +User+ is created. Note that this new +MailerObserver+ would also need to be registered in +config/application.rb+ in order to take effect:
<ruby>
-# Activate observers that should always be running
+# Activate observers that should always be running.
config.active_record.observers = :mailer_observer
</ruby>
@@ -1238,7 +1251,7 @@ h3. Transaction Callbacks
There are two additional callbacks that are triggered by the completion of a database transaction: +after_commit+ and +after_rollback+. These callbacks are very similar to the +after_save+ callback except that they don't execute until after database changes have either been committed or rolled back. They are most useful when your active record models need to interact with external systems which are not part of the database transaction.
-Consider, for example, the previous example where the +PictureFile+ model needs to delete a file after a record is destroyed. If anything raises an exception after the +after_destroy+ callback is called and the transaction rolls back, the file will have been deleted and the model will be left in an inconsistent state. For example, suppose that +picture_file_2+ in the code below is not valid and the +save!+ method raises an error.
+Consider, for example, the previous example where the +PictureFile+ model needs to delete a file after the corresponding record is destroyed. If anything raises an exception after the +after_destroy+ callback is called and the transaction rolls back, the file will have been deleted and the model will be left in an inconsistent state. For example, suppose that +picture_file_2+ in the code below is not valid and the +save!+ method raises an error.
<ruby>
PictureFile.transaction do
View
9 railties/guides/source/asset_pipeline.textile
@@ -346,6 +346,15 @@ The rake task is:
bundle exec rake assets:precompile
</plain>
+For faster asset precompiles, you can partially load your application by setting
++config.assets.initialize_on_precompile+ to false, 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.
+
Capistrano (v2.8.0 and above) has a recipe to handle this in deployment. Add the following line to +Capfile+:
<erb>
View
18 railties/guides/source/configuring.textile
@@ -179,16 +179,16 @@ h4. Configuring Middleware
Every Rails application comes with a standard set of middleware which it uses in this order in the development environment:
-* +Rack::SSL+ Will force every request to be under HTTPS protocol. Will be available if +config.force_ssl+ is set to +true+. Options passed to this can be configured by using +config.ssl_options+.
+* +Rack::SSL+ forces every request to be under HTTPS protocol. Will be available if +config.force_ssl+ is set to +true+. Options passed to this can be configured by using +config.ssl_options+.
* +ActionDispatch::Static+ is used to serve static assets. Disabled if +config.serve_static_assets+ is +true+.
-* +Rack::Lock+ Will wrap the app in mutex so it can only be called by a single thread at a time. Only enabled if +config.action_controller.allow_concurrency+ is set to +false+, which it is by default.
-* +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.
-* +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::RemoteIp+ Checks for IP spoofing attacks. Configurable with the +config.action_dispatch.ip_spoofing_check+ and +config.action_dispatch.trusted_proxies+ settings.
-* +Rack::Sendfile+ Intercepts responses whose body is being served from a file and replaces it with a server specific X-Sendfile header. Configurable with +config.action_dispatch.x_sendfile_header+.
-* +ActionDispatch::Callbacks+ Runs the prepare callbacks before serving the request.
+* +Rack::Lock+ wraps the app in mutex so it can only be called by a single thread at a time. Only enabled if +config.action_controller.allow_concurrency+ is set to +false+, which it is by default.
+* +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.
+* +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::RemoteIp+ checks for IP spoofing attacks. Configurable with the +config.action_dispatch.ip_spoofing_check+ and +config.action_dispatch.trusted_proxies+ settings.
+* +Rack::Sendfile+ intercepts responses whose body is being served from a file and replaces it with a server specific X-Sendfile header. Configurable with +config.action_dispatch.x_sendfile_header+.
+* +ActionDispatch::Callbacks+ runs the prepare callbacks before serving the request.
* +ActiveRecord::ConnectionAdapters::ConnectionManagement+ cleans active connections after each request, unless the +rack.test+ key in the request environment is set to +true+.
* +ActiveRecord::QueryCache+ caches all SELECT queries generated in a request. If any INSERT or UPDATE takes place then the cache is cleaned.
* +ActionDispatch::Cookies+ sets cookies for the request.
View
36 railties/guides/source/engines.textile
@@ -0,0 +1,36 @@
+h2. Getting Started with Engines
+
+In this guide you will learn about engines and how they can be used to provide additional functionality to their host applications through a clean and very easy-to-use interface. You will learn the following things in this guide:
+
+* What are engines
+* Generating an engine
+* Building features for the engine
+* Hooking the engine into an application
+* Overriding engine functionality in the application
+
+endprologue.
+
+h3. What are engines?
+
+Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a "supercharged" engine, with the `Rails::Application` class inheriting from `Rails::Engine`. Therefore, engines and applications share common functionality but are at the same time two separate beasts.
+
+h3. Generating an engine
+
+TODO: The engine that will be generated for this guide will be called "blorgh". It's a blogging engine that provides posts and comments and that's it.
+
+TODO: Describe here the process of generating an engine and what an engine comes with.
+
+h3. Providing engine functionality
+
+TODO: Brief explanation of what this engine is going to be doing and what we will have once we are done.
+TODO: Generate a posts scaffold (maybe?) for the engine
+TODO: Generate a comments scaffold (maybe?) for the engine
+
+h3. Hooking into application
+
+TODO: Application will provide a User foundation class which the engine hooks into through a configuration setting, configurable in the application's initializers. The engine will be mounted at the +/blog+ path in the application.
+
+h3. Overriding engine functionality
+
+TODO: Cover how to override engine functionality in the engine, such as controllers and views.
+IDEA: I like Devise's +devise :controllers => { "sessions" => "sessions" }+ idea. Perhaps we could incorporate that into the guide?
View
124 railties/guides/source/getting_started.textile
@@ -360,7 +360,7 @@ development:
h5. Configuring an SQLite3 Database for JRuby Platform
-If you choose to use SQLite3 and using JRuby, your +config/database.yml+ will
+If you choose to use SQLite3 and are using JRuby, your +config/database.yml+ will
look a little different. Here's the development section:
<yaml>
@@ -371,7 +371,7 @@ development:
h5. Configuring a MySQL Database for JRuby Platform
-If you choose to use MySQL and using JRuby, your +config/database.yml+ will look
+If you choose to use MySQL and are using JRuby, your +config/database.yml+ will look
a little different. Here's the development section:
<yaml>
@@ -384,7 +384,7 @@ development:
h5. Configuring a PostgreSQL Database for JRuby Platform
-Finally if you choose to use PostgreSQL and using JRuby, your
+Finally if you choose to use PostgreSQL and are using JRuby, your
+config/database.yml+ will look a little different. Here's the development
section:
@@ -599,7 +599,7 @@ The above migration creates a method named +change+ which will be called when yo
run this migration. The action defined in that method is also reversible, which
means Rails knows how to reverse the change made by this migration, in case you
want to reverse it at later date. By default, when you run this migration it
-will creates a +posts+ table with two string columns and a text column. It also
+creates a +posts+ table with two string columns and a text column. It also
creates two timestamp fields to track record creation and updating. More
information about Rails migrations can be found in the "Rails Database
Migrations":migrations.html guide.
@@ -620,9 +620,9 @@ table.
== CreatePosts: migrated (0.0020s) ===========================================
</shell>
-NOTE. Because you're working in the development environment by default, this
+NOTE. Because by default you're working in the development environment, this
command will apply to the database defined in the +development+ section of your
-+config/database.yml+ file. If you would like to execute migrations in other
++config/database.yml+ file. If you would like to execute migrations in another
environment, for instance in production, you must explicitly pass it when
invoking the command: <tt>rake db:migrate RAILS_ENV=production</tt>.
@@ -704,8 +704,8 @@ $ rails console
</shell>
TIP: The default console will make changes to your database. You can instead
-open a console that will roll back any changes you make by using +rails console
---sandbox+.
+open a console that will roll back any changes you make by using <tt>rails console
+--sandbox</tt>.
After the console loads, you can use it to work with your application's models:
@@ -783,7 +783,8 @@ Here's +app/views/posts/index.html.erb+:
<td><%= post.content %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
- <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
+ <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?',
+ :method => :delete %></td>
</tr>
<% end %>
</table>
@@ -867,10 +868,10 @@ The +new.html.erb+ view displays this empty Post to the user:
The +&lt;%= render 'form' %&gt;+ line is our first introduction to _partials_ in
Rails. A partial is a snippet of HTML and Ruby code that can be reused in
-multiple locations. In this case, the form used to make a new post, is basically