aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile7
-rw-r--r--README.rdoc2
-rw-r--r--actionmailer/CHANGELOG2
-rw-r--r--actionpack/CHANGELOG12
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb12
-rw-r--r--actionpack/lib/action_dispatch/routing/route.rb60
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb104
-rw-r--r--actionpack/lib/action_view/asset_paths.rb20
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb4
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb2
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb2
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb4
-rw-r--r--actionpack/lib/sprockets/assets.rake8
-rw-r--r--actionpack/lib/sprockets/helpers/rails_helper.rb28
-rw-r--r--actionpack/lib/sprockets/railtie.rb6
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb16
-rw-r--r--actionpack/test/controller/resources_test.rb2
-rw-r--r--actionpack/test/dispatch/mapper_test.rb1
-rw-r--r--actionpack/test/lib/controller/fake_models.rb11
-rw-r--r--actionpack/test/template/form_helper_test.rb3
-rw-r--r--actionpack/test/template/sprockets_helper_test.rb51
-rw-r--r--activemodel/CHANGELOG2
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb94
-rw-r--r--activemodel/lib/active_model/errors.rb31
-rw-r--r--activemodel/test/cases/attribute_methods_test.rb108
-rw-r--r--activemodel/test/cases/errors_test.rb31
-rw-r--r--activerecord/CHANGELOG10
-rw-r--r--activerecord/lib/active_record/associations.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb84
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb14
-rw-r--r--activerecord/lib/active_record/autosave_association.rb5
-rw-r--r--activerecord/lib/active_record/base.rb4
-rw-r--r--activerecord/lib/active_record/persistence.rb2
-rw-r--r--activerecord/lib/active_record/railties/databases.rake12
-rw-r--r--activerecord/lib/active_record/relation.rb3
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb36
-rw-r--r--activerecord/lib/active_record/timestamp.rb4
-rw-r--r--activerecord/test/cases/attribute_methods/read_test.rb1
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb61
-rw-r--r--activerecord/test/cases/base_test.rb13
-rw-r--r--activerecord/test/cases/persistence_test.rb17
-rw-r--r--activerecord/test/cases/relations_test.rb20
-rw-r--r--activerecord/test/cases/serialization_test.rb13
-rw-r--r--activerecord/test/cases/session_store/session_test.rb2
-rw-r--r--activerecord/test/models/contact.rb13
-rw-r--r--activerecord/test/models/topic.rb9
-rw-r--r--activerecord/test/schema/schema.rb8
-rw-r--r--activeresource/CHANGELOG2
-rw-r--r--activeresource/lib/active_resource/base.rb10
-rw-r--r--activeresource/test/cases/base/load_test.rb4
-rw-r--r--activeresource/test/cases/base_test.rb30
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb2
-rwxr-xr-xbin/rails7
-rw-r--r--rails.gemspec2
-rw-r--r--railties/CHANGELOG2
-rwxr-xr-xrailties/Rakefile9
-rwxr-xr-xrailties/bin/rails7
-rw-r--r--railties/guides/code/getting_started/Gemfile32
-rw-r--r--railties/guides/code/getting_started/README261
-rw-r--r--railties/guides/code/getting_started/Rakefile7
-rw-r--r--railties/guides/code/getting_started/app/assets/images/rails.pngbin0 -> 6646 bytes
-rw-r--r--railties/guides/code/getting_started/app/assets/javascripts/application.js9
-rw-r--r--railties/guides/code/getting_started/app/assets/javascripts/comments.js.coffee3
-rw-r--r--railties/guides/code/getting_started/app/assets/javascripts/home.js.coffee3
-rw-r--r--railties/guides/code/getting_started/app/assets/javascripts/posts.js.coffee3
-rw-r--r--railties/guides/code/getting_started/app/assets/stylesheets/application.css7
-rw-r--r--railties/guides/code/getting_started/app/assets/stylesheets/comments.css.scss3
-rw-r--r--railties/guides/code/getting_started/app/assets/stylesheets/home.css.scss3
-rw-r--r--railties/guides/code/getting_started/app/assets/stylesheets/posts.css.scss3
-rw-r--r--railties/guides/code/getting_started/app/assets/stylesheets/scaffolds.css.scss56
-rw-r--r--railties/guides/code/getting_started/app/controllers/application_controller.rb3
-rw-r--r--railties/guides/code/getting_started/app/controllers/comments_controller.rb16
-rw-r--r--railties/guides/code/getting_started/app/controllers/home_controller.rb5
-rw-r--r--railties/guides/code/getting_started/app/controllers/posts_controller.rb84
-rw-r--r--railties/guides/code/getting_started/app/helpers/application_helper.rb2
-rw-r--r--railties/guides/code/getting_started/app/helpers/comments_helper.rb2
-rw-r--r--railties/guides/code/getting_started/app/helpers/home_helper.rb2
-rw-r--r--railties/guides/code/getting_started/app/helpers/posts_helper.rb5
-rw-r--r--railties/guides/code/getting_started/app/mailers/.gitkeep0
-rw-r--r--railties/guides/code/getting_started/app/models/.gitkeep0
-rw-r--r--railties/guides/code/getting_started/app/models/comment.rb3
-rw-r--r--railties/guides/code/getting_started/app/models/post.rb11
-rw-r--r--railties/guides/code/getting_started/app/models/tag.rb3
-rw-r--r--railties/guides/code/getting_started/app/views/comments/_comment.html.erb15
-rw-r--r--railties/guides/code/getting_started/app/views/comments/_form.html.erb13
-rw-r--r--railties/guides/code/getting_started/app/views/home/index.html.erb2
-rw-r--r--railties/guides/code/getting_started/app/views/layouts/application.html.erb14
-rw-r--r--railties/guides/code/getting_started/app/views/posts/_form.html.erb32
-rw-r--r--railties/guides/code/getting_started/app/views/posts/edit.html.erb6
-rw-r--r--railties/guides/code/getting_started/app/views/posts/index.html.erb27
-rw-r--r--railties/guides/code/getting_started/app/views/posts/new.html.erb5
-rw-r--r--railties/guides/code/getting_started/app/views/posts/show.html.erb31
-rw-r--r--railties/guides/code/getting_started/app/views/tags/_form.html.erb12
-rw-r--r--railties/guides/code/getting_started/config.ru4
-rw-r--r--railties/guides/code/getting_started/config/application.rb48
-rw-r--r--railties/guides/code/getting_started/config/boot.rb6
-rw-r--r--railties/guides/code/getting_started/config/database.yml25
-rw-r--r--railties/guides/code/getting_started/config/environment.rb5
-rw-r--r--railties/guides/code/getting_started/config/environments/development.rb30
-rw-r--r--railties/guides/code/getting_started/config/environments/production.rb60
-rw-r--r--railties/guides/code/getting_started/config/environments/test.rb42
-rw-r--r--railties/guides/code/getting_started/config/initializers/backtrace_silencers.rb7
-rw-r--r--railties/guides/code/getting_started/config/initializers/inflections.rb10
-rw-r--r--railties/guides/code/getting_started/config/initializers/mime_types.rb5
-rw-r--r--railties/guides/code/getting_started/config/initializers/secret_token.rb7
-rw-r--r--railties/guides/code/getting_started/config/initializers/session_store.rb8
-rw-r--r--railties/guides/code/getting_started/config/initializers/wrap_parameters.rb14
-rw-r--r--railties/guides/code/getting_started/config/locales/en.yml5
-rw-r--r--railties/guides/code/getting_started/config/routes.rb64
-rw-r--r--railties/guides/code/getting_started/db/migrate/20110901012504_create_posts.rb11
-rw-r--r--railties/guides/code/getting_started/db/migrate/20110901012815_create_comments.rb12
-rw-r--r--railties/guides/code/getting_started/db/migrate/20110901013701_create_tags.rb11
-rw-r--r--railties/guides/code/getting_started/db/schema.rb43
-rw-r--r--railties/guides/code/getting_started/db/seeds.rb7
-rw-r--r--railties/guides/code/getting_started/doc/README_FOR_APP2
-rw-r--r--railties/guides/code/getting_started/lib/assets/.gitkeep0
-rw-r--r--railties/guides/code/getting_started/lib/tasks/.gitkeep0
-rw-r--r--railties/guides/code/getting_started/public/404.html26
-rw-r--r--railties/guides/code/getting_started/public/422.html26
-rw-r--r--railties/guides/code/getting_started/public/500.html26
-rw-r--r--railties/guides/code/getting_started/public/favicon.ico0
-rw-r--r--railties/guides/code/getting_started/public/robots.txt5
-rwxr-xr-xrailties/guides/code/getting_started/script/rails6
-rw-r--r--railties/guides/code/getting_started/test/fixtures/.gitkeep0
-rw-r--r--railties/guides/code/getting_started/test/fixtures/comments.yml11
-rw-r--r--railties/guides/code/getting_started/test/fixtures/posts.yml11
-rw-r--r--railties/guides/code/getting_started/test/fixtures/tags.yml9
-rw-r--r--railties/guides/code/getting_started/test/functional/.gitkeep0
-rw-r--r--railties/guides/code/getting_started/test/functional/comments_controller_test.rb7
-rw-r--r--railties/guides/code/getting_started/test/functional/home_controller_test.rb9
-rw-r--r--railties/guides/code/getting_started/test/functional/posts_controller_test.rb49
-rw-r--r--railties/guides/code/getting_started/test/integration/.gitkeep0
-rw-r--r--railties/guides/code/getting_started/test/performance/browsing_test.rb12
-rw-r--r--railties/guides/code/getting_started/test/test_helper.rb13
-rw-r--r--railties/guides/code/getting_started/test/unit/.gitkeep0
-rw-r--r--railties/guides/code/getting_started/test/unit/comment_test.rb7
-rw-r--r--railties/guides/code/getting_started/test/unit/helpers/comments_helper_test.rb4
-rw-r--r--railties/guides/code/getting_started/test/unit/helpers/home_helper_test.rb4
-rw-r--r--railties/guides/code/getting_started/test/unit/helpers/posts_helper_test.rb4
-rw-r--r--railties/guides/code/getting_started/test/unit/post_test.rb7
-rw-r--r--railties/guides/code/getting_started/test/unit/tag_test.rb7
-rw-r--r--railties/guides/code/getting_started/vendor/assets/stylesheets/.gitkeep0
-rw-r--r--railties/guides/code/getting_started/vendor/plugins/.gitkeep0
-rw-r--r--railties/guides/source/action_controller_overview.textile6
-rw-r--r--railties/guides/source/action_mailer_basics.textile5
-rw-r--r--railties/guides/source/action_view_overview.textile7
-rw-r--r--railties/guides/source/active_model_basics.textile5
-rw-r--r--railties/guides/source/active_record_querying.textile31
-rw-r--r--railties/guides/source/active_record_validations_callbacks.textile11
-rw-r--r--railties/guides/source/active_resource_basics.textile4
-rw-r--r--railties/guides/source/active_support_core_extensions.textile7
-rw-r--r--railties/guides/source/api_documentation_guidelines.textile4
-rw-r--r--railties/guides/source/asset_pipeline.textile28
-rw-r--r--railties/guides/source/association_basics.textile17
-rw-r--r--railties/guides/source/caching_with_rails.textile11
-rw-r--r--railties/guides/source/configuring.textile8
-rw-r--r--railties/guides/source/contribute.textile70
-rw-r--r--railties/guides/source/contributing_to_ruby_on_rails.textile26
-rw-r--r--railties/guides/source/debugging_rails_applications.textile7
-rw-r--r--railties/guides/source/form_helpers.textile10
-rw-r--r--railties/guides/source/generators.textile11
-rw-r--r--railties/guides/source/getting_started.textile44
-rw-r--r--railties/guides/source/index.html.erb1
-rw-r--r--railties/guides/source/initialization.textile2
-rw-r--r--railties/guides/source/layout.html.erb6
-rw-r--r--railties/guides/source/layouts_and_rendering.textile12
-rw-r--r--railties/guides/source/migrations.textile6
-rw-r--r--railties/guides/source/performance_testing.textile6
-rw-r--r--railties/guides/source/plugins.textile8
-rw-r--r--railties/guides/source/rails_application_templates.textile4
-rw-r--r--railties/guides/source/rails_on_rack.textile7
-rw-r--r--railties/guides/source/routing.textile9
-rw-r--r--railties/guides/source/ruby_on_rails_guides_guidelines.textile5
-rw-r--r--railties/guides/source/security.textile4
-rw-r--r--railties/guides/source/testing.textile8
-rw-r--r--railties/lib/rails/application/configuration.rb3
-rw-r--r--railties/lib/rails/application/route_inspector.rb43
-rw-r--r--railties/lib/rails/generators/app_base.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb1
-rw-r--r--railties/lib/rails/tasks/routes.rake34
-rw-r--r--railties/test/application/assets_test.rb73
-rw-r--r--railties/test/application/rake_test.rb147
-rw-r--r--railties/test/application/route_inspect_test.rb97
-rw-r--r--railties/test/isolation/abstract_unit.rb2
-rw-r--r--railties/test/railties/generators_test.rb2
190 files changed, 2362 insertions, 825 deletions
diff --git a/Gemfile b/Gemfile
index 54e171b0db..5ce420c3a3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -8,6 +8,13 @@ end
gem "bcrypt-ruby", "~> 3.0.0"
gem "jquery-rails"
+
+if ENV['JOURNEY']
+ gem "journey", :path => ENV['JOURNEY']
+else
+ gem "journey", :git => "git://github.com/rails/journey"
+end
+
# This needs to be with require false to avoid
# it being automatically loaded by sprockets
gem "uglifier", ">= 1.0.3", :require => false
diff --git a/README.rdoc b/README.rdoc
index ac43962d97..0def4e5d12 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -67,7 +67,7 @@ We encourage you to contribute to Ruby on Rails! Please check out the {Contribut
guide}[http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html] for guidelines about how
to proceed. {Join us}[http://contributors.rubyonrails.org]!
-== Travis Build Status {<img src="https://secure.travis-ci.org/rails/rails.png"/>}[https://secure.travis-ci.org/rails/rails.png]
+== Travis Build Status {<img src="https://secure.travis-ci.org/rails/rails.png"/>}[http://travis-ci.org/rails/rails]
== License
diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG
index d4475bc951..14c887eb53 100644
--- a/actionmailer/CHANGELOG
+++ b/actionmailer/CHANGELOG
@@ -1,4 +1,4 @@
-*Rails 3.1.0 (unreleased)*
+*Rails 3.1.0 (August 30, 2011)*
* No changes
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 82dfc625a6..5ee14dbdf1 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.2.0 (unreleased)*
+* Changed log level of warning for missing CSRF token from :debug to :warn. [Mike Dillon]
+
* content_tag_for and div_for can now take the collection of records. It will also yield the record as the first argument if you set a receiving argument in your block [Prem Sichanugrist]
So instead of having to do this:
@@ -46,6 +48,16 @@
*Rails 3.1.1 (unreleased)*
+* Allow asset tag helper methods to accept :digest => false option in order to completely avoid the digest generation.
+Useful for linking assets from static html files or from emails when the user
+could probably look at an older html email with an older asset. [Santiago Pastorino]
+
+* Don't mount Sprockets server at config.assets.prefix if config.assets.compile is false. [Mark J. Titorenko]
+
+* Set relative url root in assets when controller isn't available for Sprockets (eg. Sass files using asset_path). Fixes #2435 [Guillermo Iguaran]
+
+* Fix basic auth credential generation to not make newlines. GH #2882
+
* Fixed the behavior of asset pipeline when config.assets.digest and config.assets.compile are false and requested asset isn't precompiled.
Before the requested asset were compiled anyway ignoring that the config.assets.compile flag is false. [Guillermo Iguaran]
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index 65b364f872..f1b7966b9c 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
s.add_dependency('i18n', '~> 0.6')
s.add_dependency('rack', '~> 1.3.2')
s.add_dependency('rack-test', '~> 0.6.1')
- s.add_dependency('rack-mount', '~> 0.8.2')
+ s.add_dependency('journey', '~> 1.0.0')
s.add_dependency('sprockets', '~> 2.0.0')
s.add_dependency('erubis', '~> 2.7.0')
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 4d016271ea..bc22e39efb 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -74,7 +74,7 @@ module ActionController #:nodoc:
# The actual before_filter that is used. Modify this to change how you handle unverified requests.
def verify_authenticity_token
unless verified_request?
- logger.debug "WARNING: Can't verify CSRF token authenticity" if logger
+ logger.warn "WARNING: Can't verify CSRF token authenticity" if logger
handle_unverified_request
end
end
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index 8487b0fc8c..caa1decb9e 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -45,7 +45,7 @@ module ActionDispatch
rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path)
rewritten_url << "?#{params.to_query}" unless params.empty?
- rewritten_url << "##{Rack::Mount::Utils.escape_uri(options[:anchor].to_param.to_s)}" if options[:anchor]
+ rewritten_url << "##{Journey::Router::Utils.escape_uri(options[:anchor].to_param.to_s)}" if options[:anchor]
rewritten_url
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 4d65173f61..cd59b13c42 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -213,8 +213,8 @@ module ActionDispatch
end
def segment_keys
- @segment_keys ||= Rack::Mount::RegexpWithNamedGroups.new(
- Rack::Mount::Strexp.compile(@path, requirements, SEPARATORS)
+ @segment_keys ||= Journey::Path::Pattern.new(
+ Journey::Router::Strexp.compile(@path, requirements, SEPARATORS)
).names
end
@@ -235,7 +235,7 @@ module ActionDispatch
# (:locale) becomes (/:locale) instead of /(:locale). Except
# for root cases, where the latter is the correct one.
def self.normalize_path(path)
- path = Rack::Mount::Utils.normalize_path(path)
+ path = Journey::Router::Utils.normalize_path(path)
path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/\(+[^/]+\)$}
path
end
@@ -1465,9 +1465,9 @@ module ActionDispatch
end
module Shorthand #:nodoc:
- def match(*args)
- if args.size == 1 && args.last.is_a?(Hash)
- options = args.pop
+ def match(path, *rest)
+ if rest.empty? && Hash === path
+ options = path
path, to = options.find { |name, value| name.is_a?(String) }
options.merge!(:to => to).delete(path)
super(path, options)
diff --git a/actionpack/lib/action_dispatch/routing/route.rb b/actionpack/lib/action_dispatch/routing/route.rb
deleted file mode 100644
index 10b3d38346..0000000000
--- a/actionpack/lib/action_dispatch/routing/route.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-module ActionDispatch
- module Routing
- class Route #:nodoc:
- attr_reader :app, :conditions, :defaults, :name
- attr_reader :path, :requirements, :set
-
- def initialize(set, app, conditions, requirements, defaults, name, anchor)
- @set = set
- @app = app
- @defaults = defaults
- @name = name
-
- # FIXME: we should not be doing this much work in a constructor.
-
- @requirements = requirements.merge(defaults)
- @requirements.delete(:controller) if @requirements[:controller].is_a?(Regexp)
- @requirements.delete_if { |k, v|
- v == Regexp.compile("[^#{SEPARATORS.join}]+")
- }
-
- if path = conditions[:path_info]
- @path = path
- conditions[:path_info] = ::Rack::Mount::Strexp.compile(path, requirements, SEPARATORS, anchor)
- end
-
- @verbs = conditions[:request_method] || []
-
- @conditions = conditions.dup
-
- # Rack-Mount requires that :request_method be a regular expression.
- # :request_method represents the HTTP verb that matches this route.
- #
- # Here we munge values before they get sent on to rack-mount.
- @conditions[:request_method] = %r[^#{verb}$] unless @verbs.empty?
- @conditions[:path_info] = Rack::Mount::RegexpWithNamedGroups.new(@conditions[:path_info]) if @conditions[:path_info]
- @conditions.delete_if{ |k,v| k != :path_info && !valid_condition?(k) }
- @requirements.delete_if{ |k,v| !valid_condition?(k) }
- end
-
- def verb
- @verbs.join '|'
- end
-
- def segment_keys
- @segment_keys ||= conditions[:path_info].names.compact.map { |key| key.to_sym }
- end
-
- def to_s
- @to_s ||= begin
- "%-6s %-40s %s" % [(verb || :any).to_s.upcase, path, requirements.inspect]
- end
- end
-
- private
- def valid_condition?(method)
- segment_keys.include?(method) || set.valid_conditions.include?(method)
- end
- end
- end
-end
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 11228c597d..46a68a32ae 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -1,4 +1,4 @@
-require 'rack/mount'
+require 'journey/router'
require 'forwardable'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/to_query'
@@ -205,29 +205,42 @@ module ActionDispatch
end
end
- attr_accessor :set, :routes, :named_routes, :default_scope
+ attr_accessor :formatter, :set, :named_routes, :default_scope, :router
attr_accessor :disable_clear_and_finalize, :resources_path_names
attr_accessor :default_url_options, :request_class, :valid_conditions
+ alias :routes :set
+
def self.default_resources_path_names
{ :new => 'new', :edit => 'edit' }
end
def initialize(request_class = ActionDispatch::Request)
- self.routes = []
self.named_routes = NamedRouteCollection.new
self.resources_path_names = self.class.default_resources_path_names.dup
self.default_url_options = {}
self.request_class = request_class
- self.valid_conditions = request_class.public_instance_methods.map { |m| m.to_sym }
+ @valid_conditions = {}
+
+ request_class.public_instance_methods.each { |m|
+ @valid_conditions[m.to_sym] = true
+ }
+ @valid_conditions[:controller] = true
+ @valid_conditions[:action] = true
+
self.valid_conditions.delete(:id)
- self.valid_conditions.push(:controller, :action)
- @append = []
- @prepend = []
+ @append = []
+ @prepend = []
@disable_clear_and_finalize = false
- clear!
+ @finalized = false
+
+ @set = Journey::Routes.new
+ @router = Journey::Router.new(@set, {
+ :parameters_key => PARAMETERS_KEY,
+ :request_class => request_class})
+ @formatter = Journey::Formatter.new @set
end
def draw(&block)
@@ -263,17 +276,13 @@ module ActionDispatch
return if @finalized
@append.each { |blk| eval_block(blk) }
@finalized = true
- @set.freeze
end
def clear!
@finalized = false
- routes.clear
named_routes.clear
- @set = ::Rack::Mount::RouteSet.new(
- :parameters_key => PARAMETERS_KEY,
- :request_class => request_class
- )
+ set.clear
+ formatter.clear
@prepend.each { |blk| eval_block(blk) }
end
@@ -341,26 +350,55 @@ module ActionDispatch
def add_route(app, conditions = {}, requirements = {}, defaults = {}, name = nil, anchor = true)
raise ArgumentError, "Invalid route name: '#{name}'" unless name.blank? || name.to_s.match(/^[_a-z]\w*$/i)
- route = Route.new(self, app, conditions, requirements, defaults, name, anchor)
- @set.add_route(route.app, route.conditions, route.defaults, route.name)
+
+ path = build_path(conditions.delete(:path_info), requirements, SEPARATORS, anchor)
+ conditions = build_conditions(conditions, valid_conditions, path.names.map { |x| x.to_sym })
+
+ route = @set.add_route(app, path, conditions, defaults, name)
named_routes[name] = route if name
- routes << route
route
end
+ def build_path(path, requirements, separators, anchor)
+ strexp = Journey::Router::Strexp.new(
+ path,
+ requirements,
+ SEPARATORS,
+ anchor)
+
+ Journey::Path::Pattern.new(strexp)
+ end
+ private :build_path
+
+ def build_conditions(current_conditions, req_predicates, path_values)
+ conditions = current_conditions.dup
+
+ verbs = conditions[:request_method] || []
+
+ # Rack-Mount requires that :request_method be a regular expression.
+ # :request_method represents the HTTP verb that matches this route.
+ #
+ # Here we munge values before they get sent on to rack-mount.
+ unless verbs.empty?
+ conditions[:request_method] = %r[^#{verbs.join('|')}$]
+ end
+ conditions.delete_if { |k,v| !(req_predicates.include?(k) || path_values.include?(k)) }
+
+ conditions
+ end
+ private :build_conditions
+
class Generator #:nodoc:
- PARAMETERIZE = {
- :parameterize => lambda do |name, value|
- if name == :controller
- value
- elsif value.is_a?(Array)
- value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
- else
- return nil unless param = value.to_param
- param.split('/').map { |v| Rack::Mount::Utils.escape_uri(v) }.join("/")
- end
+ PARAMETERIZE = lambda do |name, value|
+ if name == :controller
+ value
+ elsif value.is_a?(Array)
+ value.map { |v| Journey::Router::Utils.escape_uri(v.to_param) }.join('/')
+ else
+ return nil unless param = value.to_param
+ param.split('/').map { |v| Journey::Router::Utils.escape_uri(v) }.join("/")
end
- }
+ end
attr_reader :options, :recall, :set, :named_route
@@ -450,14 +488,14 @@ module ActionDispatch
end
def generate
- path, params = @set.set.generate(:path_info, named_route, options, recall, PARAMETERIZE)
+ path, params = @set.formatter.generate(:path_info, named_route, options, recall, PARAMETERIZE)
raise_routing_error unless path
return [path, params.keys] if @extras
[path, params]
- rescue Rack::Mount::RoutingError
+ rescue Journey::Router::RoutingError
raise_routing_error
end
@@ -529,12 +567,12 @@ module ActionDispatch
def call(env)
finalize!
- @set.call(env)
+ @router.call(env)
end
def recognize_path(path, environment = {})
method = (environment[:method] || "GET").to_s.upcase
- path = Rack::Mount::Utils.normalize_path(path) unless path =~ %r{://}
+ path = Journey::Router::Utils.normalize_path(path) unless path =~ %r{://}
begin
env = Rack::MockRequest.env_for(path, {:method => method})
@@ -543,7 +581,7 @@ module ActionDispatch
end
req = @request_class.new(env)
- @set.recognize(req) do |route, matches, params|
+ @router.recognize(req) do |route, matches, params|
params.each do |key, value|
if value.is_a?(String)
value = value.dup.force_encoding(Encoding::BINARY) if value.encoding_aware?
diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb
index 73f4f8ee5f..cf30ad7e57 100644
--- a/actionpack/lib/action_view/asset_paths.rb
+++ b/actionpack/lib/action_view/asset_paths.rb
@@ -21,14 +21,15 @@ module ActionView
# 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)
- def compute_public_path(source, dir, ext = nil, include_host = true, protocol = nil)
+ def compute_public_path(source, dir, options = {})
source = source.to_s
return source if is_uri?(source)
- source = rewrite_extension(source, dir, ext) if ext
- source = rewrite_asset_path(source, dir)
- source = rewrite_relative_url_root(source, relative_url_root) if has_request?
- source = rewrite_host_and_protocol(source, protocol) if include_host
+ 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
end
@@ -119,10 +120,11 @@ module ActionView
end
def relative_url_root
- config = controller.config if controller.respond_to?(:config)
- config ||= config.action_controller if config.action_controller.present?
- config ||= config
- config.relative_url_root
+ if config.action_controller.present?
+ config.action_controller.relative_url_root
+ else
+ config.relative_url_root
+ end
end
def asset_host_config
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb
index 3c05173a1b..05d5f1870a 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb
@@ -60,8 +60,8 @@ module ActionView
private
- def path_to_asset(source, include_host = true, protocol = nil)
- asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension, include_host, protocol)
+ def path_to_asset(source, options = {})
+ asset_paths.compute_public_path(source, asset_name.to_s.pluralize, options.merge(:ext => extension))
end
def path_to_asset_source(source)
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb
index 8b35aa8896..dd4e9ae4cc 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb
@@ -41,7 +41,7 @@ module ActionView
# Break out the asset path rewrite in case plugins wish to put the asset id
# someplace other than the query string.
- def rewrite_asset_path(source, dir)
+ def rewrite_asset_path(source, dir, options = nil)
source = "/#{dir}/#{source}" unless source[0] == ?/
path = config.asset_path
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
index 25cc561608..09700bd0c5 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
@@ -83,7 +83,7 @@ module ActionView
# javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr
# javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
def javascript_path(source)
- asset_paths.compute_public_path(source, 'javascripts', 'js')
+ asset_paths.compute_public_path(source, 'javascripts', :ext => 'js')
end
alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
index 8c25d38bbd..2eb3eb31af 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
@@ -17,7 +17,7 @@ module ActionView
def asset_tag(source, options)
# We force the :request protocol here to avoid a double-download bug in IE7 and IE8
- tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => ERB::Util.html_escape(path_to_asset(source, true, :request)) }.merge(options), false, false)
+ tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => ERB::Util.html_escape(path_to_asset(source, :protocol => :request)) }.merge(options), false, false)
end
def custom_dir
@@ -61,7 +61,7 @@ module ActionView
# stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style
# stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css
def stylesheet_path(source)
- asset_paths.compute_public_path(source, 'stylesheets', 'css', true, :request)
+ asset_paths.compute_public_path(source, 'stylesheets', :ext => 'css', :protocol => :request)
end
alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route
diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake
index a8128d9a82..9b2f3a3f94 100644
--- a/actionpack/lib/sprockets/assets.rake
+++ b/actionpack/lib/sprockets/assets.rake
@@ -9,6 +9,7 @@ namespace :assets do
Kernel.exec $0, *ARGV
else
Rake::Task["environment"].invoke
+ Rake::Task["tmp:cache:clear"].invoke
# Ensure that action view is loaded and the appropriate sprockets hooks get executed
ActionView::Base
@@ -16,6 +17,9 @@ namespace :assets do
# Always compile files
Rails.application.config.assets.compile = true
+ # Always ignore asset host
+ Rails.application.config.action_controller.asset_host = nil
+
config = Rails.application.config
env = Rails.application.assets
target = Pathname.new(File.join(Rails.public_path, config.assets.prefix))
@@ -26,6 +30,8 @@ namespace :assets do
env.each_logical_path do |logical_path|
if path.is_a?(Regexp)
next unless path.match(logical_path)
+ elsif path.is_a?(Proc)
+ next unless path.call(logical_path)
else
next unless File.fnmatch(path.to_s, logical_path)
end
@@ -42,7 +48,7 @@ namespace :assets do
end
end
- File.open("#{manifest_path}/manifest.yml", 'w') do |f|
+ File.open("#{manifest_path}/manifest.yml", 'wb') do |f|
YAML.dump(manifest, f)
end
end
diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb
index 3987e6e17f..457ab93ae3 100644
--- a/actionpack/lib/sprockets/helpers/rails_helper.rb
+++ b/actionpack/lib/sprockets/helpers/rails_helper.rb
@@ -25,38 +25,40 @@ module Sprockets
options = sources.extract_options!
debug = options.key?(:debug) ? options.delete(:debug) : debug_assets?
body = options.key?(:body) ? options.delete(:body) : false
+ digest = options.key?(:digest) ? options.delete(:digest) : digest_assets?
sources.collect do |source|
if debug && asset = asset_paths.asset_for(source, 'js')
asset.to_a.map { |dep|
- super(dep.to_s, { :src => asset_path(dep, 'js', true) }.merge!(options))
+ super(dep.to_s, { :src => asset_path(dep, :ext => 'js', :body => true, :digest => digest) }.merge!(options))
}
else
- super(source.to_s, { :src => asset_path(source, 'js', body) }.merge!(options))
+ super(source.to_s, { :src => asset_path(source, :ext => 'js', :body => body, :digest => digest) }.merge!(options))
end
end.join("\n").html_safe
end
def stylesheet_link_tag(*sources)
options = sources.extract_options!
- debug = options.key?(:debug) ? options.delete(:debug) : debug_assets?
- body = options.key?(:body) ? options.delete(:body) : false
+ debug = options.key?(:debug) ? options.delete(:debug) : debug_assets?
+ body = options.key?(:body) ? options.delete(:body) : false
+ digest = options.key?(:digest) ? options.delete(:digest) : digest_assets?
sources.collect do |source|
if debug && asset = asset_paths.asset_for(source, 'css')
asset.to_a.map { |dep|
- super(dep.to_s, { :href => asset_path(dep, 'css', true, :request) }.merge!(options))
+ super(dep.to_s, { :href => asset_path(dep, :ext => 'css', :body => true, :protocol => :request, :digest => digest) }.merge!(options))
}
else
- super(source.to_s, { :href => asset_path(source, 'css', body, :request) }.merge!(options))
+ super(source.to_s, { :href => asset_path(source, :ext => 'css', :body => body, :protocol => :request, :digest => digest) }.merge!(options))
end
end.join("\n").html_safe
end
- def asset_path(source, default_ext = nil, body = false, protocol = nil)
+ def asset_path(source, options = {})
source = source.logical_path if source.respond_to?(:logical_path)
- path = asset_paths.compute_public_path(source, 'assets', default_ext, true, protocol)
- body ? "#{path}?body=1" : path
+ path = asset_paths.compute_public_path(source, 'assets', options.merge(:body => true))
+ options[:body] ? "#{path}?body=1" : path
end
private
@@ -100,8 +102,8 @@ module Sprockets
class AssetNotPrecompiledError < StandardError; end
- def compute_public_path(source, dir, ext=nil, include_host=true, protocol=nil)
- super(source, asset_prefix, ext, include_host, protocol)
+ def compute_public_path(source, dir, options = {})
+ super(source, asset_prefix, options)
end
# Return the filesystem path for the source
@@ -131,11 +133,11 @@ module Sprockets
end
end
- def rewrite_asset_path(source, dir)
+ def rewrite_asset_path(source, dir, options = {})
if source[0] == ?/
source
else
- source = digest_for(source)
+ source = digest_for(source) unless options[:digest] == false
source = File.join(dir, source)
source = "/#{source}" unless source =~ /^\//
source
diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb
index dc991636a1..f05d835554 100644
--- a/actionpack/lib/sprockets/railtie.rb
+++ b/actionpack/lib/sprockets/railtie.rb
@@ -67,8 +67,10 @@ module Sprockets
end
end
- app.routes.prepend do
- mount app.assets => config.assets.prefix
+ if config.assets.compile
+ app.routes.prepend do
+ mount app.assets => config.assets.prefix
+ end
end
if config.assets.digest
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index d94db7f5fb..fd5a41a0bb 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -1,6 +1,7 @@
require 'abstract_unit'
require 'digest/sha1'
require 'active_support/core_ext/string/strip'
+require "active_support/log_subscriber/test_helper"
# common controller actions
module RequestForgeryProtectionActions
@@ -157,6 +158,21 @@ module RequestForgeryProtectionTests
assert_not_blocked { put :index }
end
+ def test_should_warn_on_missing_csrf_token
+ old_logger = ActionController::Base.logger
+ logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new
+ ActionController::Base.logger = logger
+
+ begin
+ assert_blocked { post :index }
+
+ assert_equal 1, logger.logged(:warn).size
+ assert_match(/CSRF token authenticity/, logger.logged(:warn).last)
+ ensure
+ ActionController::Base.logger = old_logger
+ end
+ end
+
def assert_blocked
session[:something_like_user_id] = 1
yield
diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb
index b9cd15708b..6b8a8f6161 100644
--- a/actionpack/test/controller/resources_test.rb
+++ b/actionpack/test/controller/resources_test.rb
@@ -532,7 +532,7 @@ class ResourcesTest < ActionController::TestCase
routes.each do |route|
routes.each do |r|
next if route === r # skip the comparison instance
- assert_not_equal route.conditions, r.conditions
+ assert_not_equal [route.conditions, route.path.spec.to_s], [r.conditions, r.path.spec.to_s]
end
end
end
diff --git a/actionpack/test/dispatch/mapper_test.rb b/actionpack/test/dispatch/mapper_test.rb
index 3316dd03aa..d3465589c1 100644
--- a/actionpack/test/dispatch/mapper_test.rb
+++ b/actionpack/test/dispatch/mapper_test.rb
@@ -5,6 +5,7 @@ module ActionDispatch
class MapperTest < ActiveSupport::TestCase
class FakeSet
attr_reader :routes
+ alias :set :routes
def initialize
@routes = []
diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb
index cbef74f992..363403092b 100644
--- a/actionpack/test/lib/controller/fake_models.rb
+++ b/actionpack/test/lib/controller/fake_models.rb
@@ -48,26 +48,19 @@ module Quiz
end
end
-class Post < Struct.new(:title, :author_name, :body, :secret, :written_on, :cost)
+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
- def persisted=(boolean)
- @persisted = boolean
- end
-
- def persisted?
- @persisted
- end
-
attr_accessor :author
def author_attributes=(attributes); end
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index f898c22e1e..e36d032f6c 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -698,8 +698,7 @@ class FormHelperTest < ActionView::TestCase
expected = whole_form("/posts/44", "edit_post_44" , "edit_post", :method => "put") do
"<input name='post[title]' size='30' type='text' id='post_title' value='And his name will be forty and four.' />" +
- "<input name='commit' type='submit' value='Edit post' />" +
- "</form>"
+ "<input name='commit' type='submit' value='Edit post' />"
end
assert_dom_equal expected, output_buffer
diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb
index ae4cb1f0aa..c0fb07a29b 100644
--- a/actionpack/test/template/sprockets_helper_test.rb
+++ b/actionpack/test/template/sprockets_helper_test.rb
@@ -41,6 +41,10 @@ class SprocketsHelperTest < ActionView::TestCase
test "asset_path" do
assert_match %r{/assets/logo-[0-9a-f]+.png},
asset_path("logo.png")
+ assert_match %r{/assets/logo-[0-9a-f]+.png},
+ asset_path("logo.png", :digest => true)
+ assert_match %r{/assets/logo.png},
+ asset_path("logo.png", :digest => false)
end
test "asset_path with root relative assets" do
@@ -124,27 +128,38 @@ class SprocketsHelperTest < ActionView::TestCase
asset_path("/images/logo.gif")
end
+ 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"
+ assert_equal "/collaboration/hieraki/images/logo.gif",
+ asset_path("/images/logo.gif")
+ end
+
test "javascript path" do
assert_match %r{/assets/application-[0-9a-f]+.js},
- asset_path(:application, "js")
+ asset_path(:application, :ext => "js")
assert_match %r{/assets/xmlhr-[0-9a-f]+.js},
- asset_path("xmlhr", "js")
+ asset_path("xmlhr", :ext => "js")
assert_match %r{/assets/dir/xmlhr-[0-9a-f]+.js},
- asset_path("dir/xmlhr.js", "js")
+ asset_path("dir/xmlhr.js", :ext => "js")
assert_equal "/dir/xmlhr.js",
- asset_path("/dir/xmlhr", "js")
+ asset_path("/dir/xmlhr", :ext => "js")
assert_equal "http://www.example.com/js/xmlhr",
- asset_path("http://www.example.com/js/xmlhr", "js")
+ asset_path("http://www.example.com/js/xmlhr", :ext => "js")
assert_equal "http://www.example.com/js/xmlhr.js",
- asset_path("http://www.example.com/js/xmlhr.js", "js")
+ asset_path("http://www.example.com/js/xmlhr.js", :ext => "js")
end
test "javascript include tag" do
assert_match %r{<script src="/assets/application-[0-9a-f]+.js" type="text/javascript"></script>},
javascript_include_tag(:application)
+ assert_match %r{<script src="/assets/application-[0-9a-f]+.js" type="text/javascript"></script>},
+ javascript_include_tag(:application, :digest => true)
+ assert_match %r{<script src="/assets/application.js" type="text/javascript"></script>},
+ javascript_include_tag(:application, :digest => false)
assert_match %r{<script src="/assets/xmlhr-[0-9a-f]+.js" type="text/javascript"></script>},
javascript_include_tag("xmlhr")
@@ -166,21 +181,25 @@ class SprocketsHelperTest < ActionView::TestCase
end
test "stylesheet path" do
- assert_match %r{/assets/application-[0-9a-f]+.css}, asset_path(:application, "css")
+ assert_match %r{/assets/application-[0-9a-f]+.css}, asset_path(:application, :ext => "css")
- assert_match %r{/assets/style-[0-9a-f]+.css}, asset_path("style", "css")
- assert_match %r{/assets/dir/style-[0-9a-f]+.css}, asset_path("dir/style.css", "css")
- assert_equal "/dir/style.css", asset_path("/dir/style.css", "css")
+ assert_match %r{/assets/style-[0-9a-f]+.css}, asset_path("style", :ext => "css")
+ assert_match %r{/assets/dir/style-[0-9a-f]+.css}, asset_path("dir/style.css", :ext => "css")
+ assert_equal "/dir/style.css", asset_path("/dir/style.css", :ext => "css")
assert_equal "http://www.example.com/css/style",
- asset_path("http://www.example.com/css/style", "css")
+ asset_path("http://www.example.com/css/style", :ext => "css")
assert_equal "http://www.example.com/css/style.css",
- asset_path("http://www.example.com/css/style.css", "css")
+ asset_path("http://www.example.com/css/style.css", :ext => "css")
end
test "stylesheet link tag" do
assert_match %r{<link href="/assets/application-[0-9a-f]+.css" media="screen" rel="stylesheet" type="text/css" />},
stylesheet_link_tag(:application)
+ assert_match %r{<link href="/assets/application-[0-9a-f]+.css" media="screen" rel="stylesheet" type="text/css" />},
+ stylesheet_link_tag(:application, :digest => true)
+ assert_match %r{<link href="/assets/application.css" media="screen" rel="stylesheet" type="text/css" />},
+ stylesheet_link_tag(:application, :digest => false)
assert_match %r{<link href="/assets/style-[0-9a-f]+.css" media="screen" rel="stylesheet" type="text/css" />},
stylesheet_link_tag("style")
@@ -211,14 +230,14 @@ class SprocketsHelperTest < ActionView::TestCase
test "alternate asset prefix" do
stubs(:asset_prefix).returns("/themes/test")
- assert_match %r{/themes/test/style-[0-9a-f]+.css}, asset_path("style", "css")
+ assert_match %r{/themes/test/style-[0-9a-f]+.css}, asset_path("style", :ext => "css")
end
test "alternate asset environment" do
assets = Sprockets::Environment.new
assets.append_path(FIXTURES.join("sprockets/alternate/stylesheets"))
stubs(:asset_environment).returns(assets)
- assert_match %r{/assets/style-[0-9a-f]+.css}, asset_path("style", "css")
+ assert_match %r{/assets/style-[0-9a-f]+.css}, asset_path("style", :ext => "css")
end
test "alternate hash based on environment" do
@@ -226,10 +245,10 @@ class SprocketsHelperTest < ActionView::TestCase
assets.version = 'development'
assets.append_path(FIXTURES.join("sprockets/alternate/stylesheets"))
stubs(:asset_environment).returns(assets)
- dev_path = asset_path("style", "css")
+ dev_path = asset_path("style", :ext => "css")
assets.version = 'production'
- prod_path = asset_path("style", "css")
+ prod_path = asset_path("style", :ext => "css")
assert_not_equal prod_path, dev_path
end
diff --git a/activemodel/CHANGELOG b/activemodel/CHANGELOG
index 20e5816532..3d26d646b0 100644
--- a/activemodel/CHANGELOG
+++ b/activemodel/CHANGELOG
@@ -4,7 +4,7 @@
* Provide mass_assignment_sanitizer as an easy API to replace the sanitizer behavior. Also support both :logger (default) and :strict sanitizer behavior [Bogdan Gusiev]
-*Rails 3.1.0 (unreleased)*
+*Rails 3.1.0 (August 30, 2011)*
* Alternate I18n namespace lookup is no longer supported.
Instead of "activerecord.models.admins.post", do "activerecord.models.admins/post" instead [José Valim]
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index bdc0eb4a0d..a201e983cd 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/class/attribute'
+require 'active_support/deprecation'
module ActiveModel
class MissingAttributeError < NoMethodError
@@ -60,7 +61,7 @@ module ActiveModel
included do
class_attribute :attribute_method_matchers, :instance_writer => false
- self.attribute_method_matchers = []
+ self.attribute_method_matchers = [ClassMethods::AttributeMethodMatcher.new]
end
module ClassMethods
@@ -284,33 +285,25 @@ module ActiveModel
def define_attribute_method(attr_name)
attribute_method_matchers.each do |matcher|
- unless instance_method_already_implemented?(matcher.method_name(attr_name))
- generate_method = "define_method_#{matcher.prefix}attribute#{matcher.suffix}"
+ method_name = matcher.method_name(attr_name)
+
+ unless instance_method_already_implemented?(method_name)
+ generate_method = "define_method_#{matcher.method_missing_target}"
if respond_to?(generate_method)
send(generate_method, attr_name)
else
- method_name = matcher.method_name(attr_name)
+ if method_name =~ COMPILABLE_REGEXP
+ defn = "def #{method_name}(*args)"
+ else
+ defn = "define_method(:'#{method_name}') do |*args|"
+ end
generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
- if method_defined?('#{method_name}')
- undef :'#{method_name}'
+ #{defn}
+ send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
end
RUBY
-
- if method_name.to_s =~ COMPILABLE_REGEXP
- generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
- def #{method_name}(*args)
- send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
- end
- RUBY
- else
- generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
- define_method('#{method_name}') do |*args|
- send('#{matcher.method_missing_target}', '#{attr_name}', *args)
- end
- RUBY
- end
end
end
end
@@ -336,7 +329,7 @@ module ActiveModel
protected
def instance_method_already_implemented?(method_name)
- method_defined?(method_name)
+ generated_attribute_methods.method_defined?(method_name)
end
private
@@ -357,8 +350,11 @@ module ActiveModel
if attribute_method_matchers_cache.key?(method_name)
attribute_method_matchers_cache[method_name]
else
+ # Must try to match prefixes/suffixes first, or else the matcher with no prefix/suffix
+ # will match every time.
+ matchers = attribute_method_matchers.partition(&:plain?).reverse.flatten(1)
match = nil
- attribute_method_matchers.detect { |method| match = method.match(method_name) }
+ matchers.detect { |method| match = method.match(method_name) }
attribute_method_matchers_cache[method_name] = match
end
end
@@ -366,10 +362,20 @@ module ActiveModel
class AttributeMethodMatcher
attr_reader :prefix, :suffix, :method_missing_target
- AttributeMethodMatch = Struct.new(:target, :attr_name)
+ AttributeMethodMatch = Struct.new(:target, :attr_name, :method_name)
def initialize(options = {})
options.symbolize_keys!
+
+ if options[:prefix] == '' || options[:suffix] == ''
+ ActiveSupport::Deprecation.warn(
+ "Specifying an empty prefix/suffix for an attribute method is no longer " \
+ "necessary. If the un-prefixed/suffixed version of the method has not been " \
+ "defined when `define_attribute_methods` is called, it will be defined " \
+ "automatically."
+ )
+ end
+
@prefix, @suffix = options[:prefix] || '', options[:suffix] || ''
@regex = /^(#{Regexp.escape(@prefix)})(.+?)(#{Regexp.escape(@suffix)})$/
@method_missing_target = "#{@prefix}attribute#{@suffix}"
@@ -378,7 +384,7 @@ module ActiveModel
def match(method_name)
if @regex =~ method_name
- AttributeMethodMatch.new(method_missing_target, $2)
+ AttributeMethodMatch.new(method_missing_target, $2, method_name)
else
nil
end
@@ -387,6 +393,10 @@ module ActiveModel
def method_name(attr_name)
@method_name % attr_name
end
+
+ def plain?
+ prefix.empty? && suffix.empty?
+ end
end
end
@@ -401,13 +411,21 @@ module ActiveModel
# It's also possible to instantiate related objects, so a Client class
# belonging to the clients table with a +master_id+ foreign key can
# instantiate master through Client#master.
- def method_missing(method_id, *args, &block)
- method_name = method_id.to_s
- if match = match_attribute_method?(method_name)
- guard_private_attribute_method!(method_name, args)
- return __send__(match.target, match.attr_name, *args, &block)
+ def method_missing(method, *args, &block)
+ if respond_to_without_attributes?(method, true)
+ super
+ else
+ match = match_attribute_method?(method.to_s)
+ match ? attribute_missing(match, *args, &block) : super
end
- super
+ end
+
+ # attribute_missing is like method_missing, but for attributes. When method_missing is
+ # called we check to see if there is a matching attribute method. If so, we call
+ # attribute_missing to dispatch the attribute. This method can be overloaded to
+ # customise the behaviour.
+ def attribute_missing(match, *args, &block)
+ __send__(match.target, match.attr_name, *args, &block)
end
# A Person object with a name attribute can ask <tt>person.respond_to?(:name)</tt>,
@@ -416,15 +434,14 @@ module ActiveModel
alias :respond_to_without_attributes? :respond_to?
def respond_to?(method, include_private_methods = false)
if super
- return true
+ true
elsif !include_private_methods && super(method, true)
# If we're here then we haven't found among non-private methods
# but found among all methods. Which means that the given method is private.
- return false
- elsif match_attribute_method?(method.to_s)
- return true
+ false
+ else
+ !match_attribute_method?(method.to_s).nil?
end
- super
end
protected
@@ -440,13 +457,6 @@ module ActiveModel
match && attribute_method?(match.attr_name) ? match : nil
end
- # prevent method_missing from calling private methods with #send
- def guard_private_attribute_method!(method_name, args)
- if self.class.private_method_defined?(method_name)
- raise NoMethodError.new("Attempt to call private method `#{method_name}'", method_name, args)
- end
- end
-
def missing_attribute(attr_name, stack)
raise ActiveModel::MissingAttributeError, "missing attribute: #{attr_name}", stack
end
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 7828434927..d91e4a2b6a 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -180,6 +180,7 @@ module ActiveModel
all? { |k, v| v && v.empty? }
end
alias_method :blank?, :empty?
+
# Returns an xml formatted representation of the Errors hash.
#
# p.errors.add(:name, "can't be blank")
@@ -254,20 +255,22 @@ module ActiveModel
# company.errors.full_messages # =>
# ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Email can't be blank"]
def full_messages
- map { |attribute, message|
- if attribute == :base
- message
- else
- attr_name = attribute.to_s.gsub('.', '_').humanize
- attr_name = @base.class.human_attribute_name(attribute, :default => attr_name)
-
- I18n.t(:"errors.format", {
- :default => "%{attribute} %{message}",
- :attribute => attr_name,
- :message => message
- })
- end
- }
+ map { |attribute, message| full_message(attribute, message) }
+ end
+
+ # Returns a full message for a given attribute.
+ #
+ # company.errors.full_message(:name, "is invalid") # =>
+ # "Name is invalid"
+ def full_message(attribute, message)
+ return message if attribute == :base
+ attr_name = attribute.to_s.gsub('.', '_').humanize
+ attr_name = @base.class.human_attribute_name(attribute, :default => attr_name)
+ I18n.t(:"errors.format", {
+ :default => "%{attribute} %{message}",
+ :attribute => attr_name,
+ :message => message
+ })
end
# Translates an error message in its default scope
diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb
index 9840e3364c..67471ed497 100644
--- a/activemodel/test/cases/attribute_methods_test.rb
+++ b/activemodel/test/cases/attribute_methods_test.rb
@@ -3,8 +3,6 @@ require 'cases/helper'
class ModelWithAttributes
include ActiveModel::AttributeMethods
- attribute_method_suffix ''
-
class << self
define_method(:bar) do
'original bar'
@@ -24,14 +22,31 @@ end
class ModelWithAttributes2
include ActiveModel::AttributeMethods
+ attr_accessor :attributes
+
attribute_method_suffix '_test'
+
+private
+ def attribute(name)
+ attributes[name.to_s]
+ end
+
+ alias attribute_test attribute
+
+ def private_method
+ "<3 <3"
+ end
+
+protected
+
+ def protected_method
+ "O_o O_o"
+ end
end
class ModelWithAttributesWithSpaces
include ActiveModel::AttributeMethods
- attribute_method_suffix ''
-
def attributes
{ :'foo bar' => 'value of foo bar'}
end
@@ -45,8 +60,6 @@ end
class ModelWithWeirdNamesAttributes
include ActiveModel::AttributeMethods
- attribute_method_suffix ''
-
class << self
define_method(:'c?d') do
'original c?d'
@@ -76,6 +89,29 @@ class AttributeMethodsTest < ActiveModel::TestCase
assert_equal "value of foo", ModelWithAttributes.new.foo
end
+ test '#define_attribute_method does not generate attribute method if already defined in attribute module' do
+ klass = Class.new(ModelWithAttributes)
+ klass.generated_attribute_methods.module_eval do
+ def foo
+ '<3'
+ end
+ end
+ klass.define_attribute_method(:foo)
+
+ assert_equal '<3', klass.new.foo
+ end
+
+ test '#define_attribute_method generates a method that is already defined on the host' do
+ klass = Class.new(ModelWithAttributes) do
+ def foo
+ super
+ end
+ end
+ klass.define_attribute_method(:foo)
+
+ assert_equal 'value of foo', klass.new.foo
+ end
+
test '#define_attribute_method generates attribute method with invalid identifier characters' do
ModelWithWeirdNamesAttributes.define_attribute_method(:'a?b')
@@ -129,4 +165,64 @@ class AttributeMethodsTest < ActiveModel::TestCase
assert !ModelWithAttributes.new.respond_to?(:foo)
assert_raises(NoMethodError) { ModelWithAttributes.new.foo }
end
+
+ test 'acessing a suffixed attribute' do
+ m = ModelWithAttributes2.new
+ m.attributes = { 'foo' => 'bar' }
+
+ assert_equal 'bar', m.foo
+ assert_equal 'bar', m.foo_test
+ end
+
+ test 'explicitly specifying an empty prefix/suffix is deprecated' do
+ klass = Class.new(ModelWithAttributes)
+
+ assert_deprecated { klass.attribute_method_suffix '' }
+ assert_deprecated { klass.attribute_method_prefix '' }
+
+ klass.define_attribute_methods([:foo])
+
+ assert_equal 'value of foo', klass.new.foo
+ end
+
+ test 'should not interfere with method_missing if the attr has a private/protected method' do
+ m = ModelWithAttributes2.new
+ m.attributes = { 'private_method' => '<3', 'protected_method' => 'O_o' }
+
+ # dispatches to the *method*, not the attribute
+ assert_equal '<3 <3', m.send(:private_method)
+ assert_equal 'O_o O_o', m.send(:protected_method)
+
+ # sees that a method is already defined, so doesn't intervene
+ assert_raises(NoMethodError) { m.private_method }
+ assert_raises(NoMethodError) { m.protected_method }
+ end
+
+ test 'should not interfere with respond_to? if the attribute has a private/protected method' do
+ m = ModelWithAttributes2.new
+ m.attributes = { 'private_method' => '<3', 'protected_method' => 'O_o' }
+
+ assert !m.respond_to?(:private_method)
+ assert m.respond_to?(:private_method, true)
+
+ # This is messed up, but it's how Ruby works at the moment. Apparently it will be changed
+ # in the future.
+ assert m.respond_to?(:protected_method)
+ assert m.respond_to?(:protected_method, true)
+ end
+
+ test 'should use attribute_missing to dispatch a missing attribute' do
+ m = ModelWithAttributes2.new
+ m.attributes = { 'foo' => 'bar' }
+
+ def m.attribute_missing(match, *args, &block)
+ match
+ end
+
+ match = m.foo_test
+
+ assert_equal 'foo', match.attr_name
+ assert_equal 'attribute_test', match.target
+ assert_equal 'foo_test', match.method_name
+ end
end
diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb
index da109a8738..4c76bb43a8 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -52,7 +52,6 @@ class ErrorsTest < ActiveModel::TestCase
person.validate!
assert_equal ["name can not be nil"], person.errors.full_messages
assert_equal ["can not be nil"], person.errors[:name]
-
end
test 'should be able to assign error' do
@@ -78,7 +77,6 @@ class ErrorsTest < ActiveModel::TestCase
person.errors.add(:name, "can not be blank")
person.errors.add(:name, "can not be nil")
assert_equal ["name can not be blank", "name can not be nil"], person.errors.to_a
-
end
test 'to_hash should return an ordered hash' do
@@ -86,4 +84,33 @@ class ErrorsTest < ActiveModel::TestCase
person.errors.add(:name, "can not be blank")
assert_instance_of ActiveSupport::OrderedHash, person.errors.to_hash
end
+
+ test 'full_messages should return an array of error messages, with the attribute name included' do
+ person = Person.new
+ person.errors.add(:name, "can not be blank")
+ person.errors.add(:name, "can not be nil")
+ assert_equal ["name can not be blank", "name can not be nil"], person.errors.to_a
+ end
+
+ test 'full_message should return the given message if attribute equals :base' do
+ person = Person.new
+ assert_equal "press the button", person.errors.full_message(:base, "press the button")
+ end
+
+ test 'full_message should return the given message with the attribute name included' do
+ person = Person.new
+ assert_equal "name can not be blank", person.errors.full_message(:name, "can not be blank")
+ end
+
+ test 'should return a JSON hash representation of the errors' do
+ person = Person.new
+ person.errors.add(:name, "can not be blank")
+ person.errors.add(:name, "can not be nil")
+ person.errors.add(:email, "is invalid")
+ hash = person.errors.as_json
+ assert_equal ["can not be blank", "can not be nil"], hash[:name]
+ assert_equal ["is invalid"], hash[:email]
+ end
+
end
+
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index e82906186e..a54526dd41 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -4,10 +4,12 @@ Wed Sep 7 15:25:02 2011 Aaron Patterson <aaron@tenderlovemaking.com>
keys are per process id.
* lib/active_record/connection_adapters/sqlite_adapter.rb: ditto
-* Add first_or_create, first_or_create!, first_or_build and first_or_new methods to Active Record. This is a better approach over the old find_or_create_by dynamic methods because it's clearer which arguments are used to find the record and which are used to create it:
+* Add first_or_create, first_or_create!, first_or_initialize methods to Active Record. This is a
+ better approach over the old find_or_create_by dynamic methods because it's clearer which
+ arguments are used to find the record and which are used to create it:
+
+ User.where(:first_name => "Scarlett").first_or_create!(:last_name => "Johansson")
- User.where(:first_name => "Scarlett").first_or_create!(:last_name => "Johansson", :hot => true)
-
[Andrés Mejía]
* Support bulk change_table in mysql2 adapter, as well as the mysql one. [Jon Leighton]
@@ -34,7 +36,7 @@ a URI that specifies the connection configuration. For example:
[Prem Sichanugrist]
-*Rails 3.1.0 (unreleased)*
+*Rails 3.1.0 (August 30, 2011)*
* Add a proxy_association method to association proxies, which can be called by association
extensions to access information about the association. This replaces proxy_owner etc with
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 8d755b6848..9e7d609d19 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1329,7 +1329,7 @@ module ActiveRecord
#
# [:class_name]
# Specify the class name of the association. Use it only if that name can't be inferred
- # from the association name. So <tt>has_one :author</tt> will by default be linked to the Author class, but
+ # from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
# if the real class name is Person, you'll have to specify it with this option.
# [:conditions]
# Specify the conditions that the associated object must meet in order to be included as a +WHERE+
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index d0687ed0b6..d7bfaa5655 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/enumerable'
+require 'active_support/deprecation'
module ActiveRecord
# = Active Record Attribute Methods
@@ -11,56 +12,83 @@ module ActiveRecord
# accessors, mutators and query methods.
def define_attribute_methods
return if attribute_methods_generated?
- super(column_names)
- @attribute_methods_generated = true
+
+ if base_class == self
+ super(column_names)
+ @attribute_methods_generated = true
+ else
+ base_class.define_attribute_methods
+ end
end
def attribute_methods_generated?
- @attribute_methods_generated ||= false
+ if base_class == self
+ @attribute_methods_generated ||= false
+ else
+ base_class.attribute_methods_generated?
+ end
end
def undefine_attribute_methods(*args)
- super
- @attribute_methods_generated = false
+ if base_class == self
+ super
+ @attribute_methods_generated = false
+ else
+ base_class.undefine_attribute_methods(*args)
+ end
end
- # Checks whether the method is defined in the model or any of its subclasses
- # that also derive from Active Record. Raises DangerousAttributeError if the
- # method is defined by Active Record though.
def instance_method_already_implemented?(method_name)
- method_name = method_name.to_s
- index = ancestors.index(ActiveRecord::Base) || ancestors.length
- @_defined_class_methods ||= ancestors.first(index).map { |m|
- m.instance_methods(false) | m.private_instance_methods(false)
- }.flatten.map {|m| m.to_s }.to_set
+ if dangerous_attribute_method?(method_name)
+ raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord"
+ end
- @@_defined_activerecord_methods ||= defined_activerecord_methods
- raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord" if @@_defined_activerecord_methods.include?(method_name)
- @_defined_class_methods.include?(method_name)
+ super
end
- def defined_activerecord_methods
+ # A method name is 'dangerous' if it is already defined by Active Record, but
+ # not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
+ def dangerous_attribute_method?(method_name)
active_record = ActiveRecord::Base
- super_klass = ActiveRecord::Base.superclass
- methods = (active_record.instance_methods - super_klass.instance_methods) +
- (active_record.private_instance_methods - super_klass.private_instance_methods)
- methods.map {|m| m.to_s }.to_set
+ superclass = ActiveRecord::Base.superclass
+
+ (active_record.method_defined?(method_name) ||
+ active_record.private_method_defined?(method_name)) &&
+ !superclass.method_defined?(method_name) &&
+ !superclass.private_method_defined?(method_name)
end
end
- def method_missing(method_id, *args, &block)
- # If we haven't generated any methods yet, generate them, then
- # see if we've created the method we're looking for.
- if !self.class.attribute_methods_generated?
+ # If we haven't generated any methods yet, generate them, then
+ # see if we've created the method we're looking for.
+ def method_missing(method, *args, &block)
+ unless self.class.attribute_methods_generated?
self.class.define_attribute_methods
- method_name = method_id.to_s
- guard_private_attribute_method!(method_name, args)
- send(method_id, *args, &block)
+
+ if respond_to_without_attributes?(method)
+ send(method, *args, &block)
+ else
+ super
+ end
else
super
end
end
+ def attribute_missing(match, *args, &block)
+ if self.class.columns_hash[match.attr_name]
+ ActiveSupport::Deprecation.warn(
+ "The method `#{match.method_name}', matching the attribute `#{match.attr_name}' has " \
+ "dispatched through method_missing. This shouldn't happen, because `#{match.attr_name}' " \
+ "is a column of the table. If this error has happened through normal usage of Active " \
+ "Record (rather than through your own code or external libraries), please report it as " \
+ "a bug."
+ )
+ end
+
+ super
+ end
+
def respond_to?(name, include_private = false)
self.class.define_attribute_methods unless self.class.attribute_methods_generated?
super
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 9a50a20fbc..4174e4da09 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -6,8 +6,6 @@ module ActiveRecord
ATTRIBUTE_TYPES_CACHED_BY_DEFAULT = [:datetime, :timestamp, :time, :date]
included do
- attribute_method_suffix ""
-
cattr_accessor :attribute_types_cached_by_default, :instance_writer => false
self.attribute_types_cached_by_default = ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index c77a3ac145..e9cdb130db 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -17,6 +17,10 @@ module ActiveRecord
write_attribute(attr_name, new_value)
end
end
+
+ if attr_name == primary_key && attr_name != "id"
+ generated_attribute_methods.module_eval("alias :id= :'#{primary_key}='")
+ end
end
end
@@ -24,12 +28,16 @@ module ActiveRecord
# for fixnum and float columns are turned into +nil+.
def write_attribute(attr_name, value)
attr_name = attr_name.to_s
- attr_name = self.class.primary_key if attr_name == 'id'
+ attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
@attributes_cache.delete(attr_name)
- if (column = column_for_attribute(attr_name)) && column.number?
+ column = column_for_attribute(attr_name)
+
+ if column && column.number?
@attributes[attr_name] = convert_number_column_value(value)
- else
+ elsif column || @attributes.has_key?(attr_name)
@attributes[attr_name] = value
+ else
+ raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'"
end
end
alias_method :raw_write_attribute, :write_attribute
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index 085fdba639..056170d82a 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -370,7 +370,10 @@ module ActiveRecord
else
key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id
if autosave != false && (new_record? || record.new_record? || record[reflection.foreign_key] != key || autosave)
- record[reflection.foreign_key] = key
+ unless reflection.through_reflection
+ record[reflection.foreign_key] = key
+ end
+
saved = record.save(:validate => !autosave)
raise ActiveRecord::Rollback if !saved && autosave
saved
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 2979ad1cb3..558b341c06 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -442,7 +442,7 @@ module ActiveRecord #:nodoc:
class << self # Class methods
delegate :find, :first, :first!, :last, :last!, :all, :exists?, :any?, :many?, :to => :scoped
- delegate :first_or_create, :first_or_create!, :first_or_new, :first_or_build, :to => :scoped
+ delegate :first_or_create, :first_or_create!, :first_or_initialize, :to => :scoped
delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :scoped
delegate :find_each, :find_in_batches, :to => :scoped
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :to => :scoped
@@ -1332,7 +1332,7 @@ MSG
# Returns the class descending directly from ActiveRecord::Base or an
# abstract class, if any, in the inheritance hierarchy.
def class_of_active_record_descendant(klass)
- if klass.superclass == Base || klass.superclass.abstract_class?
+ if klass == Base || klass.superclass == Base || klass.superclass.abstract_class?
klass
elsif klass.superclass.nil?
raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 2dac9ea0fb..5e65e46a7d 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -314,7 +314,7 @@ module ActiveRecord
new_id = self.class.unscoped.insert attributes_values
- self.id ||= new_id
+ self.id ||= new_id if self.class.primary_key
IdentityMap.add(self) if IdentityMap.enabled?
@new_record = false
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 13c41350fb..b3316fd1a2 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -203,11 +203,13 @@ db_namespace = namespace :db do
end
db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}")
file_list = []
- Dir.foreach(File.join(Rails.root, 'db', 'migrate')) do |file|
- # only files matching "20091231235959_some_name.rb" pattern
- if match_data = /^(\d{14})_(.+)\.rb$/.match(file)
- status = db_list.delete(match_data[1]) ? 'up' : 'down'
- file_list << [status, match_data[1], match_data[2].humanize]
+ ActiveRecord::Migrator.migrations_paths.each do |path|
+ Dir.foreach(path) do |file|
+ # only files matching "20091231235959_some_name.rb" pattern
+ if match_data = /^(\d{14})_(.+)\.rb$/.match(file)
+ status = db_list.delete(match_data[1]) ? 'up' : 'down'
+ file_list << [status, match_data[1], match_data[2].humanize]
+ end
end
end
db_list.map! do |version|
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index d3f1347e03..ecefaa633c 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -132,10 +132,9 @@ module ActiveRecord
# Like <tt>first_or_create</tt> but calls <tt>new</tt> instead of <tt>create</tt>.
#
# Expects arguments in the same format as <tt>Base.new</tt>.
- def first_or_new(attributes = nil, options = {}, &block)
+ def first_or_initialize(attributes = nil, options = {}, &block)
first || new(attributes, options, &block)
end
- alias :first_or_build :first_or_new
def respond_to?(method, include_private = false)
arel.respond_to?(method, include_private) ||
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 7eda9ad8e8..a11b7a3864 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -147,6 +147,42 @@ module ActiveRecord
relation
end
+ # Used to extend a scope with additional methods, either through
+ # a module or through a block provided.
+ #
+ # The object returned is a relation, which can be further extended.
+ #
+ # === Using a module
+ #
+ # module Pagination
+ # def page(number)
+ # # pagination code goes here
+ # end
+ # end
+ #
+ # scope = Model.scoped.extending(Pagination)
+ # scope.page(params[:page])
+ #
+ # You can also pass a list of modules:
+ #
+ # scope = Model.scoped.extending(Pagination, SomethingElse)
+ #
+ # === Using a block
+ #
+ # scope = Model.scoped.extending do
+ # def page(number)
+ # # pagination code goes here
+ # end
+ # end
+ # scope.page(params[:page])
+ #
+ # You can also use a block and a module list:
+ #
+ # scope = Model.scoped.extending(Pagination) do
+ # def per_page(number)
+ # # pagination code goes here
+ # end
+ # end
def extending(*modules)
modules << Module.new(&Proc.new) if block_given?
diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb
index cccac6ffd7..4d5e469a7f 100644
--- a/activerecord/lib/active_record/timestamp.rb
+++ b/activerecord/lib/active_record/timestamp.rb
@@ -48,7 +48,9 @@ module ActiveRecord
current_time = current_time_from_proper_timezone
all_timestamp_attributes.each do |column|
- write_attribute(column.to_s, current_time) if respond_to?(column) && self.send(column).nil?
+ if respond_to?(column) && respond_to?("#{column}=") && self.send(column).nil?
+ write_attribute(column.to_s, current_time)
+ end
end
end
diff --git a/activerecord/test/cases/attribute_methods/read_test.rb b/activerecord/test/cases/attribute_methods/read_test.rb
index 3641031d12..e03ed33591 100644
--- a/activerecord/test/cases/attribute_methods/read_test.rb
+++ b/activerecord/test/cases/attribute_methods/read_test.rb
@@ -35,6 +35,7 @@ module ActiveRecord
end
def self.serialized_attributes; {}; end
+ def self.base_class; self; end
end
end
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index dbf5a1ba76..b1b41fed0d 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -431,30 +431,6 @@ class AttributeMethodsTest < ActiveRecord::TestCase
assert topic.is_test?
end
- def test_kernel_methods_not_implemented_in_activerecord
- %w(test name display y).each do |method|
- assert !ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined"
- end
- end
-
- def test_defined_kernel_methods_implemented_in_model
- %w(test name display y).each do |method|
- klass = Class.new ActiveRecord::Base
- klass.class_eval "def #{method}() 'defined #{method}' end"
- assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
- end
- end
-
- def test_defined_kernel_methods_implemented_in_model_abstract_subclass
- %w(test name display y).each do |method|
- abstract = Class.new ActiveRecord::Base
- abstract.class_eval "def #{method}() 'defined #{method}' end"
- abstract.abstract_class = true
- klass = Class.new abstract
- assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
- end
- end
-
def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
%w(save create_or_update).each do |method|
klass = Class.new ActiveRecord::Base
@@ -608,7 +584,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
topic = @target.new(:title => "The pros and cons of programming naked.")
assert !topic.respond_to?(:title)
exception = assert_raise(NoMethodError) { topic.title }
- assert_match %r(^Attempt to call private method), exception.message
+ assert exception.message.include?("private method")
assert_equal "I'm private", topic.send(:title)
end
@@ -618,7 +594,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
topic = @target.new
assert !topic.respond_to?(:title=)
exception = assert_raise(NoMethodError) { topic.title = "Pants"}
- assert_match %r(^Attempt to call private method), exception.message
+ assert exception.message.include?("private method")
topic.send(:title=, "Very large pants")
end
@@ -628,7 +604,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
topic = @target.new(:title => "Isaac Newton's pants")
assert !topic.respond_to?(:title?)
exception = assert_raise(NoMethodError) { topic.title? }
- assert_match %r(^Attempt to call private method), exception.message
+ assert exception.message.include?("private method")
assert topic.send(:title?)
end
@@ -659,6 +635,37 @@ class AttributeMethodsTest < ActiveRecord::TestCase
assert_equal %w(preferences), Contact.serialized_attributes.keys
end
+ def test_instance_method_should_be_defined_on_the_base_class
+ subklass = Class.new(Topic)
+
+ Topic.define_attribute_methods
+
+ instance = subklass.new
+ instance.id = 5
+ assert_equal 5, instance.id
+ assert subklass.method_defined?(:id), "subklass is missing id method"
+
+ Topic.undefine_attribute_methods
+
+ assert_equal 5, instance.id
+ assert subklass.method_defined?(:id), "subklass is missing id method"
+ end
+
+ def test_dispatching_column_attributes_through_method_missing_deprecated
+ Topic.define_attribute_methods
+
+ topic = Topic.new(:id => 5)
+ topic.id = 5
+
+ topic.method(:id).owner.send(:remove_method, :id)
+
+ assert_deprecated do
+ assert_equal 5, topic.id
+ end
+ ensure
+ Topic.undefine_attribute_methods
+ end
+
private
def cached_columns
@cached_columns ||= (time_related_columns_on_topic + serialized_columns_on_topic).map(&:name)
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 63879259af..12c1cfb30e 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -22,6 +22,7 @@ require 'models/person'
require 'models/edge'
require 'models/joke'
require 'models/bulb'
+require 'models/bird'
require 'rexml/document'
require 'active_support/core_ext/exception'
require 'bcrypt'
@@ -293,16 +294,8 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal parrot, the_same_parrot
end
- def test_first_or_new
- parrot = Bird.first_or_new(:color => 'green', :name => 'parrot')
- assert_kind_of Bird, parrot
- assert !parrot.persisted?
- assert parrot.new_record?
- assert parrot.valid?
- end
-
- def test_first_or_build
- parrot = Bird.first_or_build(:color => 'green', :name => 'parrot')
+ def test_first_or_initialize
+ parrot = Bird.first_or_initialize(:color => 'green', :name => 'parrot')
assert_kind_of Bird, parrot
assert !parrot.persisted?
assert parrot.new_record?
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index 9cd07fa8a5..adfd8e83a1 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -202,9 +202,12 @@ class PersistencesTest < ActiveRecord::TestCase
end
def test_create_columns_not_equal_attributes
- topic = Topic.new
- topic.title = 'Another New Topic'
- topic.send :write_attribute, 'does_not_exist', 'test'
+ topic = Topic.allocate.init_with(
+ 'attributes' => {
+ 'title' => 'Another New Topic',
+ 'does_not_exist' => 'test'
+ }
+ )
assert_nothing_raised { topic.save }
end
@@ -249,9 +252,11 @@ class PersistencesTest < ActiveRecord::TestCase
topic.title = "Still another topic"
topic.save
- topicReloaded = Topic.find(topic.id)
- topicReloaded.title = "A New Topic"
- topicReloaded.send :write_attribute, 'does_not_exist', 'test'
+ topicReloaded = Topic.allocate
+ topicReloaded.init_with(
+ 'attributes' => topic.attributes.merge('does_not_exist' => 'test')
+ )
+ topicReloaded.title = 'A New Topic'
assert_nothing_raised { topicReloaded.save }
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index b491d63047..95408a5f29 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -938,7 +938,7 @@ class RelationTest < ActiveRecord::TestCase
def test_first_or_create_bang_with_invalid_block
assert_raise(ActiveRecord::RecordInvalid) do
- parrot = Bird.where(:color => 'green').first_or_create! { |bird| bird.pirate_id = 1 }
+ Bird.where(:color => 'green').first_or_create! { |bird| bird.pirate_id = 1 }
end
end
@@ -956,8 +956,8 @@ class RelationTest < ActiveRecord::TestCase
assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create!([ {:name => 'parrot'}, {:pirate_id => 1} ]) }
end
- def test_first_or_new
- parrot = Bird.where(:color => 'green').first_or_new(:name => 'parrot')
+ def test_first_or_initialize
+ parrot = Bird.where(:color => 'green').first_or_initialize(:name => 'parrot')
assert_kind_of Bird, parrot
assert !parrot.persisted?
assert parrot.valid?
@@ -966,8 +966,8 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 'green', parrot.color
end
- def test_first_or_new_with_no_parameters
- parrot = Bird.where(:color => 'green').first_or_new
+ def test_first_or_initialize_with_no_parameters
+ parrot = Bird.where(:color => 'green').first_or_initialize
assert_kind_of Bird, parrot
assert !parrot.persisted?
assert !parrot.valid?
@@ -975,8 +975,8 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 'green', parrot.color
end
- def test_first_or_new_with_block
- parrot = Bird.where(:color => 'green').first_or_new { |bird| bird.name = 'parrot' }
+ def test_first_or_initialize_with_block
+ parrot = Bird.where(:color => 'green').first_or_initialize { |bird| bird.name = 'parrot' }
assert_kind_of Bird, parrot
assert !parrot.persisted?
assert parrot.valid?
@@ -985,12 +985,6 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 'parrot', parrot.name
end
- def test_first_or_build_is_alias_for_first_or_new
- birds = Bird.scoped
- assert birds.respond_to?(:first_or_build)
- assert_equal birds.method(:first_or_new), birds.method(:first_or_build)
- end
-
def test_explicit_create_scope
hens = Bird.where(:name => 'hen')
assert_equal 'hen', hens.new.name
diff --git a/activerecord/test/cases/serialization_test.rb b/activerecord/test/cases/serialization_test.rb
index 382d659289..61b04b3e37 100644
--- a/activerecord/test/cases/serialization_test.rb
+++ b/activerecord/test/cases/serialization_test.rb
@@ -7,12 +7,13 @@ class SerializationTest < ActiveRecord::TestCase
def setup
@contact_attributes = {
- :name => 'aaron stack',
- :age => 25,
- :avatar => 'binarydata',
- :created_at => Time.utc(2006, 8, 1),
- :awesome => false,
- :preferences => { :gem => '<strong>ruby</strong>' }
+ :name => 'aaron stack',
+ :age => 25,
+ :avatar => 'binarydata',
+ :created_at => Time.utc(2006, 8, 1),
+ :awesome => false,
+ :preferences => { :gem => '<strong>ruby</strong>' },
+ :alternative_id => nil
}
end
diff --git a/activerecord/test/cases/session_store/session_test.rb b/activerecord/test/cases/session_store/session_test.rb
index 669c0b7b4d..258cee7aba 100644
--- a/activerecord/test/cases/session_store/session_test.rb
+++ b/activerecord/test/cases/session_store/session_test.rb
@@ -36,6 +36,7 @@ module ActiveRecord
end
def test_find_by_sess_id_compat
+ Session.reset_column_information
klass = Class.new(Session) do
def self.session_id_column
'sessid'
@@ -53,6 +54,7 @@ module ActiveRecord
assert_equal session.sessid, found.session_id
ensure
klass.drop_table!
+ Session.reset_column_information
end
def test_find_by_session_id
diff --git a/activerecord/test/models/contact.rb b/activerecord/test/models/contact.rb
index e081eee661..3d15c7fbed 100644
--- a/activerecord/test/models/contact.rb
+++ b/activerecord/test/models/contact.rb
@@ -11,12 +11,13 @@ class Contact < ActiveRecord::Base
connection.merge_column('contacts', name, sql_type, options)
end
- column :name, :string
- column :age, :integer
- column :avatar, :binary
- column :created_at, :datetime
- column :awesome, :boolean
- column :preferences, :string
+ column :name, :string
+ column :age, :integer
+ column :avatar, :binary
+ column :created_at, :datetime
+ column :awesome, :boolean
+ column :preferences, :string
+ column :alternative_id, :integer
serialize :preferences
diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb
index 6440dbe8ab..fe424e61b2 100644
--- a/activerecord/test/models/topic.rb
+++ b/activerecord/test/models/topic.rb
@@ -78,11 +78,12 @@ class Topic < ActiveRecord::Base
after_initialize :set_email_address
+ def approved=(val)
+ @custom_approved = val
+ write_attribute(:approved, val)
+ end
+
protected
- def approved=(val)
- @custom_approved = val
- write_attribute(:approved, val)
- end
def default_written_on
self.written_on = Time.now unless attribute_present?("written_on")
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 4b3afce812..62cfe3ae94 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -47,6 +47,7 @@ ActiveRecord::Schema.define do
create_table :audit_logs, :force => true do |t|
t.column :message, :string, :null=>false
t.column :developer_id, :integer, :null=>false
+ t.integer :unvalidated_developer_id
end
create_table :authors, :force => true do |t|
@@ -157,6 +158,7 @@ ActiveRecord::Schema.define do
t.string :type
t.integer :taggings_count, :default => 0
t.integer :children_count, :default => 0
+ t.integer :parent_id
end
create_table :companies, :force => true do |t|
@@ -462,6 +464,7 @@ ActiveRecord::Schema.define do
create_table :pirates, :force => true do |t|
t.column :catchphrase, :string
t.column :parrot_id, :integer
+ t.integer :non_validated_parrot_id
t.column :created_on, :datetime
t.column :updated_on, :datetime
end
@@ -530,6 +533,7 @@ ActiveRecord::Schema.define do
create_table :ships, :force => true do |t|
t.string :name
t.integer :pirate_id
+ t.integer :update_only_pirate_id
t.datetime :created_at
t.datetime :created_on
t.datetime :updated_at
@@ -664,7 +668,9 @@ ActiveRecord::Schema.define do
t.string :description
t.integer :man_id
t.integer :polymorphic_man_id
- t.string :polymorphic_man_type
+ t.string :polymorphic_man_type
+ t.integer :horrible_polymorphic_man_id
+ t.string :horrible_polymorphic_man_type
end
create_table :interests, :force => true do |t|
diff --git a/activeresource/CHANGELOG b/activeresource/CHANGELOG
index 25f9242b98..fe356d7691 100644
--- a/activeresource/CHANGELOG
+++ b/activeresource/CHANGELOG
@@ -1,4 +1,4 @@
-*Rails 3.1.0 (unreleased)*
+*Rails 3.1.0 (August 30, 2011)*
* The default format has been changed to JSON for all requests. If you want to continue to use XML you will need to set `self.format = :xml` in the class. eg.
diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb
index 990d9a38dd..1ffd83b91d 100644
--- a/activeresource/lib/active_resource/base.rb
+++ b/activeresource/lib/active_resource/base.rb
@@ -1357,7 +1357,9 @@ module ActiveResource
end
def load_attributes_from_response(response)
- if !response['Content-Length'].blank? && response['Content-Length'] != "0" && !response.body.nil? && response.body.strip.size > 0
+ if (response_code_allows_body?(response.code) &&
+ (response['Content-Length'].nil? || response['Content-Length'] != "0") &&
+ !response.body.nil? && response.body.strip.size > 0)
load(self.class.format.decode(response.body), true)
@persisted = true
end
@@ -1381,6 +1383,12 @@ module ActiveResource
end
private
+
+ # Determine whether the response is allowed to have a body per HTTP 1.1 spec section 4.4.1
+ def response_code_allows_body?(c)
+ !((100..199).include?(c) || [204,304].include?(c))
+ end
+
# Tries to find a resource for a given collection name; if it fails, then the resource is created
def find_or_create_resource_for_collection(name)
find_or_create_resource_for(ActiveSupport::Inflector.singularize(name.to_s))
diff --git a/activeresource/test/cases/base/load_test.rb b/activeresource/test/cases/base/load_test.rb
index 0bbd3ab5f5..784e7dd036 100644
--- a/activeresource/test/cases/base/load_test.rb
+++ b/activeresource/test/cases/base/load_test.rb
@@ -66,11 +66,11 @@ class BaseLoadTest < Test::Unit::TestCase
end
def test_load_hash_with_integers_as_keys
- assert_nothing_raised{person = @person.load(@books)}
+ assert_nothing_raised{@person.load(@books)}
end
def test_load_hash_with_dates_as_keys
- assert_nothing_raised{person = @person.load(@books_date)}
+ assert_nothing_raised{@person.load(@books_date)}
end
def test_load_expects_hash
diff --git a/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb
index f45652d988..d4063fa299 100644
--- a/activeresource/test/cases/base_test.rb
+++ b/activeresource/test/cases/base_test.rb
@@ -636,13 +636,37 @@ class BaseTest < Test::Unit::TestCase
assert_nil p.__send__(:id_from_response, resp)
end
- def test_load_attributes_from_response
- p = Person.new
+ def test_not_persisted_with_no_body_and_positive_content_length
resp = ActiveResource::Response.new(nil)
resp['Content-Length'] = "100"
- assert_nil p.__send__(:load_attributes_from_response, resp)
+ Person.connection.expects(:post).returns(resp)
+ assert !Person.create.persisted?
+ end
+
+ def test_not_persisted_with_body_and_zero_content_length
+ resp = ActiveResource::Response.new(@rick)
+ resp['Content-Length'] = "0"
+ Person.connection.expects(:post).returns(resp)
+ assert !Person.create.persisted?
end
+ # These response codes aren't allowed to have bodies per HTTP spec
+ def test_not_persisted_with_empty_response_codes
+ [100,101,204,304].each do |status_code|
+ resp = ActiveResource::Response.new(@rick, status_code)
+ Person.connection.expects(:post).returns(resp)
+ assert !Person.create.persisted?
+ end
+ end
+
+ # Content-Length is not required by HTTP 1.1, so we should read
+ # the body anyway in its absence.
+ def test_persisted_with_no_content_length
+ resp = ActiveResource::Response.new(@rick)
+ resp['Content-Length'] = nil
+ Person.connection.expects(:post).returns(resp)
+ assert Person.create.persisted?
+ end
def test_create_with_custom_prefix
matzs_house = StreetAddress.new(:person_id => 1)
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 18164234a5..537980d6a1 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -20,7 +20,7 @@ Also, in 1.8 the ideographic space U+3000 is considered to be whitespace. [Akira
* ActiveSupport::OrderedHash now has different behavior for #each and
#each_pair when given a block accepting its parameters with a splat. [Andrew Radev]
-*Rails 3.1.0 (unreleased)*
+*Rails 3.1.0 (August 30, 2011)*
* ActiveSupport::Dependencies#load and ActiveSupport::Dependencies#require now
return the value from `super` [Aaron Patterson]
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index ec2c717942..63279d0e6d 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -12,7 +12,7 @@ module ActiveSupport
#
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
# Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
- # Time.zone.parse('2007-02-01 15:30:45') # => Sat, 10 Feb 2007 15:30:45 EST -05:00
+ # Time.zone.parse('2007-02-10 15:30:45') # => Sat, 10 Feb 2007 15:30:45 EST -05:00
# Time.zone.at(1170361845) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
# Time.zone.now # => Sun, 18 May 2008 13:07:55 EDT -04:00
# Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45 EST -05:00
diff --git a/bin/rails b/bin/rails
deleted file mode 100755
index f9725d78d0..0000000000
--- a/bin/rails
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env ruby
-
-if File.exists?(File.join(File.expand_path('../..', __FILE__), '.git'))
- railties_path = File.expand_path('../../railties/lib', __FILE__)
- $:.unshift(railties_path)
-end
-require "rails/cli"
diff --git a/rails.gemspec b/rails.gemspec
index bb3fe85c2b..3377b4e175 100644
--- a/rails.gemspec
+++ b/rails.gemspec
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
s.homepage = 'http://www.rubyonrails.org'
s.bindir = 'bin'
- s.executables = ['rails']
+ s.executables = []
s.add_dependency('activesupport', version)
s.add_dependency('actionpack', version)
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 6ed76974b4..72e5921d6d 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -10,7 +10,7 @@
* Removed old 'config.paths.app.controller' API in favor of 'config.paths["app/controller"]' API. [Guillermo Iguaran]
-*Rails 3.1.0 (unreleased)*
+*Rails 3.1.0 (August 30, 2011)*
* The default database schema file is written as UTF-8. [Aaron Patterson]
diff --git a/railties/Rakefile b/railties/Rakefile
index be9a77d4e4..25e515e016 100755
--- a/railties/Rakefile
+++ b/railties/Rakefile
@@ -17,8 +17,13 @@ namespace :test do
dir = ENV["TEST_DIR"] || "**"
Dir["test/#{dir}/*_test.rb"].each do |file|
next true if file.include?("fixtures")
- ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
- sh(ruby, '-Itest', "-I#{File.dirname(__FILE__)}/../activesupport/lib", file)
+ dash_i = [
+ 'test',
+ 'lib',
+ "#{File.dirname(__FILE__)}/../activesupport/lib",
+ "#{File.dirname(__FILE__)}/../actionpack/lib"
+ ]
+ ruby "-I#{dash_i.join ':'}", file
end
end
end
diff --git a/railties/bin/rails b/railties/bin/rails
index a7d6938e0d..a1c4faaa73 100755
--- a/railties/bin/rails
+++ b/railties/bin/rails
@@ -1,2 +1,7 @@
#!/usr/bin/env ruby
-require "rails/cli" \ No newline at end of file
+
+if File.exists?(File.join(File.expand_path('../../..', __FILE__), '.git'))
+ railties_path = File.expand_path('../../lib', __FILE__)
+ $:.unshift(railties_path)
+end
+require "rails/cli"
diff --git a/railties/guides/code/getting_started/Gemfile b/railties/guides/code/getting_started/Gemfile
new file mode 100644
index 0000000000..51774934cd
--- /dev/null
+++ b/railties/guides/code/getting_started/Gemfile
@@ -0,0 +1,32 @@
+source 'http://rubygems.org'
+
+gem 'rails', '3.1.0'
+# Bundle edge Rails instead:
+# gem 'rails', :git => 'git://github.com/rails/rails.git'
+
+gem 'sqlite3'
+
+
+# Gems used only for assets and not required
+# in production environments by default.
+group :assets do
+ gem 'sass-rails', " ~> 3.1.0"
+ gem 'coffee-rails', "~> 3.1.0"
+ gem 'uglifier'
+end
+
+gem 'jquery-rails'
+
+# Use unicorn as the web server
+# gem 'unicorn'
+
+# Deploy with Capistrano
+# gem 'capistrano'
+
+# To use debugger
+# gem 'ruby-debug19', :require => 'ruby-debug'
+
+group :test do
+ # Pretty printed test output
+ gem 'turn', :require => false
+end
diff --git a/railties/guides/code/getting_started/README b/railties/guides/code/getting_started/README
new file mode 100644
index 0000000000..7c36f2356e
--- /dev/null
+++ b/railties/guides/code/getting_started/README
@@ -0,0 +1,261 @@
+== Welcome to Rails
+
+Rails is a web-application framework that includes everything needed to create
+database-backed web applications according to the Model-View-Control pattern.
+
+This pattern splits the view (also called the presentation) into "dumb"
+templates that are primarily responsible for inserting pre-built data in between
+HTML tags. The model contains the "smart" domain objects (such as Account,
+Product, Person, Post) that holds all the business logic and knows how to
+persist themselves to a database. The controller handles the incoming requests
+(such as Save New Account, Update Product, Show Post) by manipulating the model
+and directing data to the view.
+
+In Rails, the model is handled by what's called an object-relational mapping
+layer entitled Active Record. This layer allows you to present the data from
+database rows as objects and embellish these data objects with business logic
+methods. You can read more about Active Record in
+link:files/vendor/rails/activerecord/README.html.
+
+The controller and view are handled by the Action Pack, which handles both
+layers by its two parts: Action View and Action Controller. These two layers
+are bundled in a single package due to their heavy interdependence. This is
+unlike the relationship between the Active Record and Action Pack that is much
+more separate. Each of these packages can be used independently outside of
+Rails. You can read more about Action Pack in
+link:files/vendor/rails/actionpack/README.html.
+
+
+== Getting Started
+
+1. At the command prompt, create a new Rails application:
+ <tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name)
+
+2. Change directory to <tt>myapp</tt> and start the web server:
+ <tt>cd myapp; rails server</tt> (run with --help for options)
+
+3. Go to http://localhost:3000/ and you'll see:
+ "Welcome aboard: You're riding Ruby on Rails!"
+
+4. Follow the guidelines to start developing your application. You can find
+the following resources handy:
+
+* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html
+* Ruby on Rails Tutorial Book: http://www.railstutorial.org/
+
+
+== Debugging Rails
+
+Sometimes your application goes wrong. Fortunately there are a lot of tools that
+will help you debug it and get it back on the rails.
+
+First area to check is the application log files. Have "tail -f" commands
+running on the server.log and development.log. Rails will automatically display
+debugging and runtime information to these files. Debugging info will also be
+shown in the browser on requests from 127.0.0.1.
+
+You can also log your own messages directly into the log file from your code
+using the Ruby logger class from inside your controllers. Example:
+
+ class WeblogController < ActionController::Base
+ def destroy
+ @weblog = Weblog.find(params[:id])
+ @weblog.destroy
+ logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
+ end
+ end
+
+The result will be a message in your log file along the lines of:
+
+ Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1!
+
+More information on how to use the logger is at http://www.ruby-doc.org/core/
+
+Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are
+several books available online as well:
+
+* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe)
+* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
+
+These two books will bring you up to speed on the Ruby language and also on
+programming in general.
+
+
+== Debugger
+
+Debugger support is available through the debugger command when you start your
+Mongrel or WEBrick server with --debugger. This means that you can break out of
+execution at any point in the code, investigate and change the model, and then,
+resume execution! You need to install ruby-debug to run the server in debugging
+mode. With gems, use <tt>sudo gem install ruby-debug</tt>. Example:
+
+ class WeblogController < ActionController::Base
+ def index
+ @posts = Post.all
+ debugger
+ end
+ end
+
+So the controller will accept the action, run the first line, then present you
+with a IRB prompt in the server window. Here you can do things like:
+
+ >> @posts.inspect
+ => "[#<Post:0x14a6be8
+ @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>,
+ #<Post:0x14a6620
+ @attributes={"title"=>"Rails", "body"=>"Only ten..", "id"=>"2"}>]"
+ >> @posts.first.title = "hello from a debugger"
+ => "hello from a debugger"
+
+...and even better, you can examine how your runtime objects actually work:
+
+ >> f = @posts.first
+ => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
+ >> f.
+ Display all 152 possibilities? (y or n)
+
+Finally, when you're ready to resume execution, you can enter "cont".
+
+
+== Console
+
+The console is a Ruby shell, which allows you to interact with your
+application's domain model. Here you'll have all parts of the application
+configured, just like it is when the application is running. You can inspect
+domain models, change values, and save to the database. Starting the script
+without arguments will launch it in the development environment.
+
+To start the console, run <tt>rails console</tt> from the application
+directory.
+
+Options:
+
+* Passing the <tt>-s, --sandbox</tt> argument will rollback any modifications
+ made to the database.
+* Passing an environment name as an argument will load the corresponding
+ environment. Example: <tt>rails console production</tt>.
+
+To reload your controllers and models after launching the console run
+<tt>reload!</tt>
+
+More information about irb can be found at:
+link:http://www.rubycentral.org/pickaxe/irb.html
+
+
+== dbconsole
+
+You can go to the command line of your database directly through <tt>rails
+dbconsole</tt>. You would be connected to the database with the credentials
+defined in database.yml. Starting the script without arguments will connect you
+to the development database. Passing an argument will connect you to a different
+database, like <tt>rails dbconsole production</tt>. Currently works for MySQL,
+PostgreSQL and SQLite 3.
+
+== Description of Contents
+
+The default directory structure of a generated Ruby on Rails application:
+
+ |-- app
+ | |-- assets
+ | |-- images
+ | |-- javascripts
+ | `-- stylesheets
+ | |-- controllers
+ | |-- helpers
+ | |-- mailers
+ | |-- models
+ | `-- views
+ | `-- layouts
+ |-- config
+ | |-- environments
+ | |-- initializers
+ | `-- locales
+ |-- db
+ |-- doc
+ |-- lib
+ | `-- tasks
+ |-- log
+ |-- public
+ |-- script
+ |-- test
+ | |-- fixtures
+ | |-- functional
+ | |-- integration
+ | |-- performance
+ | `-- unit
+ |-- tmp
+ | |-- cache
+ | |-- pids
+ | |-- sessions
+ | `-- sockets
+ `-- vendor
+ |-- assets
+ `-- stylesheets
+ `-- plugins
+
+app
+ Holds all the code that's specific to this particular application.
+
+app/assets
+ Contains subdirectories for images, stylesheets, and JavaScript files.
+
+app/controllers
+ Holds controllers that should be named like weblogs_controller.rb for
+ automated URL mapping. All controllers should descend from
+ ApplicationController which itself descends from ActionController::Base.
+
+app/models
+ Holds models that should be named like post.rb. Models descend from
+ ActiveRecord::Base by default.
+
+app/views
+ Holds the template files for the view that should be named like
+ weblogs/index.html.erb for the WeblogsController#index action. All views use
+ eRuby syntax by default.
+
+app/views/layouts
+ Holds the template files for layouts to be used with views. This models the
+ common header/footer method of wrapping views. In your views, define a layout
+ using the <tt>layout :default</tt> and create a file named default.html.erb.
+ Inside default.html.erb, call <% yield %> to render the view using this
+ layout.
+
+app/helpers
+ Holds view helpers that should be named like weblogs_helper.rb. These are
+ generated for you automatically when using generators for controllers.
+ Helpers can be used to wrap functionality for your views into methods.
+
+config
+ Configuration files for the Rails environment, the routing map, the database,
+ and other dependencies.
+
+db
+ Contains the database schema in schema.rb. db/migrate contains all the
+ sequence of Migrations for your schema.
+
+doc
+ This directory is where your application documentation will be stored when
+ generated using <tt>rake doc:app</tt>
+
+lib
+ Application specific libraries. Basically, any kind of custom code that
+ doesn't belong under controllers, models, or helpers. This directory is in
+ the load path.
+
+public
+ The directory available for the web server. Also contains the dispatchers and the
+ default HTML files. This should be set as the DOCUMENT_ROOT of your web
+ server.
+
+script
+ Helper scripts for automation and generation.
+
+test
+ Unit and functional tests along with fixtures. When using the rails generate
+ command, template test files will be generated for you and placed in this
+ directory.
+
+vendor
+ External libraries that the application depends on. Also includes the plugins
+ subdirectory. If the app has frozen rails, those gems also go here, under
+ vendor/rails/. This directory is in the load path.
diff --git a/railties/guides/code/getting_started/Rakefile b/railties/guides/code/getting_started/Rakefile
new file mode 100644
index 0000000000..e1d1ec8615
--- /dev/null
+++ b/railties/guides/code/getting_started/Rakefile
@@ -0,0 +1,7 @@
+#!/usr/bin/env rake
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require File.expand_path('../config/application', __FILE__)
+
+Blog::Application.load_tasks
diff --git a/railties/guides/code/getting_started/app/assets/images/rails.png b/railties/guides/code/getting_started/app/assets/images/rails.png
new file mode 100644
index 0000000000..d5edc04e65
--- /dev/null
+++ b/railties/guides/code/getting_started/app/assets/images/rails.png
Binary files differ
diff --git a/railties/guides/code/getting_started/app/assets/javascripts/application.js b/railties/guides/code/getting_started/app/assets/javascripts/application.js
new file mode 100644
index 0000000000..37c7bfcdb5
--- /dev/null
+++ b/railties/guides/code/getting_started/app/assets/javascripts/application.js
@@ -0,0 +1,9 @@
+// This is a manifest file that'll be compiled into including all the files listed below.
+// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
+// be included in the compiled file accessible from http://example.com/assets/application.js
+// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+// the compiled file.
+//
+//= require jquery
+//= require jquery_ujs
+//= require_tree .
diff --git a/railties/guides/code/getting_started/app/assets/javascripts/comments.js.coffee b/railties/guides/code/getting_started/app/assets/javascripts/comments.js.coffee
new file mode 100644
index 0000000000..761567942f
--- /dev/null
+++ b/railties/guides/code/getting_started/app/assets/javascripts/comments.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
diff --git a/railties/guides/code/getting_started/app/assets/javascripts/home.js.coffee b/railties/guides/code/getting_started/app/assets/javascripts/home.js.coffee
new file mode 100644
index 0000000000..761567942f
--- /dev/null
+++ b/railties/guides/code/getting_started/app/assets/javascripts/home.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
diff --git a/railties/guides/code/getting_started/app/assets/javascripts/posts.js.coffee b/railties/guides/code/getting_started/app/assets/javascripts/posts.js.coffee
new file mode 100644
index 0000000000..761567942f
--- /dev/null
+++ b/railties/guides/code/getting_started/app/assets/javascripts/posts.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
diff --git a/railties/guides/code/getting_started/app/assets/stylesheets/application.css b/railties/guides/code/getting_started/app/assets/stylesheets/application.css
new file mode 100644
index 0000000000..fc25b5723f
--- /dev/null
+++ b/railties/guides/code/getting_started/app/assets/stylesheets/application.css
@@ -0,0 +1,7 @@
+/*
+ * This is a manifest file that'll automatically include all the stylesheets available in this directory
+ * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
+ * the top of the compiled file, but it's generally better to create a new file per style scope.
+ *= require_self
+ *= require_tree .
+*/ \ No newline at end of file
diff --git a/railties/guides/code/getting_started/app/assets/stylesheets/comments.css.scss b/railties/guides/code/getting_started/app/assets/stylesheets/comments.css.scss
new file mode 100644
index 0000000000..e730912783
--- /dev/null
+++ b/railties/guides/code/getting_started/app/assets/stylesheets/comments.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Comments controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/railties/guides/code/getting_started/app/assets/stylesheets/home.css.scss b/railties/guides/code/getting_started/app/assets/stylesheets/home.css.scss
new file mode 100644
index 0000000000..f0ddc6846a
--- /dev/null
+++ b/railties/guides/code/getting_started/app/assets/stylesheets/home.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the home controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/railties/guides/code/getting_started/app/assets/stylesheets/posts.css.scss b/railties/guides/code/getting_started/app/assets/stylesheets/posts.css.scss
new file mode 100644
index 0000000000..ed4dfd10f2
--- /dev/null
+++ b/railties/guides/code/getting_started/app/assets/stylesheets/posts.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Posts controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/railties/guides/code/getting_started/app/assets/stylesheets/scaffolds.css.scss b/railties/guides/code/getting_started/app/assets/stylesheets/scaffolds.css.scss
new file mode 100644
index 0000000000..05188f08ed
--- /dev/null
+++ b/railties/guides/code/getting_started/app/assets/stylesheets/scaffolds.css.scss
@@ -0,0 +1,56 @@
+body {
+ background-color: #fff;
+ color: #333;
+ font-family: verdana, arial, helvetica, sans-serif;
+ font-size: 13px;
+ line-height: 18px; }
+
+p, ol, ul, td {
+ font-family: verdana, arial, helvetica, sans-serif;
+ font-size: 13px;
+ line-height: 18px; }
+
+pre {
+ background-color: #eee;
+ padding: 10px;
+ font-size: 11px; }
+
+a {
+ color: #000;
+ &:visited {
+ color: #666; }
+ &:hover {
+ color: #fff;
+ background-color: #000; } }
+
+div {
+ &.field, &.actions {
+ margin-bottom: 10px; } }
+
+#notice {
+ color: green; }
+
+.field_with_errors {
+ padding: 2px;
+ background-color: red;
+ display: table; }
+
+#error_explanation {
+ width: 450px;
+ border: 2px solid red;
+ padding: 7px;
+ padding-bottom: 0;
+ margin-bottom: 20px;
+ background-color: #f0f0f0;
+ h2 {
+ text-align: left;
+ font-weight: bold;
+ padding: 5px 5px 5px 15px;
+ font-size: 12px;
+ margin: -7px;
+ margin-bottom: 0px;
+ background-color: #c00;
+ color: #fff; }
+ ul li {
+ font-size: 12px;
+ list-style: square; } }
diff --git a/railties/guides/code/getting_started/app/controllers/application_controller.rb b/railties/guides/code/getting_started/app/controllers/application_controller.rb
new file mode 100644
index 0000000000..e8065d9505
--- /dev/null
+++ b/railties/guides/code/getting_started/app/controllers/application_controller.rb
@@ -0,0 +1,3 @@
+class ApplicationController < ActionController::Base
+ protect_from_forgery
+end
diff --git a/railties/guides/code/getting_started/app/controllers/comments_controller.rb b/railties/guides/code/getting_started/app/controllers/comments_controller.rb
new file mode 100644
index 0000000000..7447fd078b
--- /dev/null
+++ b/railties/guides/code/getting_started/app/controllers/comments_controller.rb
@@ -0,0 +1,16 @@
+class CommentsController < ApplicationController
+ http_basic_authenticate_with :name => "dhh", :password => "secret", :only => :destroy
+ def create
+ @post = Post.find(params[:post_id])
+ @comment = @post.comments.create(params[:comment])
+ redirect_to post_path(@post)
+ end
+
+ def destroy
+ @post = Post.find(params[:post_id])
+ @comment = @post.comments.find(params[:id])
+ @comment.destroy
+ redirect_to post_path(@post)
+ end
+
+end
diff --git a/railties/guides/code/getting_started/app/controllers/home_controller.rb b/railties/guides/code/getting_started/app/controllers/home_controller.rb
new file mode 100644
index 0000000000..6cc31c1ca3
--- /dev/null
+++ b/railties/guides/code/getting_started/app/controllers/home_controller.rb
@@ -0,0 +1,5 @@
+class HomeController < ApplicationController
+ def index
+ end
+
+end
diff --git a/railties/guides/code/getting_started/app/controllers/posts_controller.rb b/railties/guides/code/getting_started/app/controllers/posts_controller.rb
new file mode 100644
index 0000000000..7e903c984c
--- /dev/null
+++ b/railties/guides/code/getting_started/app/controllers/posts_controller.rb
@@ -0,0 +1,84 @@
+class PostsController < ApplicationController
+ http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index
+ # GET /posts
+ # GET /posts.json
+ def index
+ @posts = Post.all
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.json { render json: @posts }
+ end
+ end
+
+ # GET /posts/1
+ # GET /posts/1.json
+ def show
+ @post = Post.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.json { render json: @post }
+ end
+ end
+
+ # GET /posts/new
+ # GET /posts/new.json
+ def new
+ @post = Post.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.json { render json: @post }
+ end
+ end
+
+ # GET /posts/1/edit
+ def edit
+ @post = Post.find(params[:id])
+ end
+
+ # POST /posts
+ # POST /posts.json
+ def create
+ @post = Post.new(params[:post])
+
+ respond_to do |format|
+ if @post.save
+ format.html { redirect_to @post, notice: 'Post was successfully created.' }
+ format.json { render json: @post, status: :created, location: @post }
+ else
+ format.html { render action: "new" }
+ format.json { render json: @post.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /posts/1
+ # PUT /posts/1.json
+ def update
+ @post = Post.find(params[:id])
+
+ respond_to do |format|
+ if @post.update_attributes(params[:post])
+ format.html { redirect_to @post, notice: 'Post was successfully updated.' }
+ format.json { head :ok }
+ else
+ format.html { render action: "edit" }
+ format.json { render json: @post.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /posts/1
+ # DELETE /posts/1.json
+ def destroy
+ @post = Post.find(params[:id])
+ @post.destroy
+
+ respond_to do |format|
+ format.html { redirect_to posts_url }
+ format.json { head :ok }
+ end
+ end
+end
diff --git a/railties/guides/code/getting_started/app/helpers/application_helper.rb b/railties/guides/code/getting_started/app/helpers/application_helper.rb
new file mode 100644
index 0000000000..de6be7945c
--- /dev/null
+++ b/railties/guides/code/getting_started/app/helpers/application_helper.rb
@@ -0,0 +1,2 @@
+module ApplicationHelper
+end
diff --git a/railties/guides/code/getting_started/app/helpers/comments_helper.rb b/railties/guides/code/getting_started/app/helpers/comments_helper.rb
new file mode 100644
index 0000000000..0ec9ca5f2d
--- /dev/null
+++ b/railties/guides/code/getting_started/app/helpers/comments_helper.rb
@@ -0,0 +1,2 @@
+module CommentsHelper
+end
diff --git a/railties/guides/code/getting_started/app/helpers/home_helper.rb b/railties/guides/code/getting_started/app/helpers/home_helper.rb
new file mode 100644
index 0000000000..23de56ac60
--- /dev/null
+++ b/railties/guides/code/getting_started/app/helpers/home_helper.rb
@@ -0,0 +1,2 @@
+module HomeHelper
+end
diff --git a/railties/guides/code/getting_started/app/helpers/posts_helper.rb b/railties/guides/code/getting_started/app/helpers/posts_helper.rb
new file mode 100644
index 0000000000..b6e8e67894
--- /dev/null
+++ b/railties/guides/code/getting_started/app/helpers/posts_helper.rb
@@ -0,0 +1,5 @@
+module PostsHelper
+ def join_tags(post)
+ post.tags.map { |t| t.name }.join(", ")
+ end
+end
diff --git a/railties/guides/code/getting_started/app/mailers/.gitkeep b/railties/guides/code/getting_started/app/mailers/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/railties/guides/code/getting_started/app/mailers/.gitkeep
diff --git a/railties/guides/code/getting_started/app/models/.gitkeep b/railties/guides/code/getting_started/app/models/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/railties/guides/code/getting_started/app/models/.gitkeep
diff --git a/railties/guides/code/getting_started/app/models/comment.rb b/railties/guides/code/getting_started/app/models/comment.rb
new file mode 100644
index 0000000000..4e76c5b5b0
--- /dev/null
+++ b/railties/guides/code/getting_started/app/models/comment.rb
@@ -0,0 +1,3 @@
+class Comment < ActiveRecord::Base
+ belongs_to :post
+end
diff --git a/railties/guides/code/getting_started/app/models/post.rb b/railties/guides/code/getting_started/app/models/post.rb
new file mode 100644
index 0000000000..61c2b5ae44
--- /dev/null
+++ b/railties/guides/code/getting_started/app/models/post.rb
@@ -0,0 +1,11 @@
+class Post < ActiveRecord::Base
+ validates :name, :presence => true
+ validates :title, :presence => true,
+ :length => { :minimum => 5 }
+
+ has_many :comments, :dependent => :destroy
+ has_many :tags
+
+ accepts_nested_attributes_for :tags, :allow_destroy => :true,
+ :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
+end
diff --git a/railties/guides/code/getting_started/app/models/tag.rb b/railties/guides/code/getting_started/app/models/tag.rb
new file mode 100644
index 0000000000..30992e8ba9
--- /dev/null
+++ b/railties/guides/code/getting_started/app/models/tag.rb
@@ -0,0 +1,3 @@
+class Tag < ActiveRecord::Base
+ belongs_to :post
+end
diff --git a/railties/guides/code/getting_started/app/views/comments/_comment.html.erb b/railties/guides/code/getting_started/app/views/comments/_comment.html.erb
new file mode 100644
index 0000000000..4c3fbf26cd
--- /dev/null
+++ b/railties/guides/code/getting_started/app/views/comments/_comment.html.erb
@@ -0,0 +1,15 @@
+<p>
+ <b>Commenter:</b>
+ <%= comment.commenter %>
+</p>
+
+<p>
+ <b>Comment:</b>
+ <%= comment.body %>
+</p>
+
+<p>
+ <%= link_to 'Destroy Comment', [comment.post, comment],
+ :confirm => 'Are you sure?',
+ :method => :delete %>
+</p>
diff --git a/railties/guides/code/getting_started/app/views/comments/_form.html.erb b/railties/guides/code/getting_started/app/views/comments/_form.html.erb
new file mode 100644
index 0000000000..d15bdd6b59
--- /dev/null
+++ b/railties/guides/code/getting_started/app/views/comments/_form.html.erb
@@ -0,0 +1,13 @@
+<%= form_for([@post, @post.comments.build]) do |f| %>
+ <div class="field">
+ <%= f.label :commenter %><br />
+ <%= f.text_field :commenter %>
+ </div>
+ <div class="field">
+ <%= f.label :body %><br />
+ <%= f.text_area :body %>
+ </div>
+ <div class="actions">
+ <%= f.submit %>
+ </div>
+<% end %>
diff --git a/railties/guides/code/getting_started/app/views/home/index.html.erb b/railties/guides/code/getting_started/app/views/home/index.html.erb
new file mode 100644
index 0000000000..bb4f3dcd1f
--- /dev/null
+++ b/railties/guides/code/getting_started/app/views/home/index.html.erb
@@ -0,0 +1,2 @@
+<h1>Hello, Rails!</h1>
+<%= link_to "My Blog", posts_path %>
diff --git a/railties/guides/code/getting_started/app/views/layouts/application.html.erb b/railties/guides/code/getting_started/app/views/layouts/application.html.erb
new file mode 100644
index 0000000000..1e1e4b9a99
--- /dev/null
+++ b/railties/guides/code/getting_started/app/views/layouts/application.html.erb
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Blog</title>
+ <%= stylesheet_link_tag "application" %>
+ <%= javascript_include_tag "application" %>
+ <%= csrf_meta_tags %>
+</head>
+<body style="background: #EEEEEE;">
+
+<%= yield %>
+
+</body>
+</html>
diff --git a/railties/guides/code/getting_started/app/views/posts/_form.html.erb b/railties/guides/code/getting_started/app/views/posts/_form.html.erb
new file mode 100644
index 0000000000..e27da7f413
--- /dev/null
+++ b/railties/guides/code/getting_started/app/views/posts/_form.html.erb
@@ -0,0 +1,32 @@
+<% @post.tags.build %>
+<%= form_for(@post) do |post_form| %>
+ <% if @post.errors.any? %>
+ <div id="errorExplanation">
+ <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>
+ <ul>
+ <% @post.errors.full_messages.each do |msg| %>
+ <li><%= msg %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <div class="field">
+ <%= post_form.label :name %><br />
+ <%= post_form.text_field :name %>
+ </div>
+ <div class="field">
+ <%= post_form.label :title %><br />
+ <%= post_form.text_field :title %>
+ </div>
+ <div class="field">
+ <%= post_form.label :content %><br />
+ <%= post_form.text_area :content %>
+ </div>
+ <h2>Tags</h2>
+ <%= render :partial => 'tags/form',
+ :locals => {:form => post_form} %>
+ <div class="actions">
+ <%= post_form.submit %>
+ </div>
+<% end %>
diff --git a/railties/guides/code/getting_started/app/views/posts/edit.html.erb b/railties/guides/code/getting_started/app/views/posts/edit.html.erb
new file mode 100644
index 0000000000..720580236b
--- /dev/null
+++ b/railties/guides/code/getting_started/app/views/posts/edit.html.erb
@@ -0,0 +1,6 @@
+<h1>Editing post</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Show', @post %> |
+<%= link_to 'Back', posts_path %>
diff --git a/railties/guides/code/getting_started/app/views/posts/index.html.erb b/railties/guides/code/getting_started/app/views/posts/index.html.erb
new file mode 100644
index 0000000000..45dee1b25f
--- /dev/null
+++ b/railties/guides/code/getting_started/app/views/posts/index.html.erb
@@ -0,0 +1,27 @@
+<h1>Listing posts</h1>
+
+<table>
+ <tr>
+ <th>Name</th>
+ <th>Title</th>
+ <th>Content</th>
+ <th></th>
+ <th></th>
+ <th></th>
+ </tr>
+
+<% @posts.each do |post| %>
+ <tr>
+ <td><%= post.name %></td>
+ <td><%= post.title %></td>
+ <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>
+ </tr>
+<% end %>
+</table>
+
+<br />
+
+<%= link_to 'New Post', new_post_path %>
diff --git a/railties/guides/code/getting_started/app/views/posts/new.html.erb b/railties/guides/code/getting_started/app/views/posts/new.html.erb
new file mode 100644
index 0000000000..36ad7421f9
--- /dev/null
+++ b/railties/guides/code/getting_started/app/views/posts/new.html.erb
@@ -0,0 +1,5 @@
+<h1>New post</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Back', posts_path %>
diff --git a/railties/guides/code/getting_started/app/views/posts/show.html.erb b/railties/guides/code/getting_started/app/views/posts/show.html.erb
new file mode 100644
index 0000000000..da78a9527b
--- /dev/null
+++ b/railties/guides/code/getting_started/app/views/posts/show.html.erb
@@ -0,0 +1,31 @@
+<p class="notice"><%= notice %></p>
+
+<p>
+ <b>Name:</b>
+ <%= @post.name %>
+</p>
+
+<p>
+ <b>Title:</b>
+ <%= @post.title %>
+</p>
+
+<p>
+ <b>Content:</b>
+ <%= @post.content %>
+</p>
+
+<p>
+ <b>Tags:</b>
+ <%= join_tags(@post) %>
+</p>
+
+<h2>Comments</h2>
+<%= render @post.comments %>
+
+<h2>Add a comment:</h2>
+<%= render "comments/form" %>
+
+
+<%= link_to 'Edit Post', edit_post_path(@post) %> |
+<%= link_to 'Back to Posts', posts_path %> |
diff --git a/railties/guides/code/getting_started/app/views/tags/_form.html.erb b/railties/guides/code/getting_started/app/views/tags/_form.html.erb
new file mode 100644
index 0000000000..7e424b0e20
--- /dev/null
+++ b/railties/guides/code/getting_started/app/views/tags/_form.html.erb
@@ -0,0 +1,12 @@
+<%= form.fields_for :tags do |tag_form| %>
+ <div class="field">
+ <%= tag_form.label :name, 'Tag:' %>
+ <%= tag_form.text_field :name %>
+ </div>
+ <% unless tag_form.object.nil? || tag_form.object.new_record? %>
+ <div class="field">
+ <%= tag_form.label :_destroy, 'Remove:' %>
+ <%= tag_form.check_box :_destroy %>
+ </div>
+ <% end %>
+<% end %>
diff --git a/railties/guides/code/getting_started/config.ru b/railties/guides/code/getting_started/config.ru
new file mode 100644
index 0000000000..ddf869e921
--- /dev/null
+++ b/railties/guides/code/getting_started/config.ru
@@ -0,0 +1,4 @@
+# This file is used by Rack-based servers to start the application.
+
+require ::File.expand_path('../config/environment', __FILE__)
+run Blog::Application
diff --git a/railties/guides/code/getting_started/config/application.rb b/railties/guides/code/getting_started/config/application.rb
new file mode 100644
index 0000000000..e914b5a80e
--- /dev/null
+++ b/railties/guides/code/getting_started/config/application.rb
@@ -0,0 +1,48 @@
+require File.expand_path('../boot', __FILE__)
+
+require 'rails/all'
+
+if defined?(Bundler)
+ # If you precompile assets before deploying to production, use this line
+ Bundler.require *Rails.groups(:assets => %w(development test))
+ # If you want your assets lazily compiled in production, use this line
+ # Bundler.require(:default, :assets, Rails.env)
+end
+
+module Blog
+ class Application < Rails::Application
+ # Settings in config/environments/* take precedence over those specified here.
+ # Application configuration should go into files in config/initializers
+ # -- all .rb files in that directory are automatically loaded.
+
+ # Custom directories with classes and modules you want to be autoloadable.
+ # config.autoload_paths += %W(#{config.root}/extras)
+
+ # Only load the plugins named here, in the order given (default is alphabetical).
+ # :all can be used as a placeholder for all plugins not explicitly named.
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
+
+ # Activate observers that should always be running.
+ # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
+
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
+ # config.time_zone = 'Central Time (US & Canada)'
+
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
+ # config.i18n.default_locale = :de
+
+ # Configure the default encoding used in templates for Ruby 1.9.
+ config.encoding = "utf-8"
+
+ # Configure sensitive parameters which will be filtered from the log file.
+ config.filter_parameters += [:password]
+
+ # Enable the asset pipeline
+ config.assets.enabled = true
+
+ # Version of your assets, change this if you want to expire all your assets
+ config.assets.version = '1.0'
+ end
+end
diff --git a/railties/guides/code/getting_started/config/boot.rb b/railties/guides/code/getting_started/config/boot.rb
new file mode 100644
index 0000000000..4489e58688
--- /dev/null
+++ b/railties/guides/code/getting_started/config/boot.rb
@@ -0,0 +1,6 @@
+require 'rubygems'
+
+# Set up gems listed in the Gemfile.
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+
+require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
diff --git a/railties/guides/code/getting_started/config/database.yml b/railties/guides/code/getting_started/config/database.yml
new file mode 100644
index 0000000000..51a4dd459d
--- /dev/null
+++ b/railties/guides/code/getting_started/config/database.yml
@@ -0,0 +1,25 @@
+# SQLite version 3.x
+# gem install sqlite3
+#
+# Ensure the SQLite 3 gem is defined in your Gemfile
+# gem 'sqlite3'
+development:
+ adapter: sqlite3
+ database: db/development.sqlite3
+ pool: 5
+ timeout: 5000
+
+# Warning: The database defined as "test" will be erased and
+# re-generated from your development database when you run "rake".
+# Do not set this db to the same as development or production.
+test:
+ adapter: sqlite3
+ database: db/test.sqlite3
+ pool: 5
+ timeout: 5000
+
+production:
+ adapter: sqlite3
+ database: db/production.sqlite3
+ pool: 5
+ timeout: 5000
diff --git a/railties/guides/code/getting_started/config/environment.rb b/railties/guides/code/getting_started/config/environment.rb
new file mode 100644
index 0000000000..8f728b7ce7
--- /dev/null
+++ b/railties/guides/code/getting_started/config/environment.rb
@@ -0,0 +1,5 @@
+# Load the rails application
+require File.expand_path('../application', __FILE__)
+
+# Initialize the rails application
+Blog::Application.initialize!
diff --git a/railties/guides/code/getting_started/config/environments/development.rb b/railties/guides/code/getting_started/config/environments/development.rb
new file mode 100644
index 0000000000..89932bf19b
--- /dev/null
+++ b/railties/guides/code/getting_started/config/environments/development.rb
@@ -0,0 +1,30 @@
+Blog::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
+
+ # In the development environment your application's code is reloaded on
+ # every request. This slows down response time but is perfect for development
+ # since you don't have to restart the web server when you make code changes.
+ config.cache_classes = false
+
+ # Log error messages when you accidentally call methods on nil.
+ config.whiny_nils = true
+
+ # Show full error reports and disable caching
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
+
+ # Don't care if the mailer can't send
+ config.action_mailer.raise_delivery_errors = false
+
+ # Print deprecation notices to the Rails logger
+ config.active_support.deprecation = :log
+
+ # Only use best-standards-support built into browsers
+ config.action_dispatch.best_standards_support = :builtin
+
+ # Do not compress assets
+ config.assets.compress = false
+
+ # Expands the lines which load the assets
+ config.assets.debug = true
+end
diff --git a/railties/guides/code/getting_started/config/environments/production.rb b/railties/guides/code/getting_started/config/environments/production.rb
new file mode 100644
index 0000000000..6ab63d30a6
--- /dev/null
+++ b/railties/guides/code/getting_started/config/environments/production.rb
@@ -0,0 +1,60 @@
+Blog::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
+
+ # Code is not reloaded between requests
+ config.cache_classes = true
+
+ # Full error reports are disabled and caching is turned on
+ config.consider_all_requests_local = false
+ config.action_controller.perform_caching = true
+
+ # Disable Rails's static asset server (Apache or nginx will already do this)
+ config.serve_static_assets = false
+
+ # Compress JavaScripts and CSS
+ config.assets.compress = true
+
+ # Don't fallback to assets pipeline if a precompiled asset is missed
+ config.assets.compile = false
+
+ # Generate digests for assets URLs
+ config.assets.digest = true
+
+ # Defaults to Rails.root.join("public/assets")
+ # config.assets.manifest = YOUR_PATH
+
+ # Specifies the header that your server uses for sending files
+ # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
+ # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
+
+ # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
+ # config.force_ssl = true
+
+ # See everything in the log (default is :info)
+ # config.log_level = :debug
+
+ # Use a different logger for distributed setups
+ # config.logger = SyslogLogger.new
+
+ # Use a different cache store in production
+ # config.cache_store = :mem_cache_store
+
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server
+ # config.action_controller.asset_host = "http://assets.example.com"
+
+ # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
+ # config.assets.precompile += %w( search.js )
+
+ # Disable delivery errors, bad email addresses will be ignored
+ # config.action_mailer.raise_delivery_errors = false
+
+ # Enable threaded mode
+ # config.threadsafe!
+
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
+ # the I18n.default_locale when a translation can not be found)
+ config.i18n.fallbacks = true
+
+ # Send deprecation notices to registered listeners
+ config.active_support.deprecation = :notify
+end
diff --git a/railties/guides/code/getting_started/config/environments/test.rb b/railties/guides/code/getting_started/config/environments/test.rb
new file mode 100644
index 0000000000..833241ace3
--- /dev/null
+++ b/railties/guides/code/getting_started/config/environments/test.rb
@@ -0,0 +1,42 @@
+Blog::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
+
+ # The test environment is used exclusively to run your application's
+ # test suite. You never need to work with it otherwise. Remember that
+ # your test database is "scratch space" for the test suite and is wiped
+ # and recreated between test runs. Don't rely on the data there!
+ config.cache_classes = true
+
+ # Configure static asset server for tests with Cache-Control for performance
+ config.serve_static_assets = true
+ config.static_cache_control = "public, max-age=3600"
+
+ # Log error messages when you accidentally call methods on nil
+ config.whiny_nils = true
+
+ # Show full error reports and disable caching
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
+
+ # Raise exceptions instead of rendering exception templates
+ config.action_dispatch.show_exceptions = false
+
+ # Disable request forgery protection in test environment
+ config.action_controller.allow_forgery_protection = false
+
+ # Tell Action Mailer not to deliver emails to the real world.
+ # The :test delivery method accumulates sent emails in the
+ # ActionMailer::Base.deliveries array.
+ config.action_mailer.delivery_method = :test
+
+ # Use SQL instead of Active Record's schema dumper when creating the test database.
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
+ # like if you have constraints or database-specific column types
+ # config.active_record.schema_format = :sql
+
+ # Print deprecation notices to the stderr
+ config.active_support.deprecation = :stderr
+
+ # Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets
+ config.assets.allow_debugging = true
+end
diff --git a/railties/guides/code/getting_started/config/initializers/backtrace_silencers.rb b/railties/guides/code/getting_started/config/initializers/backtrace_silencers.rb
new file mode 100644
index 0000000000..59385cdf37
--- /dev/null
+++ b/railties/guides/code/getting_started/config/initializers/backtrace_silencers.rb
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
+# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+
+# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
+# Rails.backtrace_cleaner.remove_silencers!
diff --git a/railties/guides/code/getting_started/config/initializers/inflections.rb b/railties/guides/code/getting_started/config/initializers/inflections.rb
new file mode 100644
index 0000000000..9e8b0131f8
--- /dev/null
+++ b/railties/guides/code/getting_started/config/initializers/inflections.rb
@@ -0,0 +1,10 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new inflection rules using the following format
+# (all these examples are active by default):
+# ActiveSupport::Inflector.inflections do |inflect|
+# inflect.plural /^(ox)$/i, '\1en'
+# inflect.singular /^(ox)en/i, '\1'
+# inflect.irregular 'person', 'people'
+# inflect.uncountable %w( fish sheep )
+# end
diff --git a/railties/guides/code/getting_started/config/initializers/mime_types.rb b/railties/guides/code/getting_started/config/initializers/mime_types.rb
new file mode 100644
index 0000000000..72aca7e441
--- /dev/null
+++ b/railties/guides/code/getting_started/config/initializers/mime_types.rb
@@ -0,0 +1,5 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new mime types for use in respond_to blocks:
+# Mime::Type.register "text/richtext", :rtf
+# Mime::Type.register_alias "text/html", :iphone
diff --git a/railties/guides/code/getting_started/config/initializers/secret_token.rb b/railties/guides/code/getting_started/config/initializers/secret_token.rb
new file mode 100644
index 0000000000..b0c8ee23c1
--- /dev/null
+++ b/railties/guides/code/getting_started/config/initializers/secret_token.rb
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# Your secret key for verifying the integrity of signed cookies.
+# If you change this key, all old signed cookies will become invalid!
+# Make sure the secret is at least 30 characters and all random,
+# no regular words or you'll be exposed to dictionary attacks.
+Blog::Application.config.secret_token = '685a9bf865b728c6549a191c90851c1b5ec41ecb60b9e94ad79dd3f824749798aa7b5e94431901960bee57809db0947b481570f7f13376b7ca190fa28099c459'
diff --git a/railties/guides/code/getting_started/config/initializers/session_store.rb b/railties/guides/code/getting_started/config/initializers/session_store.rb
new file mode 100644
index 0000000000..1a67af58b5
--- /dev/null
+++ b/railties/guides/code/getting_started/config/initializers/session_store.rb
@@ -0,0 +1,8 @@
+# Be sure to restart your server when you modify this file.
+
+Blog::Application.config.session_store :cookie_store, key: '_blog_session'
+
+# Use the database for sessions instead of the cookie-based default,
+# which shouldn't be used to store highly confidential information
+# (create the session table with "rails generate session_migration")
+# Blog::Application.config.session_store :active_record_store
diff --git a/railties/guides/code/getting_started/config/initializers/wrap_parameters.rb b/railties/guides/code/getting_started/config/initializers/wrap_parameters.rb
new file mode 100644
index 0000000000..999df20181
--- /dev/null
+++ b/railties/guides/code/getting_started/config/initializers/wrap_parameters.rb
@@ -0,0 +1,14 @@
+# Be sure to restart your server when you modify this file.
+#
+# This file contains settings for ActionController::ParamsWrapper which
+# is enabled by default.
+
+# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
+ActiveSupport.on_load(:action_controller) do
+ wrap_parameters format: [:json]
+end
+
+# Disable root element in JSON by default.
+ActiveSupport.on_load(:active_record) do
+ self.include_root_in_json = false
+end
diff --git a/railties/guides/code/getting_started/config/locales/en.yml b/railties/guides/code/getting_started/config/locales/en.yml
new file mode 100644
index 0000000000..179c14ca52
--- /dev/null
+++ b/railties/guides/code/getting_started/config/locales/en.yml
@@ -0,0 +1,5 @@
+# Sample localization file for English. Add more files in this directory for other locales.
+# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
+
+en:
+ hello: "Hello world"
diff --git a/railties/guides/code/getting_started/config/routes.rb b/railties/guides/code/getting_started/config/routes.rb
new file mode 100644
index 0000000000..31f0d210db
--- /dev/null
+++ b/railties/guides/code/getting_started/config/routes.rb
@@ -0,0 +1,64 @@
+Blog::Application.routes.draw do
+ resources :posts do
+ resources :comments
+ end
+
+ get "home/index"
+
+ # The priority is based upon order of creation:
+ # first created -> highest priority.
+
+ # Sample of regular route:
+ # match 'products/:id' => 'catalog#view'
+ # Keep in mind you can assign values other than :controller and :action
+
+ # Sample of named route:
+ # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
+ # This route can be invoked with purchase_url(:id => product.id)
+
+ # Sample resource route (maps HTTP verbs to controller actions automatically):
+ # resources :products
+
+ # Sample resource route with options:
+ # resources :products do
+ # member do
+ # get 'short'
+ # post 'toggle'
+ # end
+ #
+ # collection do
+ # get 'sold'
+ # end
+ # end
+
+ # Sample resource route with sub-resources:
+ # resources :products do
+ # resources :comments, :sales
+ # resource :seller
+ # end
+
+ # Sample resource route with more complex sub-resources
+ # resources :products do
+ # resources :comments
+ # resources :sales do
+ # get 'recent', :on => :collection
+ # end
+ # end
+
+ # Sample resource route within a namespace:
+ # namespace :admin do
+ # # Directs /admin/products/* to Admin::ProductsController
+ # # (app/controllers/admin/products_controller.rb)
+ # resources :products
+ # end
+
+ # You can have the root of your site routed with "root"
+ # just remember to delete public/index.html.
+ root :to => "home#index"
+
+ # See how all your routes lay out with "rake routes"
+
+ # This is a legacy wild controller route that's not recommended for RESTful applications.
+ # Note: This route will make all actions in every controller accessible via GET requests.
+ # match ':controller(/:action(/:id(.:format)))'
+end
diff --git a/railties/guides/code/getting_started/db/migrate/20110901012504_create_posts.rb b/railties/guides/code/getting_started/db/migrate/20110901012504_create_posts.rb
new file mode 100644
index 0000000000..d45a961523
--- /dev/null
+++ b/railties/guides/code/getting_started/db/migrate/20110901012504_create_posts.rb
@@ -0,0 +1,11 @@
+class CreatePosts < ActiveRecord::Migration
+ def change
+ create_table :posts do |t|
+ t.string :name
+ t.string :title
+ t.text :content
+
+ t.timestamps
+ end
+ end
+end
diff --git a/railties/guides/code/getting_started/db/migrate/20110901012815_create_comments.rb b/railties/guides/code/getting_started/db/migrate/20110901012815_create_comments.rb
new file mode 100644
index 0000000000..adda8078c1
--- /dev/null
+++ b/railties/guides/code/getting_started/db/migrate/20110901012815_create_comments.rb
@@ -0,0 +1,12 @@
+class CreateComments < ActiveRecord::Migration
+ def change
+ create_table :comments do |t|
+ t.string :commenter
+ t.text :body
+ t.references :post
+
+ t.timestamps
+ end
+ add_index :comments, :post_id
+ end
+end
diff --git a/railties/guides/code/getting_started/db/migrate/20110901013701_create_tags.rb b/railties/guides/code/getting_started/db/migrate/20110901013701_create_tags.rb
new file mode 100644
index 0000000000..cf95b1c3d0
--- /dev/null
+++ b/railties/guides/code/getting_started/db/migrate/20110901013701_create_tags.rb
@@ -0,0 +1,11 @@
+class CreateTags < ActiveRecord::Migration
+ def change
+ create_table :tags do |t|
+ t.string :name
+ t.references :post
+
+ t.timestamps
+ end
+ add_index :tags, :post_id
+ end
+end
diff --git a/railties/guides/code/getting_started/db/schema.rb b/railties/guides/code/getting_started/db/schema.rb
new file mode 100644
index 0000000000..9db4fbe4b6
--- /dev/null
+++ b/railties/guides/code/getting_started/db/schema.rb
@@ -0,0 +1,43 @@
+# encoding: UTF-8
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# Note that this schema.rb definition is the authoritative source for your
+# database schema. If you need to create the application database on another
+# system, you should be using db:schema:load, not running all the migrations
+# from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# you'll amass, the slower it'll run and the greater likelihood for issues).
+#
+# It's strongly recommended to check this file into your version control system.
+
+ActiveRecord::Schema.define(:version => 20110901013701) do
+
+ create_table "comments", :force => true do |t|
+ t.string "commenter"
+ t.text "body"
+ t.integer "post_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "comments", ["post_id"], :name => "index_comments_on_post_id"
+
+ create_table "posts", :force => true do |t|
+ t.string "name"
+ t.string "title"
+ t.text "content"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "tags", :force => true do |t|
+ t.string "name"
+ t.integer "post_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "tags", ["post_id"], :name => "index_tags_on_post_id"
+
+end
diff --git a/railties/guides/code/getting_started/db/seeds.rb b/railties/guides/code/getting_started/db/seeds.rb
new file mode 100644
index 0000000000..4edb1e857e
--- /dev/null
+++ b/railties/guides/code/getting_started/db/seeds.rb
@@ -0,0 +1,7 @@
+# This file should contain all the record creation needed to seed the database with its default values.
+# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
+#
+# Examples:
+#
+# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
+# Mayor.create(name: 'Emanuel', city: cities.first)
diff --git a/railties/guides/code/getting_started/doc/README_FOR_APP b/railties/guides/code/getting_started/doc/README_FOR_APP
new file mode 100644
index 0000000000..fe41f5cc24
--- /dev/null
+++ b/railties/guides/code/getting_started/doc/README_FOR_APP
@@ -0,0 +1,2 @@
+Use this README file to introduce your application and point to useful places in the API for learning more.
+Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
diff --git a/railties/guides/code/getting_started/lib/assets/.gitkeep b/railties/guides/code/getting_started/lib/assets/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/railties/guides/code/getting_started/lib/assets/.gitkeep
diff --git a/railties/guides/code/getting_started/lib/tasks/.gitkeep b/railties/guides/code/getting_started/lib/tasks/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/railties/guides/code/getting_started/lib/tasks/.gitkeep
diff --git a/railties/guides/code/getting_started/public/404.html b/railties/guides/code/getting_started/public/404.html
new file mode 100644
index 0000000000..9a48320a5f
--- /dev/null
+++ b/railties/guides/code/getting_started/public/404.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>The page you were looking for doesn't exist (404)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/404.html -->
+ <div class="dialog">
+ <h1>The page you were looking for doesn't exist.</h1>
+ <p>You may have mistyped the address or the page may have moved.</p>
+ </div>
+</body>
+</html>
diff --git a/railties/guides/code/getting_started/public/422.html b/railties/guides/code/getting_started/public/422.html
new file mode 100644
index 0000000000..83660ab187
--- /dev/null
+++ b/railties/guides/code/getting_started/public/422.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>The change you wanted was rejected (422)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/422.html -->
+ <div class="dialog">
+ <h1>The change you wanted was rejected.</h1>
+ <p>Maybe you tried to change something you didn't have access to.</p>
+ </div>
+</body>
+</html>
diff --git a/railties/guides/code/getting_started/public/500.html b/railties/guides/code/getting_started/public/500.html
new file mode 100644
index 0000000000..b80307fc16
--- /dev/null
+++ b/railties/guides/code/getting_started/public/500.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>We're sorry, but something went wrong (500)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/500.html -->
+ <div class="dialog">
+ <h1>We're sorry, but something went wrong.</h1>
+ <p>We've been notified about this issue and we'll take a look at it shortly.</p>
+ </div>
+</body>
+</html>
diff --git a/railties/guides/code/getting_started/public/favicon.ico b/railties/guides/code/getting_started/public/favicon.ico
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/railties/guides/code/getting_started/public/favicon.ico
diff --git a/railties/guides/code/getting_started/public/robots.txt b/railties/guides/code/getting_started/public/robots.txt
new file mode 100644
index 0000000000..085187fa58
--- /dev/null
+++ b/railties/guides/code/getting_started/public/robots.txt
@@ -0,0 +1,5 @@
+# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
+#
+# To ban all spiders from the entire site uncomment the next two lines:
+# User-Agent: *
+# Disallow: /
diff --git a/railties/guides/code/getting_started/script/rails b/railties/guides/code/getting_started/script/rails
new file mode 100755
index 0000000000..f8da2cffd4
--- /dev/null
+++ b/railties/guides/code/getting_started/script/rails
@@ -0,0 +1,6 @@
+#!/usr/bin/env ruby
+# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
+
+APP_PATH = File.expand_path('../../config/application', __FILE__)
+require File.expand_path('../../config/boot', __FILE__)
+require 'rails/commands'
diff --git a/railties/guides/code/getting_started/test/fixtures/.gitkeep b/railties/guides/code/getting_started/test/fixtures/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/railties/guides/code/getting_started/test/fixtures/.gitkeep
diff --git a/railties/guides/code/getting_started/test/fixtures/comments.yml b/railties/guides/code/getting_started/test/fixtures/comments.yml
new file mode 100644
index 0000000000..d33da386bf
--- /dev/null
+++ b/railties/guides/code/getting_started/test/fixtures/comments.yml
@@ -0,0 +1,11 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html
+
+one:
+ commenter: MyString
+ body: MyText
+ post:
+
+two:
+ commenter: MyString
+ body: MyText
+ post:
diff --git a/railties/guides/code/getting_started/test/fixtures/posts.yml b/railties/guides/code/getting_started/test/fixtures/posts.yml
new file mode 100644
index 0000000000..8b0f75a33d
--- /dev/null
+++ b/railties/guides/code/getting_started/test/fixtures/posts.yml
@@ -0,0 +1,11 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html
+
+one:
+ name: MyString
+ title: MyString
+ content: MyText
+
+two:
+ name: MyString
+ title: MyString
+ content: MyText
diff --git a/railties/guides/code/getting_started/test/fixtures/tags.yml b/railties/guides/code/getting_started/test/fixtures/tags.yml
new file mode 100644
index 0000000000..8485668908
--- /dev/null
+++ b/railties/guides/code/getting_started/test/fixtures/tags.yml
@@ -0,0 +1,9 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html
+
+one:
+ name: MyString
+ post:
+
+two:
+ name: MyString
+ post:
diff --git a/railties/guides/code/getting_started/test/functional/.gitkeep b/railties/guides/code/getting_started/test/functional/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/railties/guides/code/getting_started/test/functional/.gitkeep
diff --git a/railties/guides/code/getting_started/test/functional/comments_controller_test.rb b/railties/guides/code/getting_started/test/functional/comments_controller_test.rb
new file mode 100644
index 0000000000..2ec71b4ec5
--- /dev/null
+++ b/railties/guides/code/getting_started/test/functional/comments_controller_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class CommentsControllerTest < ActionController::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/railties/guides/code/getting_started/test/functional/home_controller_test.rb b/railties/guides/code/getting_started/test/functional/home_controller_test.rb
new file mode 100644
index 0000000000..0d9bb47c3e
--- /dev/null
+++ b/railties/guides/code/getting_started/test/functional/home_controller_test.rb
@@ -0,0 +1,9 @@
+require 'test_helper'
+
+class HomeControllerTest < ActionController::TestCase
+ test "should get index" do
+ get :index
+ assert_response :success
+ end
+
+end
diff --git a/railties/guides/code/getting_started/test/functional/posts_controller_test.rb b/railties/guides/code/getting_started/test/functional/posts_controller_test.rb
new file mode 100644
index 0000000000..b8f7b07820
--- /dev/null
+++ b/railties/guides/code/getting_started/test/functional/posts_controller_test.rb
@@ -0,0 +1,49 @@
+require 'test_helper'
+
+class PostsControllerTest < ActionController::TestCase
+ setup do
+ @post = posts(:one)
+ end
+
+ test "should get index" do
+ get :index
+ assert_response :success
+ assert_not_nil assigns(:posts)
+ end
+
+ test "should get new" do
+ get :new
+ assert_response :success
+ end
+
+ test "should create post" do
+ assert_difference('Post.count') do
+ post :create, post: @post.attributes
+ end
+
+ assert_redirected_to post_path(assigns(:post))
+ end
+
+ test "should show post" do
+ get :show, id: @post.to_param
+ assert_response :success
+ end
+
+ test "should get edit" do
+ get :edit, id: @post.to_param
+ assert_response :success
+ end
+
+ test "should update post" do
+ put :update, id: @post.to_param, post: @post.attributes
+ assert_redirected_to post_path(assigns(:post))
+ end
+
+ test "should destroy post" do
+ assert_difference('Post.count', -1) do
+ delete :destroy, id: @post.to_param
+ end
+
+ assert_redirected_to posts_path
+ end
+end
diff --git a/railties/guides/code/getting_started/test/integration/.gitkeep b/railties/guides/code/getting_started/test/integration/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/railties/guides/code/getting_started/test/integration/.gitkeep
diff --git a/railties/guides/code/getting_started/test/performance/browsing_test.rb b/railties/guides/code/getting_started/test/performance/browsing_test.rb
new file mode 100644
index 0000000000..3fea27b916
--- /dev/null
+++ b/railties/guides/code/getting_started/test/performance/browsing_test.rb
@@ -0,0 +1,12 @@
+require 'test_helper'
+require 'rails/performance_test_help'
+
+class BrowsingTest < ActionDispatch::PerformanceTest
+ # Refer to the documentation for all available options
+ # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory]
+ # :output => 'tmp/performance', :formats => [:flat] }
+
+ def test_homepage
+ get '/'
+ end
+end
diff --git a/railties/guides/code/getting_started/test/test_helper.rb b/railties/guides/code/getting_started/test/test_helper.rb
new file mode 100644
index 0000000000..8bf1192ffe
--- /dev/null
+++ b/railties/guides/code/getting_started/test/test_helper.rb
@@ -0,0 +1,13 @@
+ENV["RAILS_ENV"] = "test"
+require File.expand_path('../../config/environment', __FILE__)
+require 'rails/test_help'
+
+class ActiveSupport::TestCase
+ # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
+ #
+ # Note: You'll currently still have to declare fixtures explicitly in integration tests
+ # -- they do not yet inherit this setting
+ fixtures :all
+
+ # Add more helper methods to be used by all tests here...
+end
diff --git a/railties/guides/code/getting_started/test/unit/.gitkeep b/railties/guides/code/getting_started/test/unit/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/railties/guides/code/getting_started/test/unit/.gitkeep
diff --git a/railties/guides/code/getting_started/test/unit/comment_test.rb b/railties/guides/code/getting_started/test/unit/comment_test.rb
new file mode 100644
index 0000000000..b6d6131a96
--- /dev/null
+++ b/railties/guides/code/getting_started/test/unit/comment_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class CommentTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/railties/guides/code/getting_started/test/unit/helpers/comments_helper_test.rb b/railties/guides/code/getting_started/test/unit/helpers/comments_helper_test.rb
new file mode 100644
index 0000000000..2518c16bd5
--- /dev/null
+++ b/railties/guides/code/getting_started/test/unit/helpers/comments_helper_test.rb
@@ -0,0 +1,4 @@
+require 'test_helper'
+
+class CommentsHelperTest < ActionView::TestCase
+end
diff --git a/railties/guides/code/getting_started/test/unit/helpers/home_helper_test.rb b/railties/guides/code/getting_started/test/unit/helpers/home_helper_test.rb
new file mode 100644
index 0000000000..4740a18dac
--- /dev/null
+++ b/railties/guides/code/getting_started/test/unit/helpers/home_helper_test.rb
@@ -0,0 +1,4 @@
+require 'test_helper'
+
+class HomeHelperTest < ActionView::TestCase
+end
diff --git a/railties/guides/code/getting_started/test/unit/helpers/posts_helper_test.rb b/railties/guides/code/getting_started/test/unit/helpers/posts_helper_test.rb
new file mode 100644
index 0000000000..48549c2ea1
--- /dev/null
+++ b/railties/guides/code/getting_started/test/unit/helpers/posts_helper_test.rb
@@ -0,0 +1,4 @@
+require 'test_helper'
+
+class PostsHelperTest < ActionView::TestCase
+end
diff --git a/railties/guides/code/getting_started/test/unit/post_test.rb b/railties/guides/code/getting_started/test/unit/post_test.rb
new file mode 100644
index 0000000000..6d9d463a71
--- /dev/null
+++ b/railties/guides/code/getting_started/test/unit/post_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class PostTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/railties/guides/code/getting_started/test/unit/tag_test.rb b/railties/guides/code/getting_started/test/unit/tag_test.rb
new file mode 100644
index 0000000000..b8498a117c
--- /dev/null
+++ b/railties/guides/code/getting_started/test/unit/tag_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class TagTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/railties/guides/code/getting_started/vendor/assets/stylesheets/.gitkeep b/railties/guides/code/getting_started/vendor/assets/stylesheets/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/railties/guides/code/getting_started/vendor/assets/stylesheets/.gitkeep
diff --git a/railties/guides/code/getting_started/vendor/plugins/.gitkeep b/railties/guides/code/getting_started/vendor/plugins/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/railties/guides/code/getting_started/vendor/plugins/.gitkeep
diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile
index 4e47712636..d8d66302fe 100644
--- a/railties/guides/source/action_controller_overview.textile
+++ b/railties/guides/source/action_controller_overview.textile
@@ -815,9 +815,3 @@ end
</ruby>
Please note that if you found yourself adding +force_ssl+ to many controllers, you may found yourself wanting to force the whole application to use HTTPS instead. In that case, you can set the +config.force_ssl+ in your environment file.
-
-h3. Changelog
-
-* February 17, 2009: Yet another proofread by Xavier Noria.
-
-* November 4, 2008: First release version by Tore Darell
diff --git a/railties/guides/source/action_mailer_basics.textile b/railties/guides/source/action_mailer_basics.textile
index 67761645fa..ad5b848d2c 100644
--- a/railties/guides/source/action_mailer_basics.textile
+++ b/railties/guides/source/action_mailer_basics.textile
@@ -521,8 +521,3 @@ end
</ruby>
In the test we send the email and store the returned object in the +email+ variable. We then ensure that it was sent (the first assert), then, in the second batch of assertions, we ensure that the email does indeed contain what we expect.
-
-h3. Changelog
-
-* September 1, 2011: Changed the lines that said <tt>config/environments/env.rb</tt> to <tt>config/environments/$RAILS_ENV.rb</tt>. People were mis-interpreting the filename to literally be env.rb. "Andy Leeper":http://mochaleaf.com
-* September 30, 2010: Fixed typos and reformatted Action Mailer configuration table for better understanding. "Jaime Iniesta":http://jaimeiniesta.com
diff --git a/railties/guides/source/action_view_overview.textile b/railties/guides/source/action_view_overview.textile
index edaaeb8543..87250c684b 100644
--- a/railties/guides/source/action_view_overview.textile
+++ b/railties/guides/source/action_view_overview.textile
@@ -1495,10 +1495,3 @@ end
Then you could create special views like +app/views/posts/show.expert.html.erb+ that would only be displayed to expert users.
You can read more about the Rails Internationalization (I18n) API "here":i18n.html.
-
-h3. Changelog
-
-* May 29, 2011: Removed references to remote_* helpers - Vijay Dev
-* April 16, 2011: Added 'Using Action View with Rails', 'Templates' and 'Partials' sections. "Sebastian Martinez":http://wyeworks.com
-* September 3, 2009: Continuing work by Trevor Turk, leveraging the Action Pack docs and "What's new in Edge Rails":http://ryandaigle.com/articles/2007/8/3/what-s-new-in-edge-rails-partials-get-layouts
-* April 5, 2009: Starting work by Trevor Turk, leveraging Mike Gunderloy's docs
diff --git a/railties/guides/source/active_model_basics.textile b/railties/guides/source/active_model_basics.textile
index 73df567579..9c8ad24cee 100644
--- a/railties/guides/source/active_model_basics.textile
+++ b/railties/guides/source/active_model_basics.textile
@@ -203,8 +203,3 @@ person.valid? #=> true
person.token = nil
person.valid? #=> raises ActiveModel::StrictValidationFailed
</ruby>
-
-h3. Changelog
-
-* August 24, 2011: Add strict validation usage example. "Bogdan Gusiev":http://gusiev.com
-* August 5, 2011: Initial version by "Arun Agrawal":http://github.com/arunagw
diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile
index 7a853db813..96f91cfef6 100644
--- a/railties/guides/source/active_record_querying.textile
+++ b/railties/guides/source/active_record_querying.textile
@@ -1042,20 +1042,26 @@ INSERT INTO clients (created_at, first_name, locked, orders_count, updated_at) V
COMMIT
</sql>
-+first_or_create+ returns either the record that already existed or the new record. In our case, we didn't already have a client named Andy so the record was created an returned.
++first_or_create+ returns either the record that already exists or the new record. In our case, we didn't already have a client named Andy so the record is created and returned.
The new record might not be saved to the database; that depends on whether validations passed or not (just like +create+).
It's also worth noting that +first_or_create+ takes into account the arguments of the +where+ method. In the example above we didn't explicitly pass a +:first_name => 'Andy'+ argument to +first_or_create+. However, that was used when creating the new record because it was already passed before to the +where+ method.
-NOTE: On previous versions of Rails you could do a similar thing with the +find_or_create_by+ method. Following our example, you could also run something like +Client.find_or_create_by_first_name(:first_name => "Andy", :locked => false)+. This method still works, but it's encouraged to use +first_or_create+ because it's more explicit on what arguments are used to _find_ the record and what arguments are used to _create_ it, resulting in less confusion overall.
+You can do the same with the +find_or_create_by+ method:
+
+<ruby>
+Client.find_or_create_by_first_name(:first_name => "Andy", :locked => false)
+</ruby>
+
+This method still works, but it's encouraged to use +first_or_create+ because it's more explicit on which arguments are used to _find_ the record and which are used to _create_, resulting in less confusion overall.
h4. +first_or_create!+
You can also use +first_or_create!+ to raise an exception if the new record is invalid. Validations are not covered on this guide, but let's assume for a moment that you temporarily add
<ruby>
- validates :orders_count, :presence => true
+validates :orders_count, :presence => true
</ruby>
to your +Client+ model. If you try to create a new +Client+ without passing an +orders_count+, the record will be invalid and an exception will be raised:
@@ -1065,14 +1071,12 @@ Client.where(:first_name => 'Andy').first_or_create!(:locked => false)
# => ActiveRecord::RecordInvalid: Validation failed: Orders count can't be blank
</ruby>
-NOTE: Be sure to check the extensive *Active Record Validations and Callbacks Guide* for more information about validations.
+h4. +first_or_initialize+
-h4. +first_or_new+
-
-The +first_or_new+ method will work just like +first_or_create+ but it will not call +create+ but +new+. This means that a new model instance will be created in memory but won't be saved to the database. Continuing with the +first_or_create+ example, we now want the client named 'Nick':
+The +first_or_initialize+ method will work just like +first_or_create+ but it will not call +create+ but +new+. This means that a new model instance will be created in memory but won't be saved to the database. Continuing with the +first_or_create+ example, we now want the client named 'Nick':
<ruby>
-nick = Client.where(:first_name => 'Nick').first_or_new(:locked => false)
+nick = Client.where(:first_name => 'Nick').first_or_initialize(:locked => false)
# => <Client id: nil, first_name: "Nick", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">
nick.persisted?
@@ -1095,8 +1099,6 @@ nick.save
# => true
</ruby>
-Just like you can use *+build+* instead of *+new+*, you can use *+first_or_build+* instead of *+first_or_new+*.
-
h3. Finding by SQL
If you'd like to use your own SQL to find records in a table you can use +find_by_sql+. The +find_by_sql+ method will return an array of objects even if the underlying query returns just a single record. For example you could run this query:
@@ -1246,12 +1248,3 @@ Client.sum("orders_count")
</ruby>
For options, please see the parent section, "Calculations":#calculations.
-
-h3. Changelog
-
-* June 26 2011: Added documentation for the +scoped+, +unscoped+ and +default+ methods. "Ryan Bigg":credits.html#radar
-* December 23 2010: Add documentation for the +scope+ method. "Ryan Bigg":credits.html#radar
-* April 7, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com
-* February 3, 2010: Update to Rails 3 by "James Miller":credits.html#bensie
-* February 7, 2009: Second version by "Pratik":credits.html#lifo
-* December 29 2008: Initial version by "Ryan Bigg":credits.html#radar
diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile
index aba3224ba7..20f5e52891 100644
--- a/railties/guides/source/active_record_validations_callbacks.textile
+++ b/railties/guides/source/active_record_validations_callbacks.textile
@@ -1267,14 +1267,3 @@ end
</ruby>
The +after_commit+ and +after_rollback+ callbacks are guaranteed to be called for all models created, updated, or destroyed within a transaction block. If any exceptions are raised within one of these callbacks, they will be ignored so that they don't interfere with the other callbacks. As such, if your callback code could raise an exception, you'll need to rescue it and handle it appropriately within the callback.
-
-h3. Changelog
-
-* February 17, 2011: Add description of transaction callbacks.
-* July 20, 2010: Fixed typos and rephrased some paragraphs for clarity. "Jaime Iniesta":http://jaimeiniesta.com
-* May 24, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com
-* May 15, 2010: Validation Errors section updated by "Emili Parreño":http://www.eparreno.com
-* March 7, 2009: Callbacks revision by Trevor Turk
-* February 10, 2009: Observers revision by Trevor Turk
-* February 5, 2009: Initial revision by Trevor Turk
-* January 9, 2009: Initial version by "Cássio Marques":credits.html#cmarques
diff --git a/railties/guides/source/active_resource_basics.textile b/railties/guides/source/active_resource_basics.textile
index 3294227f7b..851aac1a3f 100644
--- a/railties/guides/source/active_resource_basics.textile
+++ b/railties/guides/source/active_resource_basics.textile
@@ -118,7 +118,3 @@ This validates the resource with any local validations written in base class and
h5. valid?
Runs all the local validations and will return true if no errors.
-
-h3. Changelog
-
-* July 30, 2011: Initial version by "Vishnu Atrai":http://github.com/vatrai \ No newline at end of file
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index b2436a2e68..d006cc9214 100644
--- a/railties/guides/source/active_support_core_extensions.textile
+++ b/railties/guides/source/active_support_core_extensions.textile
@@ -1020,7 +1020,7 @@ class A
class_attribute :x, :instance_reader => false
end
-A.x = 1 # NoMethodError
+A.new.x = 1 # NoMethodError
</ruby>
For convenience +class_attribute+ also defines an instance predicate which is the double negation of what the instance reader returns. In the examples above it would be called +x?+.
@@ -3599,8 +3599,3 @@ end
</ruby>
NOTE: Defined in +active_support/core_ext/load_error.rb+.
-
-h3. Changelog
-
-* August 10, 2010: Starts to take shape, added to the index.
-* April 18, 2009: Initial version by "Xavier Noria":credits.html#fxn
diff --git a/railties/guides/source/api_documentation_guidelines.textile b/railties/guides/source/api_documentation_guidelines.textile
index 3ebf0e10f1..c0f709eda8 100644
--- a/railties/guides/source/api_documentation_guidelines.textile
+++ b/railties/guides/source/api_documentation_guidelines.textile
@@ -183,7 +183,3 @@ self.class_eval %{
end
}
</ruby>
-
-h3. Changelog
-
-* July 17, 2010: ported from the docrails wiki and revised by "Xavier Noria":credits.html#fxn
diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile
index bad1c08747..ce4eafb97c 100644
--- a/railties/guides/source/asset_pipeline.textile
+++ b/railties/guides/source/asset_pipeline.textile
@@ -63,7 +63,7 @@ This has several disadvantages:
<ol>
<li>
<strong>Not all caches will cache content with a query string</strong><br>
- "Steve Souders recommends":http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/, "...avoiding a querystring for cacheable resources". He found that in these case 5-20% of requests will not be cached.
+ "Steve Souders recommends":http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/, "...avoiding a querystring for cacheable resources". He found that in this case 5-20% of requests will not be cached.
</li>
<li>
<strong>The file name can change between nodes in multi-server environments.</strong><br>
@@ -132,7 +132,7 @@ In regular views you can access images in the +assets/images+ directory like thi
Provided that the pipeline is enabled within your application (and not disabled in the current environment context), this file is served by Sprockets. If a file exists at +public/assets/rails.png+ it is served by the webserver.
-Alternatively, a request for a file with an MD5 hash such as +public/assets/rails-af27b6a414e6da00003503148be9b409.png+ is treated the same way. How these hashes are generated is covered in the "Production Assets":#production_assets section later on in this guide.
+Alternatively, a request for a file with an MD5 hash such as +public/assets/rails-af27b6a414e6da00003503148be9b409.png+ is treated the same way. How these hashes are generated is covered in the "In Production":#in-production section later on in this guide.
Sprockets will also look through the paths specified in +config.assets.paths+ which includes the standard application paths and any path added by Rails engines.
@@ -282,7 +282,7 @@ When debug mode is off Sprockets will concatenate and run the necessary preproce
<script src='/assets/application.js'></script>
</html>
-Assets are compiled and cached on the first request after the server is started. Sprockets sets a +must-validate+ Cache-Control HTTP header to reduce request overhead on subsequent requests -- on these the browser gets a 304 (not-modified) response.
+Assets are compiled and cached on the first request after the server is started. Sprockets sets a +must-revalidate+ Cache-Control HTTP header to reduce request overhead on subsequent requests -- on these the browser gets a 304 (not-modified) response.
If any of the files in the manifest have changed between requests, the server responds with a new compiled file.
@@ -403,7 +403,21 @@ For Apache:
</LocationMatch>
</plain>
-TODO: nginx instructions
+For nginx:
+
+<plain>
+location ~ ^/assets/ {
+ expires 1y;
+ add_header Cache-Control public;
+
+ # Some browsers still send conditional-GET requests if there's a
+ # Last-Modified header or an ETag header even if they haven't
+ # reached the expiry date sent in the Expires header.
+ add_header Last-Modified "";
+ add_header ETag "";
+ break;
+}
+</plain>
When files are precompiled, Sprockets also creates a "Gzip":http://en.wikipedia.org/wiki/Gzip (.gz) version of your assets. This avoids the server having to do this for any requests; it can simply read the compressed files from disk. You must configure your server to use gzip compression and serve the compressed assets that will be stored in the +public/assets+ folder. The following configuration options can be used:
@@ -415,12 +429,12 @@ For Apache:
RewriteCond %{REQUEST_FILENAME}.gz -s
RewriteRule ^(.+) $1.gz [L]
</LocationMatch>
-
+
# without these, Content-Type will be "application/x-gzip"
<FilesMatch "^/assets/.*\.css.gz$">
ForceType text/css
</FilesMatch>
-
+
<FilesMatch "^/assets/.*\.js.gz$">
ForceType text/javascript
</FilesMatch>
@@ -537,7 +551,7 @@ WARNING: If you are upgrading an existing application and intend to use this opt
h3. How Caching Works
-Sprockets uses the default rails cache store to cache assets in development and production.
+Sprockets uses the default Rails cache store to cache assets in development and production.
TODO: Add more about changing the default store.
diff --git a/railties/guides/source/association_basics.textile b/railties/guides/source/association_basics.textile
index ce4ff0389d..f5f0f9340c 100644
--- a/railties/guides/source/association_basics.textile
+++ b/railties/guides/source/association_basics.textile
@@ -1855,17 +1855,8 @@ class Customer < ActiveRecord::Base
end
</ruby>
-Extensions can refer to the internals of the association proxy using these three accessors:
+Extensions can refer to the internals of the association proxy using these three attributes of the +proxy_association+ accessor:
-* +proxy_owner+ returns the object that the association is a part of.
-* +proxy_reflection+ returns the reflection object that describes the association.
-* +proxy_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+.
-
-h3. Changelog
-
-* April 7, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com
-* April 19, 2009: Added +:touch+ option to +belongs_to+ associations by "Mike Gunderloy":credits.html#mgunderloy
-* February 1, 2009: Added +:autosave+ option "Mike Gunderloy":credits.html#mgunderloy
-* September 28, 2008: Corrected +has_many :through+ diagram, added polymorphic diagram, some reorganization by "Mike Gunderloy":credits.html#mgunderloy . First release version.
-* September 22, 2008: Added diagrams, misc. cleanup by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication)
-* September 14, 2008: initial version by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication)
+* +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+.
diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile
index 693303950d..19378d63ce 100644
--- a/railties/guides/source/caching_with_rails.textile
+++ b/railties/guides/source/caching_with_rails.textile
@@ -403,14 +403,3 @@ end
h3. Further reading
* "Scaling Rails Screencasts":http://railslab.newrelic.com/scaling-rails
-
-h3. Changelog
-
-* Feb 17, 2011: Document 3.0.0 changes to ActiveSupport::Cache
-* May 02, 2009: Formatting cleanups
-* April 26, 2009: Clean up typos in submitted patch
-* April 1, 2009: Made a bunch of small fixes
-* February 22, 2009: Beefed up the section on cache_stores
-* December 27, 2008: Typo fixes
-* November 23, 2008: Incremental updates with various suggested changes and formatting cleanup
-* September 15, 2008: Initial version by Aditya Chadha
diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile
index ae84bb5b92..cad2d03c23 100644
--- a/railties/guides/source/configuring.textile
+++ b/railties/guides/source/configuring.textile
@@ -604,11 +604,3 @@ The error occurred while evaluating nil.each
*+set_routes_reloader+* Configures Action Dispatch to reload the routes file using +ActionDispatch::Callbacks.to_prepare+.
*+disable_dependency_loading+* Disables the automatic dependency loading if the +config.cache_classes+ is set to true and +config.dependency_loading+ is set to false.
-
-h3. Changelog
-
-* December 3, 2010: Added initialization events for Rails 3 ("Ryan Bigg":http://ryanbigg.com)
-* November 26, 2010: Removed all config settings not available in Rails 3 ("Ryan Bigg":http://ryanbigg.com)
-* August 13, 2009: Updated with config syntax and added general configuration options by "John Pignata"
-* January 3, 2009: First reasonably complete draft by "Mike Gunderloy":credits.html#mgunderloy
-* November 5, 2008: Rough outline by "Mike Gunderloy":credits.html#mgunderloy
diff --git a/railties/guides/source/contribute.textile b/railties/guides/source/contribute.textile
deleted file mode 100644
index f9bb80861c..0000000000
--- a/railties/guides/source/contribute.textile
+++ /dev/null
@@ -1,70 +0,0 @@
-h2. Contribute to the Rails Guides
-
-Rails Guides aim to improve the Rails documentation and to make the barrier to entry as low as possible. A reasonably experienced developer should be able to use the guides to come up to speed on Rails quickly. Our sponsors have contributed prizes for those who write an entire guide, but there are many other ways to contribute.
-
-endprologue.
-
-h3. How to Contribute?
-
-* We have an open commit policy: anyone is welcome to contribute and to review contributions.
-* "docrails is hosted on GitHub":https://github.com/lifo/docrails and has public write access.
-* Guides are written in Textile, and reside at +railties/guides/source+ in the docrails project.
-* Follow the "Rails Guides Conventions":https://wiki.github.com/lifo/docrails/rails-guides-conventions.
-* Assets are stored in the +railties/guides/assets+ directory.
-* Sample format : "Active Record Associations":https://github.com/lifo/docrails/blob/3e56a3832415476fdd1cb963980d0ae390ac1ed3/railties/guides/source/association_basics.textile.
-* Sample output : "Active Record Associations":association_basics.html.
-* You can build the Guides during testing by running +bundle exec rake generate_guides+ in the +railties+ directory.
-* You're encouraged to validate XHTML for the generated guides before committing your changes by running +bundle exec rake validate_guides+ in the +railties+ directory.
-* Edge guides "can be consulted online":http://edgeguides.rubyonrails.org/. That website is generated periodically from docrails.
-
-h3. What to Contribute?
-
-* We need authors, editors, proofreaders, and translators. Adding a single paragraph of quality content to a guide is a good way to get started.
-* The easiest way to start is by improving an existing guide:
-** Improve the structure to make it more coherent.
-** Add missing information.
-** Correct any factual errors.
-** Fix typos or improve style.
-** Bring it up to date with the latest Edge Rails.
-* We're also open to suggestions for entire new guides:
-** Contact lifo or fxn to get your idea approved. See the Contact section below.
-** If you're the main author on a significant guide, you're eligible for the prizes.
-
-h3. How is the process?
-
-* The preferred way to contribute is to commit to docrails directly.
-* A new guide is only edited by its author until finished though.
-* If you are writing a new guide freely commit to docrails partial work and ping lifo or fxn when done with a first draft.
-* Guides reviewers will then provide feedback, some of it possibly in form of direct commits to agilize the process.
-* Eventually the guide will be approved and added to the index.
-
-h3. Prizes
-
-For each completed guide, the lead contributor will receive all of the following prizes:
-
-* $200 from Caboose Rails Documentation Project.
-* 1 year of GitHub Micro account worth $84.
-* 1 year of RPM Basic (Production performance management) for up to 10 hosts worth 12 months x $40 per host x 10 hosts = $4800. And also, savings of $45 per host per month over list price to upgrade to advanced product.
-
-h3. Rules
-
-* Guides are licensed under a Creative Commons Attribution-Share Alike 3.0 License.
-* If you're not sure whether a guide is actively being worked on, stop by IRC and ask.
-* If the same guide writer wants to write multiple guides, that's ideally the situation we'd love to be in! However, that guide writer will only receive the cash prize for all the subsequent guides (and not the GitHub or RPM prizes).
-* Our review team will have the final say on whether the guide is complete and of good enough quality.
-
-All authors should read and follow the "Rails Guides Conventions":ruby_on_rails_guides_guidelines.html and the "Rails API Documentation Conventions":api_documentation_guidelines.html.
-
-h3. Translations
-
-The translation effort for the Rails Guides is just getting underway. We know about projects to translate the Guides into Spanish, Portuguese, Polish, and French. For more details or to get involved see the "Translating Rails Guides":https://wiki.github.com/lifo/docrails/translating-rails-guides page.
-
-h3. Mailing List
-
-"Ruby on Rails: Documentation":http://groups.google.com/group/rubyonrails-docs is the mailing list for all the guides/documentation related discussions.
-
-h3. Contact
-
-* IRC : #docrails channel in irc.freenode.net
-* Twitter: "@docrails":http://twitter.com/docrails, "@lifo":http://twitter.com/lifo, "@fxn":http://twitter.com/fxn
-* Email : pratiknaik aT gmail, fxn aT hashref dot com
diff --git a/railties/guides/source/contributing_to_ruby_on_rails.textile b/railties/guides/source/contributing_to_ruby_on_rails.textile
index c302d393aa..30714e7e18 100644
--- a/railties/guides/source/contributing_to_ruby_on_rails.textile
+++ b/railties/guides/source/contributing_to_ruby_on_rails.textile
@@ -200,11 +200,11 @@ You can also invoke +test_jdbcmysql+, +test_jdbcsqlite3+ or +test_jdbcpostgresql
h4. Older versions of Ruby on Rails
-If you want to add a fix to older versions of Ruby on Rails, you'll need to set up and switch to your own local tracking branch. Here is an example to switch to the 2-3-stable branch:
+If you want to add a fix to older versions of Ruby on Rails, you'll need to set up and switch to your own local tracking branch. Here is an example to switch to the 3-0-stable branch:
<shell>
-$ git branch --track 2-3-stable origin/2-3-stable
-$ git checkout 2-3-stable
+$ git branch --track 3-0-stable origin/3-0-stable
+$ git checkout 3-0-stable
</shell>
TIP: You may want to "put your git branch name in your shell prompt":http://qugstart.com/blog/git-and-svn/add-colored-git-branch-name-to-your-shell-prompt/ to make it easier to remember which version of the code you're working with.
@@ -257,16 +257,18 @@ h3. Contributing to the Rails Documentation
Ruby on Rails has two main sets of documentation: The guides help you to learn Ruby on Rails, and the API is a reference.
-You can create an issue in GitHub issues to fix or expand documentation. However, if you're confident about your changes you can push them yourself directly via "docrails":https://github.com/lifo/docrails/tree/master. docrails is a branch with an *open commit policy* and public write access. Commits to docrails are still reviewed, but that happens after they are pushed. docrails is merged with master regularly, so you are effectively editing the Ruby on Rails documentation.
+You can help improve the Rails guides by making them more coherent, adding missing information, correcting factual errors, fixing typos, 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.
+
+If you're confident about your changes, you can push them yourself directly 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 that 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.
When working with documentation, please take into account the "API Documentation Guidelines":api_documentation_guidelines.html and the "Ruby on Rails Guides Guidelines":ruby_on_rails_guides_guidelines.html.
-NOTE: As explained above, ordinary code patches should have proper documentation coverage. docrails is only used for isolated documentation improvements.
+NOTE: As explained earlier, ordinary code patches should have proper documentation coverage. docrails is only used for isolated documentation improvements.
WARNING: docrails has a very strict policy: no code can be touched whatsoever, no matter how trivial or small the change. Only RDoc and guides can be edited via docrails. Also, CHANGELOGs should never be edited in docrails.
-If you have an idea for a new guide you can refer to the "contribution page":contribute.html for instructions on getting involved.
-
h3. Contributing to the Rails Code
h4. Clone the Rails Repository
@@ -381,13 +383,3 @@ And then...think about your next contribution!
h3. Rails Contributors
All contributions, either via master or docrails, get credit in "Rails Contributors":http://contributors.rubyonrails.org.
-
-h3. Changelog
-
-* May 12, 2011: Modified to prefer topic branches instead of master branch for users contributions by "Guillermo Iguaran":http://quillarb.org
-* April 29, 2011: Reflect GitHub Issues and Pull Request workflow by "Dan Pickett":http://www.enlightsolutions.com
-* April 14, 2011: Modified Contributing to the Rails Code section to add '[#ticket_number state:commited]' on patches commit messages by "Sebastian Martinez":http://wyeworks.com
-* December 28, 2010: Complete revision by "Xavier Noria":credits.html#fxn
-* April 6, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com
-* August 1, 2009: Updates/amplifications by "Mike Gunderloy":credits.html#mgunderloy
-* March 2, 2009: Initial draft by "Mike Gunderloy":credits.html#mgunderloy
diff --git a/railties/guides/source/debugging_rails_applications.textile b/railties/guides/source/debugging_rails_applications.textile
index f5bee52b5a..3552c68418 100644
--- a/railties/guides/source/debugging_rails_applications.textile
+++ b/railties/guides/source/debugging_rails_applications.textile
@@ -712,10 +712,3 @@ h3. References
* "ruby-debug cheat sheet":http://cheat.errtheblog.com/s/rdebug/
* "Ruby on Rails Wiki: How to Configure Logging":http://wiki.rubyonrails.org/rails/pages/HowtoConfigureLogging
* "Bleak House Documentation":http://blog.evanweaver.com/files/doc/fauna/bleak_house/files/README.html
-
-h3. Changelog
-
-* April 4, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com
-* November 3, 2008: Accepted for publication. Added RJS, memory leaks and plugins chapters by "Emilio Tagua":credits.html#miloops
-* October 19, 2008: Copy editing pass by "Mike Gunderloy":credits.html#mgunderloy
-* September 16, 2008: initial version by "Emilio Tagua":credits.html#miloops
diff --git a/railties/guides/source/form_helpers.textile b/railties/guides/source/form_helpers.textile
index c277f5723a..821bb305f6 100644
--- a/railties/guides/source/form_helpers.textile
+++ b/railties/guides/source/form_helpers.textile
@@ -796,13 +796,3 @@ Many apps grow beyond simple forms editing a single object. For example when cre
* Eloy Duran's "complex-forms-examples":https://github.com/alloy/complex-form-examples/ application
* Lance Ivy's "nested_assignment":https://github.com/cainlevy/nested_assignment/tree/master plugin and "sample application":https://github.com/cainlevy/complex-form-examples/tree/cainlevy
* James Golick's "attribute_fu":https://github.com/jamesgolick/attribute_fu plugin
-
-h3. Changelog
-
-* February 5, 2011: Added 'Forms to external resources' section. Timothy N. Tsvetkov <timothy.tsvetkov@gmail.com>
-* April 6, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com
-
-h3. Authors
-
-* Mislav Marohnić <mislav.marohnic@gmail.com>
-* "Frederick Cheung":credits.html#fcheung
diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile
index 3f990ef54b..7a863ccbc7 100644
--- a/railties/guides/source/generators.textile
+++ b/railties/guides/source/generators.textile
@@ -619,14 +619,3 @@ Output the contents of a file in the template's +source_path+, usually a README.
<ruby>
readme("README")
</ruby>
-
-h3. Changelog
-
-* December 1, 2010: Documenting the available methods and options for generators and templates by "Ryan Bigg":http://ryanbigg.com
-* December 1, 2010: Addition of Rails application templates by "Ryan Bigg":http://ryanbigg.com
-
-* August 23, 2010: Edit pass by "Xavier Noria":credits.html#fxn
-
-* April 30, 2010: Reviewed by José Valim
-
-* November 20, 2009: First version by José Valim
diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile
index f4a61482c6..33f383f173 100644
--- a/railties/guides/source/getting_started.textile
+++ b/railties/guides/source/getting_started.textile
@@ -41,6 +41,9 @@ internet for learning Ruby, including:
* "Programming Ruby":http://www.ruby-doc.org/docs/ProgrammingRuby/
* "Why's (Poignant) Guide to Ruby":http://mislav.uniqpath.com/poignant-guide/
+Also, the example code for this guide is available in the rails github:https://github.com/rails/rails repository
+in rails/railties/guides/code/getting_started.
+
h3. What is Rails?
Rails is a web application development framework written in the Ruby language.
@@ -549,9 +552,9 @@ folders, and edit <tt>config/routes.rb</tt>. Here's a quick overview of what it
|app/views/posts/new.html.erb |A view to create a new post|
|app/views/posts/_form.html.erb |A partial to control the overall look and feel of the form used in edit and new views|
|app/helpers/posts_helper.rb |Helper functions to be used from the post views|
-|app/assets/stylesheets/scaffolds.css.scss |Cascading style sheet to make the scaffolded views look better|
-|app/assets/stylesheets/posts.css.scss |Cascading style sheet for the posts controller|
-|app/assets/javascripts/posts.js.coffee |CoffeeScript for the posts controller|
+|app/assets/stylesheets/scaffolds.css.scss |Cascading style sheet to make the scaffolded views look better|
+|app/assets/stylesheets/posts.css.scss |Cascading style sheet for the posts controller|
+|app/assets/javascripts/posts.js.coffee |CoffeeScript for the posts controller|
|test/unit/post_test.rb |Unit testing harness for the posts model|
|test/functional/posts_controller_test.rb |Functional testing harness for the posts controller|
|test/unit/helpers/posts_helper_test.rb |Unit testing harness for the posts helper|
@@ -821,8 +824,8 @@ this layout in your editor and modify the +body+ tag:
<html>
<head>
<title>Blog</title>
- <%= stylesheet_link_tag :all %>
- <%= javascript_include_tag :defaults %>
+ <%= stylesheet_link_tag "application" %>
+ <%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body style="background: #EEEEEE;">
@@ -1083,8 +1086,8 @@ def destroy
@post.destroy
respond_to do |format|
- format.html { redirect_to(posts_url) }
- format.json { render :json => {}, :status => :ok }
+ format.html { redirect_to posts_url }
+ format.json { head :ok }
end
end
</ruby>
@@ -1453,7 +1456,7 @@ comment to a local variable named the same as the partial, in this case
h4. Rendering a Partial Form
-Lets also move that new comment section out to it's own partial, again, you
+Let's also move that new comment section out to its own partial. Again, you
create a file +app/views/comments/_form.html.erb+ and in it you put:
<erb>
@@ -1719,8 +1722,8 @@ This example shows another option of the render helper, being able to pass in
local variables, in this case, we want the local variable +form+ in the partial
to refer to the +post_form+ object.
-We also add a <tt>@post.tags.build</tt> at the top of this form, this is to make
-sure there is a new tag ready to have it's name filled in by the user. If you do
+We also add a <tt>@post.tags.build</tt> at the top of this form. This is to make
+sure there is a new tag ready to have its name filled in by the user. If you do
not build the new tag, then the form will not appear as there is no new Tag
object ready to create.
@@ -1885,24 +1888,3 @@ Two very common sources of data that are not UTF-8:
is using Latin-1 internally, and your user enters a Russian, Hebrew, or Japanese
character, the data will be lost forever once it enters the database. If possible,
use UTF-8 as the internal storage of your database.
-
-h3. Changelog
-
-* April 26, 2011: Change migration code from +up+, +down+ pair to +change+ method by "Prem Sichanugrist":http://sikachu.com
-* April 11, 2011: Change scaffold_controller generator to create format block for JSON instead of XML by "Sebastian Martinez":http://www.wyeworks.com
-* August 30, 2010: Minor editing after Rails 3 release by Joost Baaij
-* July 12, 2010: Fixes, editing and updating of code samples by "Jaime Iniesta":http://jaimeiniesta.com
-* May 16, 2010: Added a section on configuration gotchas to address common encoding problems that people might have by "Yehuda Katz":http://www.yehudakatz.com
-* April 30, 2010: Fixes, editing and updating of code samples by "Rohit Arondekar":http://rohitarondekar.com
-* April 25, 2010: Couple of more minor fixups by "Mikel Lindsaar":credits.html#raasdnil
-* April 1, 2010: Fixed document to validate XHTML 1.0 Strict by "Jaime Iniesta":http://jaimeiniesta.com
-* February 8, 2010: Full re-write for Rails 3.0-beta, added helpers and before_filters, refactored code by "Mikel Lindsaar":credits.html#raasdnil
-* January 24, 2010: Re-write for Rails 3.0 by "Mikel Lindsaar":credits.html#raasdnil
-* July 18, 2009: Minor cleanup in anticipation of Rails 2.3.3 by "Mike Gunderloy":credits.html#mgunderloy
-* February 1, 2009: Updated for Rails 2.3 by "Mike Gunderloy":credits.html#mgunderloy
-* November 3, 2008: Formatting patch from Dave Rothlisberger
-* November 1, 2008: First approved version by "Mike Gunderloy":credits.html#mgunderloy
-* October 16, 2008: Revised based on feedback from Pratik Naik by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication)
-* October 13, 2008: First complete draft by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication)
-* October 12, 2008: More detail, rearrangement, editing by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication)
-* September 8, 2008: initial version by "James Miller":credits.html#bensie (not yet approved for publication)
diff --git a/railties/guides/source/index.html.erb b/railties/guides/source/index.html.erb
index 214155c088..c9a8c4fa5c 100644
--- a/railties/guides/source/index.html.erb
+++ b/railties/guides/source/index.html.erb
@@ -30,7 +30,6 @@ Ruby on Rails Guides
<% content_for :index_section do %>
<div id="subCol">
<dl>
- <dd class="warning">Rails Guides are a result of the ongoing <a href="http://hackfest.rubyonrails.org">Guides hackfest</a>, and a work in progress.</dd>
<dd class="work-in-progress">Guides marked with this icon are currently being worked on. While they might still be useful to you, they may contain incomplete information and even errors. You can help by reviewing them and posting your comments and corrections to the author.</dd>
</dl>
</div>
diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile
index 9cc4dd5f04..8aabc3ae91 100644
--- a/railties/guides/source/initialization.textile
+++ b/railties/guides/source/initialization.textile
@@ -454,7 +454,7 @@ app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
TOPLEVEL_BINDING, config
</ruby>
-The <ruby>initialize</ruby> method 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 chain of events that this simple line sets off will be the focus of a large majority of this guide. The +require+ line for +config/environment.rb+ in +config.ru+ is the first to run:
+The +initialize+ method 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 chain of events that this simple line sets off will be the focus of a large majority of this guide. The +require+ line for +config/environment.rb+ in +config.ru+ is the first to run:
<ruby>
require ::File.expand_path('../config/environment', __FILE__)
diff --git a/railties/guides/source/layout.html.erb b/railties/guides/source/layout.html.erb
index 3ccbc3a477..4c979888b7 100644
--- a/railties/guides/source/layout.html.erb
+++ b/railties/guides/source/layout.html.erb
@@ -91,7 +91,7 @@
</dl>
</div>
</li>
- <li><a href="contribute.html">Contribute</a></li>
+ <li><a href="contributing_to_ruby_on_rails.html">Contribute</a></li>
<li><a href="credits.html">Credits</a></li>
</ul>
</div>
@@ -129,6 +129,10 @@
<%= link_to 'Ruby on Rails Guides Guidelines', 'ruby_on_rails_guides_guidelines.html' %>
for style and conventions.
</p>
+ <p>
+ If for whatever reason you spot something to fix but cannot patch it yourself, please
+ <%= link_to 'open an issue', 'https://github.com/rails/rails/issues' %>.
+ </p>
<p>And last but not least, any kind of discussion regarding Ruby on Rails
documentation is very welcome in the <%= link_to 'rubyonrails-docs mailing list', 'http://groups.google.com/group/rubyonrails-docs' %>.
</p>
diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile
index f49c2000ee..69ef05104c 100644
--- a/railties/guides/source/layouts_and_rendering.textile
+++ b/railties/guides/source/layouts_and_rendering.textile
@@ -1194,15 +1194,3 @@ On pages generated by +NewsController+, you want to hide the top menu and add a
That's it. The News views will use the new layout, hiding the top menu and adding a new right menu inside the "content" div.
There are several ways of getting similar results with different sub-templating schemes using this technique. Note that there is no limit in nesting levels. One can use the +ActionView::render+ method via +render :template => 'layouts/news'+ to base a new layout on the News layout. If you are sure you will not subtemplate the +News+ layout, you can replace the +content_for?(:news_content) ? yield(:news_content) : yield+ with simply +yield+.
-
-h3. Changelog
-
-* April 4, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com
-* January 25, 2010: Rails 3.0 Update by "Mikel Lindsaar":credits.html#raasdnil
-* December 27, 2008: Merge patch from Rodrigo Rosenfeld Rosas covering subtemplates
-* December 27, 2008: Information on new rendering defaults by "Mike Gunderloy":credits.html#mgunderloy
-* November 9, 2008: Added partial collection counter by "Mike Gunderloy":credits.html#mgunderloy
-* November 1, 2008: Added +:js+ option for +render+ by "Mike Gunderloy":credits.html#mgunderloy
-* October 16, 2008: Ready for publication by "Mike Gunderloy":credits.html#mgunderloy
-* October 4, 2008: Additional info on partials (+:object+, +:as+, and +:spacer_template+) by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication)
-* September 28, 2008: First draft by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication)
diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile
index 6fcc3cf4a2..7faa18e888 100644
--- a/railties/guides/source/migrations.textile
+++ b/railties/guides/source/migrations.textile
@@ -673,9 +673,3 @@ The Active Record way claims that intelligence belongs in your models, not in th
Validations such as +validates :foreign_key, :uniqueness => true+ are one way in which models can enforce data integrity. The +:dependent+ option on associations allows models to automatically destroy child objects when the parent is destroyed. Like anything which operates at the application level these cannot guarantee referential integrity and so some people augment them with foreign key constraints.
Although Active Record does not provide any tools for working directly with such features, the +execute+ method can be used to execute arbitrary SQL. There are also a number of plugins such as "foreign_key_migrations":https://github.com/harukizaemon/redhillonrails/tree/master/foreign_key_migrations/ which add foreign key support to Active Record (including support for dumping foreign keys in +db/schema.rb+).
-
-h3. Changelog
-
-* April 26, 2011: change generated +up+ and +down+ methods to +change+ method, and describe detail about +change+ method by "Prem Sichanugrist":http://sikachu.com
-* July 15, 2010: minor typos corrected by "Jaime Iniesta":http://jaimeiniesta.com
-* September 14, 2008: initial version by "Frederick Cheung":credits.html#fcheung
diff --git a/railties/guides/source/performance_testing.textile b/railties/guides/source/performance_testing.textile
index 5947735deb..f3ea7e38bc 100644
--- a/railties/guides/source/performance_testing.textile
+++ b/railties/guides/source/performance_testing.textile
@@ -595,9 +595,3 @@ Rails has been lucky to have a few companies dedicated to Rails-specific perform
* "New Relic":http://www.newrelic.com
* "Scout":http://scoutapp.com
-
-h3. Changelog
-
-* March 30, 2011: Documented the recent improvements (multiple interpreters, options, etc) and necessary adjustments. Other minor improvements. "Gonçalo Silva":http://goncalossilva.com.
-* January 9, 2009: Complete rewrite by "Pratik":credits.html#lifo
-* September 6, 2008: Initial version by Matthew Bergman
diff --git a/railties/guides/source/plugins.textile b/railties/guides/source/plugins.textile
index e8bdfa7f1c..5cfd336d1e 100644
--- a/railties/guides/source/plugins.textile
+++ b/railties/guides/source/plugins.textile
@@ -462,11 +462,3 @@ h4. References
* "Gemspec Reference":http://docs.rubygems.org/read/chapter/20
* "GemPlugins":http://www.mbleigh.com/2008/06/11/gemplugins-a-brief-introduction-to-the-future-of-rails-plugins
* "Keeping init.rb thin":http://daddy.platte.name/2007/05/rails-plugins-keep-initrb-thin.html
-
-h3. Changelog
-
-* March 10, 2011: Minor formatting tweaks.
-* February 13, 2011: Get guide in synch with Rails 3.0.3. Remove information not compatible with Rails 3. Send reader elsewhere
-for information that is covered elsewhere.
-* April 4, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com
-* November 17, 2008: Major revision by Jeff Dean
diff --git a/railties/guides/source/rails_application_templates.textile b/railties/guides/source/rails_application_templates.textile
index c3c8af4d3a..3b51a52733 100644
--- a/railties/guides/source/rails_application_templates.textile
+++ b/railties/guides/source/rails_application_templates.textile
@@ -238,7 +238,3 @@ git :init
git :add => "."
git :commit => "-a -m 'Initial commit'"
</ruby>
-
-h3. Changelog
-
-* April 29, 2009: Initial version by "Pratik":credits.html#lifo
diff --git a/railties/guides/source/rails_on_rack.textile b/railties/guides/source/rails_on_rack.textile
index 818df0ffaf..57c03b54dc 100644
--- a/railties/guides/source/rails_on_rack.textile
+++ b/railties/guides/source/rails_on_rack.textile
@@ -216,7 +216,7 @@ config.middleware.clear
<ruby>
# config.ru
-use MyOwnStackFromStratch
+use MyOwnStackFromScratch
run ActionController::Dispatcher.new
</ruby>
@@ -232,8 +232,3 @@ h4. Learning Rack
h4. Understanding Middlewares
* "Railscast on Rack Middlewares":http://railscasts.com/episodes/151-rack-middleware
-
-h3. Changelog
-
-* February 7, 2009: Second version by "Pratik":credits.html#lifo
-* January 11, 2009: First version by "Pratik":credits.html#lifo
diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile
index 99dd9a1cd2..0a9f1e8388 100644
--- a/railties/guides/source/routing.textile
+++ b/railties/guides/source/routing.textile
@@ -881,12 +881,3 @@ The +assert_routing+ assertion checks the route both ways: it tests that the pat
<ruby>
assert_routing({ :path => "photos", :method => :post }, { :controller => "photos", :action => "create" })
</ruby>
-
-h3. Changelog
-
-* April 10, 2010: Updated guide to remove outdated and superfluous information, and to provide information about new features, by "Yehuda Katz":http://www.yehudakatz.com
-* April 2, 2010: Updated guide to match new Routing DSL in Rails 3, by "Rizwan Reza":http://www.rizwanreza.com/
-* February 1, 2010: Modifies the routing documentation to match new routing DSL in Rails 3, by Prem Sichanugrist
-* October 4, 2008: Added additional detail on specifying verbs for resource member/collection routes, by "Mike Gunderloy":credits.html#mgunderloy
-* September 23, 2008: Added section on namespaced controllers and routing, by "Mike Gunderloy":credits.html#mgunderloy
-* September 10, 2008: initial version by "Mike Gunderloy":credits.html#mgunderloy
diff --git a/railties/guides/source/ruby_on_rails_guides_guidelines.textile b/railties/guides/source/ruby_on_rails_guides_guidelines.textile
index 5989191b5c..e63f564c83 100644
--- a/railties/guides/source/ruby_on_rails_guides_guidelines.textile
+++ b/railties/guides/source/ruby_on_rails_guides_guidelines.textile
@@ -77,8 +77,3 @@ bundle exec rake validate_guides
</plain>
Particularly, titles get an ID generated from their content and this often leads to duplicates. Please set +WARNINGS=1+ when generating guides to detect them. The warning messages suggest a way to fix them.
-
-h3. Changelog
-
-* March 31, 2011: grammar tweaks by "Josiah Ivey":http://twitter.com/josiahivey
-* October 5, 2010: ported from the docrails wiki and revised by "Xavier Noria":credits.html#fxn
diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile
index 04d1d0bda8..4cf9e2a7f3 100644
--- a/railties/guides/source/security.textile
+++ b/railties/guides/source/security.textile
@@ -1002,7 +1002,3 @@ The security landscape shifts and it is important to keep up to date, because mi
* Subscribe to the Rails security "mailing list":http://groups.google.com/group/rubyonrails-security
* "Keep up to date on the other application layers":http://secunia.com/ (they have a weekly newsletter, too)
* A "good security blog":http://ha.ckers.org/blog/ including the "Cross-Site scripting Cheat Sheet":http://ha.ckers.org/xss.html
-
-h3. Changelog
-
-* November 1, 2008: First approved version by Heiko Webers
diff --git a/railties/guides/source/testing.textile b/railties/guides/source/testing.textile
index caa0d91a83..2341a3522c 100644
--- a/railties/guides/source/testing.textile
+++ b/railties/guides/source/testing.textile
@@ -945,11 +945,3 @@ The built-in +test/unit+ based testing is not the only way to test Rails applica
* "Machinist":https://github.com/notahat/machinist/tree/master, another replacement for fixtures.
* "Shoulda":http://www.thoughtbot.com/projects/shoulda, an extension to +test/unit+ with additional helpers, macros, and assertions.
* "RSpec":http://relishapp.com/rspec, a behavior-driven development framework
-
-h3. Changelog
-
-* April 4, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com
-* November 13, 2008: Revised based on feedback from Pratik Naik by "Akshay Surve":credits.html#asurve (not yet approved for publication)
-* October 14, 2008: Edit and formatting pass by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication)
-* October 12, 2008: First draft by "Akshay Surve":credits.html#asurve (not yet approved for publication)
-
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 0ca664e4f0..a48db3b6d2 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -37,7 +37,8 @@ module Rails
@assets = ActiveSupport::OrderedOptions.new
@assets.enabled = false
@assets.paths = []
- @assets.precompile = [ /\w+\.(?!js|css).+/, /application.(css|js)$/ ]
+ @assets.precompile = [ Proc.new{ |path| !File.extname(path).in?(['.js', '.css']) },
+ /application.(css|js)$/ ]
@assets.prefix = "/assets"
@assets.version = ''
@assets.debug = false
diff --git a/railties/lib/rails/application/route_inspector.rb b/railties/lib/rails/application/route_inspector.rb
new file mode 100644
index 0000000000..8c6911e6bb
--- /dev/null
+++ b/railties/lib/rails/application/route_inspector.rb
@@ -0,0 +1,43 @@
+module Rails
+ class Application
+ ##
+ # This class is just used for displaying route information when someone
+ # executes `rake routes`. People should not use this class.
+ class RouteInspector # :nodoc:
+ def format all_routes, filter = nil
+ if filter
+ all_routes = all_routes.select{ |route| route.defaults[:controller] == filter }
+ end
+
+ routes = all_routes.collect do |route|
+
+ reqs = route.requirements.dup
+ rack_app = route.app unless route.app.class.name.to_s =~ /^ActionDispatch::Routing/
+
+ endpoint = rack_app ? rack_app.inspect : "#{reqs[:controller]}##{reqs[:action]}"
+ constraints = reqs.except(:controller, :action)
+
+ reqs = endpoint == '#' ? '' : endpoint
+
+ unless constraints.empty?
+ reqs = reqs.empty? ? constraints.inspect : "#{reqs} #{constraints.inspect}"
+ end
+
+ verb = route.verb.source.gsub(/[$^]/, '')
+ {:name => route.name.to_s, :verb => verb, :path => route.path.spec.to_s, :reqs => reqs}
+ end
+
+ # Skip the route if it's internal info route
+ routes.reject! { |r| r[:path] =~ %r{/rails/info/properties|^/assets} }
+
+ name_width = routes.map{ |r| r[:name].length }.max
+ verb_width = routes.map{ |r| r[:verb].length }.max
+ path_width = routes.map{ |r| r[:path].length }.max
+
+ routes.map do |r|
+ "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
+ end
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 93f5023a7a..294563ad06 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -138,10 +138,12 @@ module Rails
if options.dev?
<<-GEMFILE.strip_heredoc
gem 'rails', :path => '#{Rails::Generators::RAILS_DEV_PATH}'
+ gem 'journey', :path => '#{Rails::Generators::JOURNEY_DEV_PATH}'
GEMFILE
elsif options.edge?
<<-GEMFILE.strip_heredoc
gem 'rails', :git => 'git://github.com/rails/rails.git'
+ gem 'journey', :git => 'git://github.com/rails/journey.git'
GEMFILE
else
<<-GEMFILE.strip_heredoc
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index d9dd33518a..9cbda6649d 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -139,6 +139,7 @@ module Rails
# We need to store the RAILS_DEV_PATH in a constant, otherwise the path
# can change in Ruby 1.8.7 when we FileUtils.cd.
RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__))
+ JOURNEY_DEV_PATH = File.expand_path("../../../../../../../journey", File.dirname(__FILE__))
RESERVED_NAMES = %w[application destroy benchmarker profiler plugin runner test]
diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake
index 0c26bcf790..7dc54144da 100644
--- a/railties/lib/rails/tasks/routes.rake
+++ b/railties/lib/rails/tasks/routes.rake
@@ -3,35 +3,7 @@ task :routes => :environment do
Rails.application.reload_routes!
all_routes = Rails.application.routes.routes
- if ENV['CONTROLLER']
- all_routes = all_routes.select{ |route| route.defaults[:controller] == ENV['CONTROLLER'] }
- end
-
- routes = all_routes.collect do |route|
-
- reqs = route.requirements.dup
- rack_app = route.app unless route.app.class.name.to_s =~ /^ActionDispatch::Routing/
-
- endpoint = rack_app ? rack_app.inspect : "#{reqs[:controller]}##{reqs[:action]}"
- constraints = reqs.except(:controller, :action)
-
- reqs = endpoint == '#' ? '' : endpoint
-
- unless constraints.empty?
- reqs = reqs.empty? ? constraints.inspect : "#{reqs} #{constraints.inspect}"
- end
-
- {:name => route.name.to_s, :verb => route.verb.to_s, :path => route.path, :reqs => reqs}
- end
-
- # Skip the route if it's internal info route
- routes.reject! { |r| r[:path] =~ %r{/rails/info/properties|^/assets} }
-
- name_width = routes.map{ |r| r[:name].length }.max
- verb_width = routes.map{ |r| r[:verb].length }.max
- path_width = routes.map{ |r| r[:path].length }.max
-
- routes.each do |r|
- puts "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
- end
+ require 'rails/application/route_inspector'
+ inspector = Rails::Application::RouteInspector.new
+ puts inspector.format(all_routes, ENV['CONTROLLER']).join "\n"
end
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
index b9d8c002d7..959914bcea 100644
--- a/railties/test/application/assets_test.rb
+++ b/railties/test/application/assets_test.rb
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
require 'isolation/abstract_unit'
require 'active_support/core_ext/kernel/reporting'
require 'rack/test'
@@ -37,7 +38,7 @@ module ApplicationTests
test "assets do not require compressors until it is used" do
app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
- add_to_config "config.assets.compile = true"
+ app_file "config/initializers/compile.rb", "Rails.application.config.assets.compile = true"
ENV["RAILS_ENV"] = "production"
require "#{app_path}/config/environment"
@@ -64,6 +65,34 @@ module ApplicationTests
end
end
+ test "precompile application.js and application.css and all other files not ending with .js or .css by default" do
+ app_file "app/assets/javascripts/application.js", "alert();"
+ app_file "app/assets/stylesheets/application.css", "body{}"
+ app_file "app/assets/javascripts/something.min.js", "alert();"
+ app_file "app/assets/stylesheets/something.min.css", "body{}"
+
+ images_should_compile = ["a.png", "happyface.png", "happy_face.png", "happy.face.png",
+ "happy-face.png", "happy.happy_face.png", "happy_happy.face.png",
+ "happy.happy.face.png", "happy", "happy.face", "-happyface",
+ "-happy.png", "-happy.face.png", "_happyface", "_happy.face.png",
+ "_happy.png"]
+ images_should_compile.each do |filename|
+ app_file "app/assets/images/#{filename}", "happy"
+ end
+
+ capture(:stdout) do
+ Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
+ end
+
+ images_should_compile.each do |filename|
+ assert File.exists?("#{app_path}/public/assets/#{filename}")
+ end
+ assert File.exists?("#{app_path}/public/assets/application.js")
+ assert File.exists?("#{app_path}/public/assets/application.css")
+ assert !File.exists?("#{app_path}/public/assets/something.min.js")
+ assert !File.exists?("#{app_path}/public/assets/something.min.css")
+ 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"
@@ -147,6 +176,7 @@ module ApplicationTests
test "assets do not require any assets group gem when manifest file is present" do
app_file "app/assets/javascripts/application.js", "alert();"
+ app_file "config/initializers/serve_static_assets.rb", "Rails.application.config.serve_static_assets = true"
ENV["RAILS_ENV"] = "production"
capture(:stdout) do
@@ -240,6 +270,36 @@ module ApplicationTests
assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file))
end
+ test "precompile ignore asset_host" do
+ app_file "app/assets/javascripts/application.css.erb", "<%= asset_path 'rails.png' %>"
+ add_to_config "config.action_controller.asset_host = Proc.new { |source, request| 'http://www.example.com/' }"
+
+ capture(:stdout) do
+ Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
+ end
+
+ file = Dir["#{app_path}/public/assets/application.css"].first
+ content = File.read(file)
+ assert_match(/\/assets\/rails.png/, content)
+ assert_no_match(/www\.example\.com/, content)
+ end
+
+ test "precompile should handle utf8 filenames" do
+ app_file "app/assets/images/レイルズ.png", "not a image really"
+ add_to_config "config.assets.precompile = [ /\.png$$/, /application.(css|js)$/ ]"
+
+ capture(:stdout) do
+ Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
+ end
+
+ assert File.exists?("#{app_path}/public/assets/レイルズ.png")
+
+ manifest = "#{app_path}/public/assets/manifest.yml"
+
+ assets = YAML.load_file(manifest)
+ assert_equal "レイルズ.png", assets["レイルズ.png"]
+ end
+
test "assets are cleaned up properly" do
app_file "public/assets/application.js", "alert();"
app_file "public/assets/application.css", "a { color: green; }"
@@ -253,6 +313,17 @@ module ApplicationTests
assert_equal 0, files.length, "Expected no assets, but found #{files.join(', ')}"
end
+ test "assets routes are not drawn when compilation is disabled" do
+ app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
+ add_to_config "config.assets.compile = false"
+
+ ENV["RAILS_ENV"] = "production"
+ require "#{app_path}/config/environment"
+
+ get "/assets/demo.js"
+ assert_equal 404, last_response.status
+ end
+
test "does not stream session cookies back" do
app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index 0e03c3dc2d..c76bc3d526 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -1,3 +1,4 @@
+# coding:utf-8
require "isolation/abstract_unit"
module ApplicationTests
@@ -85,7 +86,7 @@ module ApplicationTests
end
end
- def test_rake_routes_output_strips_anchors_from_http_verbs
+ def test_rake_routes_calls_the_route_inspector
app_file "config/routes.rb", <<-RUBY
AppTemplate::Application.routes.draw do
get '/cart', :to => 'cart#show'
@@ -94,99 +95,6 @@ module ApplicationTests
assert_equal "cart GET /cart(.:format) cart#show\n", Dir.chdir(app_path){ `rake routes` }
end
- def test_rake_routes_shows_custom_assets
- app_file "config/routes.rb", <<-RUBY
- AppTemplate::Application.routes.draw do
- get '/custom/assets', :to => 'custom_assets#show'
- end
- RUBY
- assert_equal "custom_assets GET /custom/assets(.:format) custom_assets#show\n",
- Dir.chdir(app_path){ `rake routes` }
- end
-
- def test_rake_routes_shows_resources_route
- app_file "config/routes.rb", <<-RUBY
- AppTemplate::Application.routes.draw do
- resources :articles
- end
- RUBY
- expected =
- " articles GET /articles(.:format) articles#index\n" <<
- " POST /articles(.:format) articles#create\n" <<
- " new_article GET /articles/new(.:format) articles#new\n" <<
- "edit_article GET /articles/:id/edit(.:format) articles#edit\n" <<
- " article GET /articles/:id(.:format) articles#show\n" <<
- " PUT /articles/:id(.:format) articles#update\n" <<
- " DELETE /articles/:id(.:format) articles#destroy\n"
- assert_equal expected, Dir.chdir(app_path){ `rake routes` }
- end
-
- def test_rake_routes_shows_root_route
- app_file "config/routes.rb", <<-RUBY
- AppTemplate::Application.routes.draw do
- root :to => 'pages#main'
- end
- RUBY
- assert_equal "root / pages#main\n", Dir.chdir(app_path){ `rake routes` }
- end
-
- def test_rake_routes_shows_controller_and_action_only_route
- app_file "config/routes.rb", <<-RUBY
- AppTemplate::Application.routes.draw do
- match ':controller/:action'
- end
- RUBY
- assert_equal " /:controller/:action(.:format) \n", Dir.chdir(app_path){ `rake routes` }
- end
-
- def test_rake_routes_shows_controller_and_action_route_with_constraints
- app_file "config/routes.rb", <<-RUBY
- AppTemplate::Application.routes.draw do
- match ':controller(/:action(/:id))', :id => /\\d+/
- end
- RUBY
- assert_equal " /:controller(/:action(/:id))(.:format) {:id=>/\\d+/}\n", Dir.chdir(app_path){ `rake routes` }
- end
-
- def test_rake_routes_shows_route_with_defaults
- app_file "config/routes.rb", <<-RUBY
- AppTemplate::Application.routes.draw do
- match 'photos/:id' => 'photos#show', :defaults => {:format => 'jpg'}
- end
- RUBY
- assert_equal %Q[ /photos/:id(.:format) photos#show {:format=>"jpg"}\n], Dir.chdir(app_path){ `rake routes` }
- end
-
- def test_rake_routes_shows_route_with_constraints
- app_file "config/routes.rb", <<-RUBY
- AppTemplate::Application.routes.draw do
- match 'photos/:id' => 'photos#show', :id => /[A-Z]\\d{5}/
- end
- RUBY
- assert_equal " /photos/:id(.:format) photos#show {:id=>/[A-Z]\\d{5}/}\n", Dir.chdir(app_path){ `rake routes` }
- end
-
- def test_rake_routes_shows_route_with_rack_app
- app_file "lib/rack_app.rb", <<-RUBY
- class RackApp
- class << self
- def call(env)
- end
- end
- end
- RUBY
-
- app_file "config/routes.rb", <<-RUBY
- require 'rack_app'
-
- AppTemplate::Application.routes.draw do
- match 'foo/:id' => RackApp, :id => /[A-Z]\\d{5}/
- end
- RUBY
-
- assert_equal " /foo/:id(.:format) RackApp {:id=>/[A-Z]\\d{5}/}\n", Dir.chdir(app_path){ `rake routes` }
- end
-
def test_logger_is_flushed_when_exiting_production_rake_tasks
add_to_config <<-RUBY
rake_tasks do
@@ -219,6 +127,55 @@ module ApplicationTests
assert_match(/AddEmailToUsers: reverted/, output)
end
+ def test_migration_status_when_schema_migrations_table_is_not_present
+ output = Dir.chdir(app_path){ `rake db:migrate:status` }
+ assert_equal "Schema migrations table does not exist yet.\n", output
+ end
+
+ def test_migration_status
+ Dir.chdir(app_path) do
+ `rails generate model user username:string password:string`
+ `rails generate migration add_email_to_users email:string`
+ end
+
+ Dir.chdir(app_path) { `rake db:migrate`}
+ output = Dir.chdir(app_path) { `rake db:migrate:status` }
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/up\s+\d{14}\s+Add email to users/, output)
+
+ Dir.chdir(app_path) { `rake db:rollback STEP=1` }
+ output = Dir.chdir(app_path) { `rake db:migrate:status` }
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/down\s+\d{14}\s+Add email to users/, output)
+ end
+
+ def test_migration_status_after_rollback_and_redo
+ Dir.chdir(app_path) do
+ `rails generate model user username:string password:string`
+ `rails generate migration add_email_to_users email:string`
+ end
+
+ Dir.chdir(app_path) { `rake db:migrate`}
+ output = Dir.chdir(app_path) { `rake db:migrate:status` }
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/up\s+\d{14}\s+Add email to users/, output)
+
+ Dir.chdir(app_path) { `rake db:rollback STEP=2` }
+ output = Dir.chdir(app_path) { `rake db:migrate:status` }
+
+ assert_match(/down\s+\d{14}\s+Create users/, output)
+ assert_match(/down\s+\d{14}\s+Add email to users/, output)
+
+ Dir.chdir(app_path) { `rake db:migrate:redo` }
+ output = Dir.chdir(app_path) { `rake db:migrate:status` }
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/up\s+\d{14}\s+Add email to users/, output)
+ end
+
def test_loading_specific_fixtures
Dir.chdir(app_path) do
`rails generate model user username:string password:string`
@@ -245,4 +202,4 @@ module ApplicationTests
assert_match(/7 tests, 10 assertions, 0 failures, 0 errors/, content)
end
end
-end \ No newline at end of file
+end
diff --git a/railties/test/application/route_inspect_test.rb b/railties/test/application/route_inspect_test.rb
new file mode 100644
index 0000000000..add8256b5d
--- /dev/null
+++ b/railties/test/application/route_inspect_test.rb
@@ -0,0 +1,97 @@
+require 'test/unit'
+require 'rails/application/route_inspector'
+require 'action_controller'
+
+module ApplicationTests
+ class RouteInspectTest < Test::Unit::TestCase
+ def setup
+ @set = ActionDispatch::Routing::RouteSet.new
+ @inspector = Rails::Application::RouteInspector.new
+ end
+
+ def test_cart_inspect
+ @set.draw do
+ get '/cart', :to => 'cart#show'
+ end
+ output = @inspector.format @set.routes
+ assert_equal ["cart GET /cart(.:format) cart#show"], output
+ end
+
+ def test_inspect_shows_custom_assets
+ @set.draw do
+ get '/custom/assets', :to => 'custom_assets#show'
+ end
+ output = @inspector.format @set.routes
+ assert_equal ["custom_assets GET /custom/assets(.:format) custom_assets#show"], output
+ end
+
+ def test_inspect_routes_shows_resources_route
+ @set.draw do
+ resources :articles
+ end
+ output = @inspector.format @set.routes
+ expected = [
+ " articles GET /articles(.:format) articles#index",
+ " POST /articles(.:format) articles#create",
+ " new_article GET /articles/new(.:format) articles#new",
+ "edit_article GET /articles/:id/edit(.:format) articles#edit",
+ " article GET /articles/:id(.:format) articles#show",
+ " PUT /articles/:id(.:format) articles#update",
+ " DELETE /articles/:id(.:format) articles#destroy" ]
+ assert_equal expected, output
+ end
+
+ def test_inspect_routes_shows_root_route
+ @set.draw do
+ root :to => 'pages#main'
+ end
+ output = @inspector.format @set.routes
+ assert_equal ["root / pages#main"], output
+ end
+
+ def test_inspect_routes_shows_controller_and_action_only_route
+ @set.draw do
+ match ':controller/:action'
+ end
+ output = @inspector.format @set.routes
+ assert_equal [" /:controller/:action(.:format) "], output
+ end
+
+ def test_inspect_routes_shows_controller_and_action_route_with_constraints
+ @set.draw do
+ match ':controller(/:action(/:id))', :id => /\d+/
+ end
+ output = @inspector.format @set.routes
+ assert_equal [" /:controller(/:action(/:id))(.:format) {:id=>/\\d+/}"], output
+ end
+
+ def test_rake_routes_shows_route_with_defaults
+ @set.draw do
+ match 'photos/:id' => 'photos#show', :defaults => {:format => 'jpg'}
+ end
+ output = @inspector.format @set.routes
+ assert_equal [%Q[ /photos/:id(.:format) photos#show {:format=>"jpg"}]], output
+ end
+
+ def test_rake_routes_shows_route_with_constraints
+ @set.draw do
+ match 'photos/:id' => 'photos#show', :id => /[A-Z]\d{5}/
+ end
+ output = @inspector.format @set.routes
+ assert_equal [" /photos/:id(.:format) photos#show {:id=>/[A-Z]\\d{5}/}"], output
+ end
+
+ class RackApp
+ def self.call(env)
+ end
+ end
+
+ def test_rake_routes_shows_route_with_rack_app
+ @set.draw do
+ match 'foo/:id' => RackApp, :id => /[A-Z]\d{5}/
+ end
+ output = @inspector.format @set.routes
+ assert_equal [" /foo/:id(.:format) #{RackApp.name} {:id=>/[A-Z]\\d{5}/}"], output
+ end
+ end
+end
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb
index 685d1b154b..4a6bdb0320 100644
--- a/railties/test/isolation/abstract_unit.rb
+++ b/railties/test/isolation/abstract_unit.rb
@@ -282,7 +282,7 @@ Module.new do
require_environment = "-r #{environment}"
end
- `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/bin/rails new #{tmp_path('app_template')}`
+ `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/railties/bin/rails new #{tmp_path('app_template')}`
File.open("#{tmp_path}/app_template/config/boot.rb", 'w') do |f|
if require_environment
f.puts "Dir.chdir('#{File.dirname(environment)}') do"
diff --git a/railties/test/railties/generators_test.rb b/railties/test/railties/generators_test.rb
index 1d4ba0e5b6..f8540d69d9 100644
--- a/railties/test/railties/generators_test.rb
+++ b/railties/test/railties/generators_test.rb
@@ -28,7 +28,7 @@ module RailtiesTests
if File.exist?("#{environment}.rb")
require_environment = "-r #{environment}"
end
- `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/bin/rails #{cmd}`
+ `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/railties/bin/rails #{cmd}`
end
def build_engine(is_mountable=false)