aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile1
-rw-r--r--actionpack/CHANGELOG23
-rw-r--r--actionpack/lib/action_controller/caching/sweeping.rb2
-rw-r--r--actionpack/lib/action_controller/metal/helpers.rb9
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb2
-rw-r--r--actionpack/lib/action_controller/test_case.rb6
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb14
-rw-r--r--actionpack/lib/action_view/asset_paths.rb2
-rw-r--r--actionpack/lib/action_view/base.rb2
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb6
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/record_tag_helper.rb56
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb6
-rw-r--r--actionpack/lib/sprockets/helpers/rails_helper.rb4
-rw-r--r--actionpack/test/controller/render_test.rb2
-rw-r--r--actionpack/test/fixtures/test/hello,world.erb (renamed from actionpack/test/fixtures/test/hello_w*rld.erb)0
-rw-r--r--actionpack/test/template/capture_helper_test.rb36
-rw-r--r--actionpack/test/template/record_tag_helper_test.rb29
-rw-r--r--activemodel/activemodel.gemspec1
-rw-r--r--activemodel/lib/active_model/dirty.rb2
-rw-r--r--activemodel/lib/active_model/secure_password.rb11
-rw-r--r--activerecord/lib/active_record/fixtures.rb729
-rw-r--r--activerecord/lib/active_record/relation/batches.rb2
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb8
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb6
-rw-r--r--activerecord/test/cases/base_test.rb1
-rw-r--r--activerecord/test/cases/batches_test.rb20
-rw-r--r--activerecord/test/cases/finder_test.rb26
-rw-r--r--activerecord/test/cases/relations_test.rb5
-rw-r--r--activerecord/test/fixtures/tasks.yml2
-rw-r--r--activerecord/test/models/post.rb10
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/hash/indifferent_access.rb2
-rw-r--r--activesupport/lib/active_support/hash_with_indifferent_access.rb2
-rw-r--r--activesupport/lib/active_support/log_subscriber/test_helper.rb4
-rw-r--r--activesupport/lib/active_support/ordered_hash.rb5
-rw-r--r--activesupport/test/core_ext/module_test.rb10
-rw-r--r--activesupport/test/ordered_hash_test.rb5
-rw-r--r--railties/guides/source/3_1_release_notes.textile4
-rw-r--r--railties/guides/source/action_controller_overview.textile4
-rw-r--r--railties/guides/source/action_mailer_basics.textile9
-rw-r--r--railties/guides/source/action_view_overview.textile77
-rw-r--r--railties/guides/source/active_model_basics.textile2
-rw-r--r--railties/guides/source/active_record_querying.textile4
-rw-r--r--railties/guides/source/asset_pipeline.textile219
-rw-r--r--railties/guides/source/configuring.textile10
-rw-r--r--railties/guides/source/generators.textile9
-rw-r--r--railties/guides/source/getting_started.textile2
-rw-r--r--railties/guides/source/layouts_and_rendering.textile9
-rw-r--r--railties/guides/source/performance_testing.textile4
-rw-r--r--railties/guides/source/rails_application_templates.textile12
-rw-r--r--railties/guides/source/testing.textile2
-rw-r--r--railties/lib/rails/generators/actions.rb33
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/public/500.html1
-rw-r--r--railties/lib/rails/generators/test_case.rb6
-rw-r--r--railties/lib/rails/generators/test_unit/model/templates/fixtures.yml2
-rw-r--r--railties/test/application/asset_debugging_test.rb8
-rw-r--r--railties/test/application/assets_test.rb44
-rw-r--r--railties/test/application/rake_test.rb6
-rw-r--r--railties/test/generators/actions_test.rb16
-rw-r--r--railties/test/generators/plugin_new_generator_test.rb6
-rw-r--r--railties/test/generators/shared_generator_tests.rb4
-rw-r--r--railties/test/railties/engine_test.rb2
-rw-r--r--railties/test/railties/shared_tests.rb10
66 files changed, 1013 insertions, 554 deletions
diff --git a/Gemfile b/Gemfile
index f0880926a3..d36aec6b4a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,6 +6,7 @@ if ENV['AREL']
gem "arel", :path => ENV['AREL']
end
+gem "bcrypt-ruby", "~> 3.0.0"
gem "jquery-rails"
# This needs to be with require false to avoid
# it being automatically loaded by sprockets
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 71f38797ae..82dfc625a6 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,21 @@
*Rails 3.2.0 (unreleased)*
+* 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:
+
+ @items.each do |item|
+ content_tag_for(:li, item) do
+ Title: <%= item.title %>
+ end
+ end
+
+ You can now do this:
+
+ content_tag_for(:li, @items) do |item|
+ Title: <%= item.title %>
+ end
+
* send_file now guess the mime type [Esad Hajdarevic]
* Mime type entries for PDF, ZIP and other formats were added [Esad Hajdarevic]
@@ -30,11 +46,14 @@
*Rails 3.1.1 (unreleased)*
+* 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]
+
* CookieJar is now Enumerable. Fixes #2795
-* Fixed AssetNotPrecompiled error raised when rake assets:precompile is compiling certain .erb files. [Guillermo Iguaran]
+* Fixed AssetNotPrecompiled error raised when rake assets:precompile is compiling certain .erb files. See GH #2763 #2765 #2805 [Guillermo Iguaran]
-* Manifest is correctly placed in assets path when default assets prefix is changed. [Guillermo Iguaran]
+* Manifest is correctly placed in assets path when default assets prefix is changed. Fixes #2776 [Guillermo Iguaran]
* Fixed stylesheet_link_tag and javascript_include_tag to respect additional options passed by the users when debug is on. [Guillermo Iguaran]
diff --git a/actionpack/lib/action_controller/caching/sweeping.rb b/actionpack/lib/action_controller/caching/sweeping.rb
index 938a6ae81c..49cf70ec21 100644
--- a/actionpack/lib/action_controller/caching/sweeping.rb
+++ b/actionpack/lib/action_controller/caching/sweeping.rb
@@ -88,7 +88,7 @@ module ActionController #:nodoc:
end
def method_missing(method, *arguments, &block)
- return if @controller.nil?
+ return unless @controller
@controller.__send__(method, *arguments, &block)
end
end
diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb
index 2df0e9422c..bd515bba82 100644
--- a/actionpack/lib/action_controller/metal/helpers.rb
+++ b/actionpack/lib/action_controller/metal/helpers.rb
@@ -7,9 +7,12 @@ module ActionController
# by default.
#
# In addition to using the standard template helpers provided, creating custom helpers to
- # extract complicated logic or reusable functionality is strongly encouraged. By default, the controller will
- # include a helper whose name matches that of the controller, e.g., <tt>MyController</tt> will automatically
- # include <tt>MyHelper</tt>.
+ # extract complicated logic or reusable functionality is strongly encouraged. By default, each controller
+ # will include all helpers.
+ #
+ # In previous versions of \Rails the controller will include a helper whose
+ # name matches that of the controller, e.g., <tt>MyController</tt> will automatically
+ # include <tt>MyHelper</tt>. To return old behavior set +config.action_controller.include_all_helpers+ to +false+.
#
# Additional helpers can be specified using the +helper+ class method in ActionController::Base or any
# controller which inherits from it.
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index 4f311a1cf5..f2dfb3833b 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -57,7 +57,7 @@ module ActionController
# When using <tt>redirect_to :back</tt>, if there is no referrer, RedirectBackError will be raised. You may specify some fallback
# behavior for this case by rescuing RedirectBackError.
def redirect_to(options = {}, response_status = {}) #:doc:
- raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
+ raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise AbstractController::DoubleRenderError if response_body
self.status = _extract_redirect_to_status(options, response_status)
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 40332da321..a83fa74795 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -79,10 +79,10 @@ module ActionController
"expecting <?> but rendering with <?>",
options, rendered.keys.join(', '))
assert_block(msg) do
- if options.nil?
- @templates.blank?
- else
+ if options
rendered.any? { |t,num| t.match(options) }
+ else
+ @templates.blank?
end
end
when Hash
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index a5c1501f61..21dc5af486 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1036,12 +1036,12 @@ module ActionDispatch
#
# This generates the following comments routes:
#
- # GET /photos/:id/comments/new
- # POST /photos/:id/comments
- # GET /photos/:id/comments/:id
- # GET /photos/:id/comments/:id/edit
- # PUT /photos/:id/comments/:id
- # DELETE /photos/:id/comments/:id
+ # GET /photos/:photo_id/comments/new
+ # POST /photos/:photo_id/comments
+ # GET /photos/:photo_id/comments/:id
+ # GET /photos/:photo_id/comments/:id/edit
+ # PUT /photos/:photo_id/comments/:id
+ # DELETE /photos/:photo_id/comments/:id
#
# === Options
# Takes same options as <tt>Base#match</tt> as well as:
@@ -1436,7 +1436,7 @@ module ActionDispatch
name_prefix = @scope[:as]
if parent_resource
- return nil if as.nil? && action.nil?
+ return nil unless as || action
collection_name = parent_resource.collection_name
member_name = parent_resource.member_name
diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb
index aae8377f8a..73f4f8ee5f 100644
--- a/actionpack/lib/action_view/asset_paths.rb
+++ b/actionpack/lib/action_view/asset_paths.rb
@@ -69,7 +69,7 @@ module ActionView
host = "#{compute_protocol(protocol)}#{host}"
end
end
- host.nil? ? source : "#{host}#{source}"
+ host ? "#{host}#{source}" : source
end
def compute_protocol(protocol)
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 43d67f2032..36c49d9c91 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -116,7 +116,7 @@ module ActionView #:nodoc:
# xml.language "en-us"
# xml.ttl "40"
#
- # for item in @recent_items
+ # @recent_items.each do |item|
# xml.item do
# xml.title(item_title(item))
# xml.description(item_description(item)) if item_description(item)
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index 62f95379cd..8abd85c3a3 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -134,9 +134,9 @@ module ActionView
# WARNING: content_for is ignored in caches. So you shouldn't use it
# for elements that will be fragment cached.
def content_for(name, content = nil, &block)
- content = capture(&block) if block_given?
- if content
- @view_flow.append(name, content)
+ if content || block_given?
+ content = capture(&block) if block_given?
+ @view_flow.append(name, content) if content
nil
else
@view_flow.get(name)
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 1ceb53fe9c..13b9dc8553 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -656,7 +656,7 @@ module ActionView
if token == false || !protect_against_forgery?
''
else
- token = form_authenticity_token if token.nil?
+ token ||= form_authenticity_token
tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => token)
end
end
diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb
index 142a25f118..ad8896a2fd 100644
--- a/actionpack/lib/action_view/helpers/record_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb
@@ -17,6 +17,19 @@ module ActionView
#
# <div id="person_123" class="person foo"> Joe Bloggs </div>
#
+ # You can also pass an array of Active Record objects, which will then
+ # get iterates over and yield each record as an argument for the block.
+ # For example:
+ #
+ # <%= div_for(@people, :class => "foo") do |person| %>
+ # <%= person.name %>
+ # <% end %>
+ #
+ # produces:
+ #
+ # <div id="person_123" class="person foo"> Joe Bloggs </div>
+ # <div id="person_124" class="person foo"> Jane Bloggs </div>
+ #
def div_for(record, *args, &block)
content_tag_for(:div, record, *args, &block)
end
@@ -42,6 +55,21 @@ module ActionView
#
# <tr id="foo_person_123" class="person">...
#
+ # You can also pass an array of objects which this method will loop through
+ # and yield the current object to the supplied block, reduce the need for
+ # having to iterate through the object (using <tt>each</tt>) beforehand.
+ # For example (assuming @people is an array of Person objects):
+ #
+ # <%= content_tag_for(:tr, @people) do |person| %>
+ # <td><%= person.first_name %></td>
+ # <td><%= person.last_name %></td>
+ # <% end %>
+ #
+ # produces:
+ #
+ # <tr id="person_123" class="person">...</tr>
+ # <tr id="person_124" class="person">...</tr>
+ #
# content_tag_for also accepts a hash of options, which will be converted to
# additional HTML attributes. If you specify a <tt>:class</tt> value, it will be combined
# with the default class name for your object. For example:
@@ -52,12 +80,30 @@ module ActionView
#
# <li id="person_123" class="person bar">...
#
- def content_tag_for(tag_name, record, prefix = nil, options = nil, &block)
- options, prefix = prefix, nil if prefix.is_a?(Hash)
- options ||= {}
- options.merge!({ :class => "#{dom_class(record, prefix)} #{options[:class]}".strip, :id => dom_id(record, prefix) })
- content_tag(tag_name, options, &block)
+ def content_tag_for(tag_name, single_or_multiple_records, prefix = nil, options = nil, &block)
+ if single_or_multiple_records.respond_to?(:to_ary)
+ single_or_multiple_records.to_ary.map do |single_record|
+ capture { content_tag_for_single_record(tag_name, single_record, prefix, options, &block) }
+ end.join("\n")
+ else
+ content_tag_for_single_record(tag_name, single_or_multiple_records, prefix, options, &block)
+ end
end
+
+ private
+
+ # Called by <tt>content_tag_for</tt> internally to render a content tag
+ # for each record.
+ def content_tag_for_single_record(tag_name, record, prefix, options, &block)
+ options, prefix = prefix, nil if prefix.is_a?(Hash)
+ options ||= {}
+ options.merge!({ :class => "#{dom_class(record, prefix)} #{options[:class]}".strip, :id => dom_id(record, prefix) })
+ if block.arity == 0
+ content_tag(tag_name, capture(&block), options)
+ else
+ content_tag(tag_name, capture(record, &block), options)
+ end
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 5a043846a7..acd5e46e33 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -604,9 +604,7 @@ module ActionView
private
def convert_options_to_data_attributes(options, html_options)
- if html_options.nil?
- link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
- else
+ if html_options
html_options = html_options.stringify_keys
html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
@@ -619,6 +617,8 @@ module ActionView
add_method_to_attributes!(html_options, method) if method
html_options
+ else
+ link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
end
end
diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb
index 2dde2e9cc9..bcb70ee95d 100644
--- a/actionpack/lib/sprockets/helpers/rails_helper.rb
+++ b/actionpack/lib/sprockets/helpers/rails_helper.rb
@@ -124,7 +124,7 @@ module Sprockets
end
if compile_assets
- if asset = asset_environment[logical_path]
+ if digest_assets && asset = asset_environment[logical_path]
return asset.digest_path
end
return logical_path
@@ -137,7 +137,7 @@ module Sprockets
if source[0] == ?/
source
else
- source = digest_for(source) if digest_assets
+ source = digest_for(source)
source = File.join(dir, source)
source = "/#{source}" unless source =~ /^\//
source
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 6bcd606bf4..c46755417f 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -410,7 +410,7 @@ class TestController < ActionController::Base
end
def render_with_explicit_escaped_template
- render :template => "test/hello_w*rld"
+ render :template => "test/hello,world"
end
def render_with_explicit_string_template
diff --git a/actionpack/test/fixtures/test/hello_w*rld.erb b/actionpack/test/fixtures/test/hello,world.erb
index bc8fa5e0ca..bc8fa5e0ca 100644
--- a/actionpack/test/fixtures/test/hello_w*rld.erb
+++ b/actionpack/test/fixtures/test/hello,world.erb
diff --git a/actionpack/test/template/capture_helper_test.rb b/actionpack/test/template/capture_helper_test.rb
index a9157e711c..13e2d5b595 100644
--- a/actionpack/test/template/capture_helper_test.rb
+++ b/actionpack/test/template/capture_helper_test.rb
@@ -46,6 +46,42 @@ class CaptureHelperTest < ActionView::TestCase
assert_equal "bar", content_for(:bar)
end
+ def test_content_for_with_multiple_calls
+ assert ! content_for?(:title)
+ content_for :title, 'foo'
+ content_for :title, 'bar'
+ assert_equal 'foobar', content_for(:title)
+ end
+
+ def test_content_for_with_block
+ assert ! content_for?(:title)
+ content_for :title do
+ output_buffer << 'foo'
+ output_buffer << 'bar'
+ nil
+ end
+ assert_equal 'foobar', content_for(:title)
+ end
+
+ def test_content_for_with_whitespace_block
+ assert ! content_for?(:title)
+ content_for :title, 'foo'
+ content_for :title do
+ output_buffer << " \n "
+ nil
+ end
+ content_for :title, 'bar'
+ assert_equal 'foobar', content_for(:title)
+ end
+
+ def test_content_for_returns_nil_when_writing
+ assert ! content_for?(:title)
+ assert_equal nil, content_for(:title, 'foo')
+ assert_equal nil, content_for(:title) { output_buffer << 'bar'; nil }
+ assert_equal nil, content_for(:title) { output_buffer << " \n "; nil }
+ assert_equal 'foobar', content_for(:title)
+ end
+
def test_content_for_question_mark
assert ! content_for?(:title)
content_for :title, 'title'
diff --git a/actionpack/test/template/record_tag_helper_test.rb b/actionpack/test/template/record_tag_helper_test.rb
index 1ba14e8bc9..7d38b01c1b 100644
--- a/actionpack/test/template/record_tag_helper_test.rb
+++ b/actionpack/test/template/record_tag_helper_test.rb
@@ -4,11 +4,20 @@ require 'controller/fake_models'
class Post
extend ActiveModel::Naming
include ActiveModel::Conversion
+ attr_writer :id, :body
+
+ def initialize
+ @id = nil
+ @body = nil
+ super
+ end
+
def id
- 45
+ @id || 45
end
+
def body
- super || "What a wonderful world!"
+ super || @body || "What a wonderful world!"
end
end
@@ -58,4 +67,20 @@ class RecordTagHelperTest < ActionView::TestCase
actual = div_for(@post, :class => "bar") { concat @post.body }
assert_dom_equal expected, actual
end
+
+ def test_content_tag_for_collection
+ post_1 = Post.new.tap { |post| post.id = 101; post.body = "Hello!"; post.persisted = true }
+ post_2 = Post.new.tap { |post| post.id = 102; post.body = "World!"; post.persisted = true }
+ expected = %(<li class="post" id="post_101">Hello!</li>\n<li class="post" id="post_102">World!</li>)
+ actual = content_tag_for(:li, [post_1, post_2]) { |post| concat post.body }
+ assert_dom_equal expected, actual
+ end
+
+ def test_div_for_collection
+ post_1 = Post.new.tap { |post| post.id = 101; post.body = "Hello!"; post.persisted = true }
+ post_2 = Post.new.tap { |post| post.id = 102; post.body = "World!"; post.persisted = true }
+ expected = %(<div class="post" id="post_101">Hello!</div>\n<div class="post" id="post_102">World!</div>)
+ actual = div_for([post_1, post_2]) { |post| concat post.body }
+ assert_dom_equal expected, actual
+ end
end
diff --git a/activemodel/activemodel.gemspec b/activemodel/activemodel.gemspec
index e5075485bb..260ad01b65 100644
--- a/activemodel/activemodel.gemspec
+++ b/activemodel/activemodel.gemspec
@@ -19,5 +19,4 @@ Gem::Specification.new do |s|
s.add_dependency('activesupport', version)
s.add_dependency('builder', '~> 3.0.0')
s.add_dependency('i18n', '~> 0.6')
- s.add_dependency('bcrypt-ruby', '~> 3.0.0')
end
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index e3e71525fa..166cccf161 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -29,7 +29,7 @@ module ActiveModel
#
# include ActiveModel::Dirty
#
- # define_attribute_methods = [:name]
+ # define_attribute_methods [:name]
#
# def name
# @name
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
index 63380d6ffd..7a109d9a52 100644
--- a/activemodel/lib/active_model/secure_password.rb
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -1,5 +1,3 @@
-require 'bcrypt'
-
module ActiveModel
module SecurePassword
extend ActiveSupport::Concern
@@ -12,6 +10,10 @@ module ActiveModel
# a "password_confirmation" attribute) are automatically added.
# You can add more validations by hand if need be.
#
+ # You need to add bcrypt-ruby (~> 3.0.0) to Gemfile to use has_secure_password:
+ #
+ # gem 'bcrypt-ruby', '~> 3.0.0'
+ #
# Example using Active Record (which automatically includes ActiveModel::SecurePassword):
#
# # Schema: User(name:string, password_digest:string)
@@ -30,6 +32,11 @@ module ActiveModel
# User.find_by_name("david").try(:authenticate, "notright") # => nil
# User.find_by_name("david").try(:authenticate, "mUc3m00RsqyRe") # => user
def has_secure_password
+ # Load bcrypt-ruby only when has_secured_password is used to avoid make ActiveModel
+ # (and by extension the entire framework) dependent on a binary library.
+ gem 'bcrypt-ruby', '~> 3.0.0'
+ require 'bcrypt'
+
attr_reader :password
validates_confirmation_of :password
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 3f36dcde14..6f1ec7f9b3 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -24,375 +24,368 @@ end
class FixturesFileNotFound < StandardError; end
-# Fixtures are a way of organizing data that you want to test against; in short, sample data.
-#
-# = Fixture formats
-#
-# Fixtures come in 1 flavor:
-#
-# 1. YAML fixtures
-#
-# == YAML fixtures
-#
-# This type of fixture is in YAML format and the preferred default. YAML is a file format which describes data structures
-# in a non-verbose, human-readable format. It ships with Ruby 1.8.1+.
-#
-# Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed
-# in the directory appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is
-# automatically configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/</tt>).
-# The fixture file ends with the <tt>.yml</tt> file extension (Rails example:
-# <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>). The format of a YAML fixture file looks like this:
-#
-# rubyonrails:
-# id: 1
-# name: Ruby on Rails
-# url: http://www.rubyonrails.org
-#
-# google:
-# id: 2
-# name: Google
-# url: http://www.google.com
-#
-# This YAML fixture file includes two fixtures. Each YAML fixture (ie. record) is given a name and is followed by an
-# indented list of key/value pairs in the "key: value" format. Records are separated by a blank line for your viewing
-# pleasure.
-#
-# Note that YAML fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
-# See http://yaml.org/type/omap.html
-# for the specification. You will need ordered fixtures when you have foreign key constraints on keys in the same table.
-# This is commonly needed for tree structures. Example:
-#
-# --- !omap
-# - parent:
-# id: 1
-# parent_id: NULL
-# title: Parent
-# - child:
-# id: 2
-# parent_id: 1
-# title: Child
-#
-# = Using fixtures in testcases
-#
-# Since fixtures are a testing construct, we use them in our unit and functional tests. There are two ways to use the
-# fixtures, but first let's take a look at a sample unit test:
-#
-# require 'test_helper'
-#
-# class WebSiteTest < ActiveSupport::TestCase
-# test "web_site_count" do
-# assert_equal 2, WebSite.count
-# end
-# end
-#
-# By default, the <tt>test_helper module</tt> will load all of your fixtures into your test database,
-# so this test will succeed.
-# The testing environment will automatically load the all fixtures into the database before each test.
-# To ensure consistent data, the environment deletes the fixtures before running the load.
-#
-# In addition to being available in the database, the fixture's data may also be accessed by
-# using a special dynamic method, which has the same name as the model, and accepts the
-# name of the fixture to instantiate:
-#
-# test "find" do
-# assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
-# end
-#
-# Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the following tests:
-#
-# test "find_alt_method_1" do
-# assert_equal "Ruby on Rails", @web_sites['rubyonrails']['name']
-# end
-#
-# test "find_alt_method_2" do
-# assert_equal "Ruby on Rails", @rubyonrails.news
-# end
-#
-# In order to use these methods to access fixtured data within your testcases, you must specify one of the
-# following in your <tt>ActiveSupport::TestCase</tt>-derived class:
-#
-# - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above)
-# self.use_instantiated_fixtures = true
-#
-# - create only the hash for the fixtures, do not 'find' each instance (enable alternate method #1 only)
-# self.use_instantiated_fixtures = :no_instances
-#
-# Using either of these alternate methods incurs a performance hit, as the fixtured data must be fully
-# traversed in the database to create the fixture hash and/or instance variables. This is expensive for
-# large sets of fixtured data.
-#
-# = Dynamic fixtures with ERB
-#
-# Some times you don't care about the content of the fixtures as much as you care about the volume. In these cases, you can
-# mix ERB in with your YAML fixtures to create a bunch of fixtures for load testing, like:
-#
-# <% for i in 1..1000 %>
-# fix_<%= i %>:
-# id: <%= i %>
-# name: guy_<%= 1 %>
-# <% end %>
-#
-# This will create 1000 very simple YAML fixtures.
-#
-# Using ERB, you can also inject dynamic values into your fixtures with inserts like <tt><%= Date.today.strftime("%Y-%m-%d") %></tt>.
-# This is however a feature to be used with some caution. The point of fixtures are that they're
-# stable units of predictable sample data. If you feel that you need to inject dynamic values, then
-# perhaps you should reexamine whether your application is properly testable. Hence, dynamic values
-# in fixtures are to be considered a code smell.
-#
-# = Transactional fixtures
-#
-# TestCases can use begin+rollback to isolate their changes to the database instead of having to
-# delete+insert for every test case.
-#
-# class FooTest < ActiveSupport::TestCase
-# self.use_transactional_fixtures = true
-#
-# test "godzilla" do
-# assert !Foo.all.empty?
-# Foo.destroy_all
-# assert Foo.all.empty?
-# end
-#
-# test "godzilla aftermath" do
-# assert !Foo.all.empty?
-# end
-# end
-#
-# If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures,
-# then you may omit all fixtures declarations in your test cases since all the data's already there
-# and every case rolls back its changes.
-#
-# In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to true. This will provide
-# access to fixture data for every table that has been loaded through fixtures (depending on the
-# value of +use_instantiated_fixtures+)
-#
-# When *not* to use transactional fixtures:
-#
-# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until
-# all parent transactions commit, particularly, the fixtures transaction which is begun in setup
-# and rolled back in teardown. Thus, you won't be able to verify
-# the results of your transaction until Active Record supports nested transactions or savepoints (in progress).
-# 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
-# Use InnoDB, MaxDB, or NDB instead.
-#
-# = Advanced YAML Fixtures
-#
-# YAML fixtures that don't specify an ID get some extra features:
-#
-# * Stable, autogenerated IDs
-# * Label references for associations (belongs_to, has_one, has_many)
-# * HABTM associations as inline lists
-# * Autofilled timestamp columns
-# * Fixture label interpolation
-# * Support for YAML defaults
-#
-# == Stable, autogenerated IDs
-#
-# Here, have a monkey fixture:
-#
-# george:
-# id: 1
-# name: George the Monkey
-#
-# reginald:
-# id: 2
-# name: Reginald the Pirate
-#
-# Each of these fixtures has two unique identifiers: one for the database
-# and one for the humans. Why don't we generate the primary key instead?
-# Hashing each fixture's label yields a consistent ID:
-#
-# george: # generated id: 503576764
-# name: George the Monkey
-#
-# reginald: # generated id: 324201669
-# name: Reginald the Pirate
-#
-# Active Record looks at the fixture's model class, discovers the correct
-# primary key, and generates it right before inserting the fixture
-# into the database.
-#
-# The generated ID for a given label is constant, so we can discover
-# any fixture's ID without loading anything, as long as we know the label.
-#
-# == Label references for associations (belongs_to, has_one, has_many)
-#
-# Specifying foreign keys in fixtures can be very fragile, not to
-# mention difficult to read. Since Active Record can figure out the ID of
-# any fixture from its label, you can specify FK's by label instead of ID.
-#
-# === belongs_to
-#
-# Let's break out some more monkeys and pirates.
-#
-# ### in pirates.yml
-#
-# reginald:
-# id: 1
-# name: Reginald the Pirate
-# monkey_id: 1
-#
-# ### in monkeys.yml
-#
-# george:
-# id: 1
-# name: George the Monkey
-# pirate_id: 1
-#
-# Add a few more monkeys and pirates and break this into multiple files,
-# and it gets pretty hard to keep track of what's going on. Let's
-# use labels instead of IDs:
-#
-# ### in pirates.yml
-#
-# reginald:
-# name: Reginald the Pirate
-# monkey: george
-#
-# ### in monkeys.yml
-#
-# george:
-# name: George the Monkey
-# pirate: reginald
-#
-# Pow! All is made clear. Active Record reflects on the fixture's model class,
-# finds all the +belongs_to+ associations, and allows you to specify
-# a target *label* for the *association* (monkey: george) rather than
-# a target *id* for the *FK* (<tt>monkey_id: 1</tt>).
-#
-# ==== Polymorphic belongs_to
-#
-# Supporting polymorphic relationships is a little bit more complicated, since
-# Active Record needs to know what type your association is pointing at. Something
-# like this should look familiar:
-#
-# ### in fruit.rb
-#
-# belongs_to :eater, :polymorphic => true
-#
-# ### in fruits.yml
-#
-# apple:
-# id: 1
-# name: apple
-# eater_id: 1
-# eater_type: Monkey
-#
-# Can we do better? You bet!
-#
-# apple:
-# eater: george (Monkey)
-#
-# Just provide the polymorphic target type and Active Record will take care of the rest.
-#
-# === has_and_belongs_to_many
-#
-# Time to give our monkey some fruit.
-#
-# ### in monkeys.yml
-#
-# george:
-# id: 1
-# name: George the Monkey
-#
-# ### in fruits.yml
-#
-# apple:
-# id: 1
-# name: apple
-#
-# orange:
-# id: 2
-# name: orange
-#
-# grape:
-# id: 3
-# name: grape
-#
-# ### in fruits_monkeys.yml
-#
-# apple_george:
-# fruit_id: 1
-# monkey_id: 1
-#
-# orange_george:
-# fruit_id: 2
-# monkey_id: 1
-#
-# grape_george:
-# fruit_id: 3
-# monkey_id: 1
-#
-# Let's make the HABTM fixture go away.
-#
-# ### in monkeys.yml
-#
-# george:
-# id: 1
-# name: George the Monkey
-# fruits: apple, orange, grape
-#
-# ### in fruits.yml
-#
-# apple:
-# name: apple
-#
-# orange:
-# name: orange
-#
-# grape:
-# name: grape
-#
-# Zap! No more fruits_monkeys.yml file. We've specified the list of fruits
-# on George's fixture, but we could've just as easily specified a list
-# of monkeys on each fruit. As with +belongs_to+, Active Record reflects on
-# the fixture's model class and discovers the +has_and_belongs_to_many+
-# associations.
-#
-# == Autofilled timestamp columns
-#
-# If your table/model specifies any of Active Record's
-# standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+),
-# they will automatically be set to <tt>Time.now</tt>.
-#
-# If you've set specific values, they'll be left alone.
-#
-# == Fixture label interpolation
-#
-# The label of the current fixture is always available as a column value:
-#
-# geeksomnia:
-# name: Geeksomnia's Account
-# subdomain: $LABEL
-#
-# Also, sometimes (like when porting older join table fixtures) you'll need
-# to be able to get a hold of the identifier for a given label. ERB
-# to the rescue:
-#
-# george_reginald:
-# monkey_id: <%= ActiveRecord::Fixtures.identify(:reginald) %>
-# pirate_id: <%= ActiveRecord::Fixtures.identify(:george) %>
-#
-# == Support for YAML defaults
-#
-# You probably already know how to use YAML to set and reuse defaults in
-# your <tt>database.yml</tt> file. You can use the same technique in your fixtures:
-#
-# DEFAULTS: &DEFAULTS
-# created_on: <%= 3.weeks.ago.to_s(:db) %>
-#
-# first:
-# name: Smurf
-# *DEFAULTS
-#
-# second:
-# name: Fraggle
-# *DEFAULTS
-#
-# Any fixture labeled "DEFAULTS" is safely ignored.
-
module ActiveRecord
+ # \Fixtures are a way of organizing data that you want to test against; in short, sample data.
+ #
+ # They are stored in YAML files, one file per model, which are placed in the directory
+ # appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically
+ # configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/</tt>).
+ # The fixture file ends with the <tt>.yml</tt> file extension (Rails example:
+ # <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>). The format of a fixture file looks
+ # like this:
+ #
+ # rubyonrails:
+ # id: 1
+ # name: Ruby on Rails
+ # url: http://www.rubyonrails.org
+ #
+ # google:
+ # id: 2
+ # name: Google
+ # url: http://www.google.com
+ #
+ # This fixture file includes two fixtures. Each YAML fixture (ie. record) is given a name and
+ # is followed by an indented list of key/value pairs in the "key: value" format. Records are
+ # separated by a blank line for your viewing pleasure.
+ #
+ # Note that fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
+ # See http://yaml.org/type/omap.html
+ # for the specification. You will need ordered fixtures when you have foreign key constraints
+ # on keys in the same table. This is commonly needed for tree structures. Example:
+ #
+ # --- !omap
+ # - parent:
+ # id: 1
+ # parent_id: NULL
+ # title: Parent
+ # - child:
+ # id: 2
+ # parent_id: 1
+ # title: Child
+ #
+ # = Using Fixtures in Test Cases
+ #
+ # Since fixtures are a testing construct, we use them in our unit and functional tests. There
+ # are two ways to use the fixtures, but first let's take a look at a sample unit test:
+ #
+ # require 'test_helper'
+ #
+ # class WebSiteTest < ActiveSupport::TestCase
+ # test "web_site_count" do
+ # assert_equal 2, WebSite.count
+ # end
+ # end
+ #
+ # By default, <tt>test_helper.rb</tt> will load all of your fixtures into your test database,
+ # so this test will succeed.
+ #
+ # The testing environment will automatically load the all fixtures into the database before each
+ # test. To ensure consistent data, the environment deletes the fixtures before running the load.
+ #
+ # In addition to being available in the database, the fixture's data may also be accessed by
+ # using a special dynamic method, which has the same name as the model, and accepts the
+ # name of the fixture to instantiate:
+ #
+ # test "find" do
+ # assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
+ # end
+ #
+ # Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the
+ # following tests:
+ #
+ # test "find_alt_method_1" do
+ # assert_equal "Ruby on Rails", @web_sites['rubyonrails']['name']
+ # end
+ #
+ # test "find_alt_method_2" do
+ # assert_equal "Ruby on Rails", @rubyonrails.news
+ # end
+ #
+ # In order to use these methods to access fixtured data within your testcases, you must specify one of the
+ # following in your <tt>ActiveSupport::TestCase</tt>-derived class:
+ #
+ # - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above)
+ # self.use_instantiated_fixtures = true
+ #
+ # - create only the hash for the fixtures, do not 'find' each instance (enable alternate method #1 only)
+ # self.use_instantiated_fixtures = :no_instances
+ #
+ # Using either of these alternate methods incurs a performance hit, as the fixtured data must be fully
+ # traversed in the database to create the fixture hash and/or instance variables. This is expensive for
+ # large sets of fixtured data.
+ #
+ # = Dynamic fixtures with ERB
+ #
+ # Some times you don't care about the content of the fixtures as much as you care about the volume.
+ # In these cases, you can mix ERB in with your YAML fixtures to create a bunch of fixtures for load
+ # testing, like:
+ #
+ # <% 1.upto(1000) do |i| %>
+ # fix_<%= i %>:
+ # id: <%= i %>
+ # name: guy_<%= 1 %>
+ # <% end %>
+ #
+ # This will create 1000 very simple fixtures.
+ #
+ # Using ERB, you can also inject dynamic values into your fixtures with inserts like
+ # <tt><%= Date.today.strftime("%Y-%m-%d") %></tt>.
+ # This is however a feature to be used with some caution. The point of fixtures are that they're
+ # stable units of predictable sample data. If you feel that you need to inject dynamic values, then
+ # perhaps you should reexamine whether your application is properly testable. Hence, dynamic values
+ # in fixtures are to be considered a code smell.
+ #
+ # = Transactional Fixtures
+ #
+ # Test cases can use begin+rollback to isolate their changes to the database instead of having to
+ # delete+insert for every test case.
+ #
+ # class FooTest < ActiveSupport::TestCase
+ # self.use_transactional_fixtures = true
+ #
+ # test "godzilla" do
+ # assert !Foo.all.empty?
+ # Foo.destroy_all
+ # assert Foo.all.empty?
+ # end
+ #
+ # test "godzilla aftermath" do
+ # assert !Foo.all.empty?
+ # end
+ # end
+ #
+ # If you preload your test database with all fixture data (probably in the rake task) and use
+ # transactional fixtures, then you may omit all fixtures declarations in your test cases since
+ # all the data's already there and every case rolls back its changes.
+ #
+ # In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to
+ # true. This will provide access to fixture data for every table that has been loaded through
+ # fixtures (depending on the value of +use_instantiated_fixtures+).
+ #
+ # When *not* to use transactional fixtures:
+ #
+ # 1. You're testing whether a transaction works correctly. Nested transactions don't commit until
+ # all parent transactions commit, particularly, the fixtures transaction which is begun in setup
+ # and rolled back in teardown. Thus, you won't be able to verify
+ # the results of your transaction until Active Record supports nested transactions or savepoints (in progress).
+ # 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
+ # Use InnoDB, MaxDB, or NDB instead.
+ #
+ # = Advanced Fixtures
+ #
+ # Fixtures that don't specify an ID get some extra features:
+ #
+ # * Stable, autogenerated IDs
+ # * Label references for associations (belongs_to, has_one, has_many)
+ # * HABTM associations as inline lists
+ # * Autofilled timestamp columns
+ # * Fixture label interpolation
+ # * Support for YAML defaults
+ #
+ # == Stable, Autogenerated IDs
+ #
+ # Here, have a monkey fixture:
+ #
+ # george:
+ # id: 1
+ # name: George the Monkey
+ #
+ # reginald:
+ # id: 2
+ # name: Reginald the Pirate
+ #
+ # Each of these fixtures has two unique identifiers: one for the database
+ # and one for the humans. Why don't we generate the primary key instead?
+ # Hashing each fixture's label yields a consistent ID:
+ #
+ # george: # generated id: 503576764
+ # name: George the Monkey
+ #
+ # reginald: # generated id: 324201669
+ # name: Reginald the Pirate
+ #
+ # Active Record looks at the fixture's model class, discovers the correct
+ # primary key, and generates it right before inserting the fixture
+ # into the database.
+ #
+ # The generated ID for a given label is constant, so we can discover
+ # any fixture's ID without loading anything, as long as we know the label.
+ #
+ # == Label references for associations (belongs_to, has_one, has_many)
+ #
+ # Specifying foreign keys in fixtures can be very fragile, not to
+ # mention difficult to read. Since Active Record can figure out the ID of
+ # any fixture from its label, you can specify FK's by label instead of ID.
+ #
+ # === belongs_to
+ #
+ # Let's break out some more monkeys and pirates.
+ #
+ # ### in pirates.yml
+ #
+ # reginald:
+ # id: 1
+ # name: Reginald the Pirate
+ # monkey_id: 1
+ #
+ # ### in monkeys.yml
+ #
+ # george:
+ # id: 1
+ # name: George the Monkey
+ # pirate_id: 1
+ #
+ # Add a few more monkeys and pirates and break this into multiple files,
+ # and it gets pretty hard to keep track of what's going on. Let's
+ # use labels instead of IDs:
+ #
+ # ### in pirates.yml
+ #
+ # reginald:
+ # name: Reginald the Pirate
+ # monkey: george
+ #
+ # ### in monkeys.yml
+ #
+ # george:
+ # name: George the Monkey
+ # pirate: reginald
+ #
+ # Pow! All is made clear. Active Record reflects on the fixture's model class,
+ # finds all the +belongs_to+ associations, and allows you to specify
+ # a target *label* for the *association* (monkey: george) rather than
+ # a target *id* for the *FK* (<tt>monkey_id: 1</tt>).
+ #
+ # ==== Polymorphic belongs_to
+ #
+ # Supporting polymorphic relationships is a little bit more complicated, since
+ # Active Record needs to know what type your association is pointing at. Something
+ # like this should look familiar:
+ #
+ # ### in fruit.rb
+ #
+ # belongs_to :eater, :polymorphic => true
+ #
+ # ### in fruits.yml
+ #
+ # apple:
+ # id: 1
+ # name: apple
+ # eater_id: 1
+ # eater_type: Monkey
+ #
+ # Can we do better? You bet!
+ #
+ # apple:
+ # eater: george (Monkey)
+ #
+ # Just provide the polymorphic target type and Active Record will take care of the rest.
+ #
+ # === has_and_belongs_to_many
+ #
+ # Time to give our monkey some fruit.
+ #
+ # ### in monkeys.yml
+ #
+ # george:
+ # id: 1
+ # name: George the Monkey
+ #
+ # ### in fruits.yml
+ #
+ # apple:
+ # id: 1
+ # name: apple
+ #
+ # orange:
+ # id: 2
+ # name: orange
+ #
+ # grape:
+ # id: 3
+ # name: grape
+ #
+ # ### in fruits_monkeys.yml
+ #
+ # apple_george:
+ # fruit_id: 1
+ # monkey_id: 1
+ #
+ # orange_george:
+ # fruit_id: 2
+ # monkey_id: 1
+ #
+ # grape_george:
+ # fruit_id: 3
+ # monkey_id: 1
+ #
+ # Let's make the HABTM fixture go away.
+ #
+ # ### in monkeys.yml
+ #
+ # george:
+ # id: 1
+ # name: George the Monkey
+ # fruits: apple, orange, grape
+ #
+ # ### in fruits.yml
+ #
+ # apple:
+ # name: apple
+ #
+ # orange:
+ # name: orange
+ #
+ # grape:
+ # name: grape
+ #
+ # Zap! No more fruits_monkeys.yml file. We've specified the list of fruits
+ # on George's fixture, but we could've just as easily specified a list
+ # of monkeys on each fruit. As with +belongs_to+, Active Record reflects on
+ # the fixture's model class and discovers the +has_and_belongs_to_many+
+ # associations.
+ #
+ # == Autofilled Timestamp Columns
+ #
+ # If your table/model specifies any of Active Record's
+ # standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+),
+ # they will automatically be set to <tt>Time.now</tt>.
+ #
+ # If you've set specific values, they'll be left alone.
+ #
+ # == Fixture label interpolation
+ #
+ # The label of the current fixture is always available as a column value:
+ #
+ # geeksomnia:
+ # name: Geeksomnia's Account
+ # subdomain: $LABEL
+ #
+ # Also, sometimes (like when porting older join table fixtures) you'll need
+ # to be able to get a hold of the identifier for a given label. ERB
+ # to the rescue:
+ #
+ # george_reginald:
+ # monkey_id: <%= ActiveRecord::Fixtures.identify(:reginald) %>
+ # pirate_id: <%= ActiveRecord::Fixtures.identify(:george) %>
+ #
+ # == Support for YAML defaults
+ #
+ # You probably already know how to use YAML to set and reuse defaults in
+ # your <tt>database.yml</tt> file. You can use the same technique in your fixtures:
+ #
+ # DEFAULTS: &DEFAULTS
+ # created_on: <%= 3.weeks.ago.to_s(:db) %>
+ #
+ # first:
+ # name: Smurf
+ # *DEFAULTS
+ #
+ # second:
+ # name: Fraggle
+ # *DEFAULTS
+ #
+ # Any fixture labeled "DEFAULTS" is safely ignored.
class Fixtures
MAX_ID = 2 ** 30 - 1
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb
index ec1176e3dd..2fd89882ff 100644
--- a/activerecord/lib/active_record/relation/batches.rb
+++ b/activerecord/lib/active_record/relation/batches.rb
@@ -62,7 +62,7 @@ module ActiveRecord
start = options.delete(:start).to_i
batch_size = options.delete(:batch_size) || 1000
- relation = relation.except(:order).order(batch_order).limit(batch_size)
+ relation = relation.reorder(batch_order).limit(batch_size)
records = relation.where(table[primary_key].gteq(start)).all
while records.any?
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 73368aed18..83d650d3f4 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -114,7 +114,7 @@ module ActiveRecord
def first(*args)
if args.any?
if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
- to_a.first(*args)
+ limit(*args).to_a
else
apply_finder_options(args.first).first
end
@@ -134,7 +134,11 @@ module ActiveRecord
def last(*args)
if args.any?
if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
- to_a.last(*args)
+ if order_values.empty? && reorder_value.nil?
+ order("#{primary_key} DESC").limit(*args).reverse
+ else
+ to_a.last(*args)
+ end
else
apply_finder_options(args.first).last
end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 355540782f..7eda9ad8e8 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -305,8 +305,10 @@ module ActiveRecord
when Arel::Nodes::Ordering
o.reverse
when String, Symbol
- s = o.to_s.gsub(/\s((desc)|(asc))\s*(,|\Z)/i) { |m| " #{$2 ? 'ASC' : 'DESC'}#{$4}" }
- s.match(/\s(de|a)sc\Z/i) ? s : s.concat(" DESC")
+ o.to_s.split(',').collect do |s|
+ s.strip!
+ s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC')
+ end
else
o
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 1e647b5970..8b95eb958b 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -24,6 +24,7 @@ require 'models/joke'
require 'models/bulb'
require 'rexml/document'
require 'active_support/core_ext/exception'
+require 'bcrypt'
class Category < ActiveRecord::Base; end
class Categorization < ActiveRecord::Base; end
diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb
index a35baee4ed..660098b9ad 100644
--- a/activerecord/test/cases/batches_test.rb
+++ b/activerecord/test/cases/batches_test.rb
@@ -113,7 +113,27 @@ class EachTest < ActiveRecord::TestCase
batch.map! { not_a_post }
end
end
+ end
+ def test_find_in_batches_should_ignore_the_order_default_scope
+ # First post is with title scope
+ first_post = PostWithDefaultScope.first
+ posts = []
+ PostWithDefaultScope.find_in_batches do |batch|
+ posts.concat(batch)
+ end
+ # posts.first will be ordered using id only. Title order scope should not apply here
+ assert_not_equal first_post, posts.first
+ assert_equal posts(:welcome), posts.first
+ end
+
+ def test_find_in_batches_should_not_ignore_the_default_scope_if_it_is_other_then_order
+ special_posts_ids = SpecialPostWithDefaultScope.all.map(&:id).sort
+ posts = []
+ SpecialPostWithDefaultScope.find_in_batches do |batch|
+ posts.concat(batch)
+ end
+ assert_equal special_posts_ids, posts.map(&:id)
end
end
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 5dc5f99582..d840d38678 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -243,6 +243,32 @@ class FinderTest < ActiveRecord::TestCase
end
end
+ def test_first_and_last_with_integer_should_use_sql_limit
+ assert_sql(/LIMIT 2/) { Topic.first(2).entries }
+ assert_sql(/LIMIT 5/) { Topic.last(5).entries }
+ end
+
+ def test_last_with_integer_and_order_should_keep_the_order
+ assert_equal Topic.order("title").to_a.last(2), Topic.order("title").last(2)
+ end
+
+ def test_last_with_integer_and_order_should_not_use_sql_limit
+ query = assert_sql { Topic.order("title").last(5).entries }
+ assert_equal 1, query.length
+ assert_no_match(/LIMIT/, query.first)
+ end
+
+ def test_last_with_integer_and_reorder_should_not_use_sql_limit
+ query = assert_sql { Topic.reorder("title").last(5).entries }
+ assert_equal 1, query.length
+ assert_no_match(/LIMIT/, query.first)
+ end
+
+ def test_first_and_last_with_integer_should_return_an_array
+ assert_kind_of Array, Topic.first(5)
+ assert_kind_of Array, Topic.last(5)
+ end
+
def test_unexisting_record_exception_handling
assert_raise(ActiveRecord::RecordNotFound) {
Topic.find(1).parent
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index c3bad58174..da96afd718 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -934,11 +934,6 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 'zyke', FastCar.order_using_old_style.limit(1).first.name
end
- def test_order_with_function_and_last
- authors = Author.scoped
- assert_equal authors(:bob), authors.order( "id asc, COALESCE( organization_id, owned_essay_id)" ).last
- end
-
def test_order_using_scoping
car1 = CoolCar.order('id DESC').scoping do
CoolCar.find(:first, :order => 'id asc')
diff --git a/activerecord/test/fixtures/tasks.yml b/activerecord/test/fixtures/tasks.yml
index 01c95b3a4c..402ca85faf 100644
--- a/activerecord/test/fixtures/tasks.yml
+++ b/activerecord/test/fixtures/tasks.yml
@@ -1,4 +1,4 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
first_task:
id: 1
starting: 2005-03-30t06:30:00.00+01:00
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index affa37b02d..198a963cbc 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -171,4 +171,14 @@ class PostWithDefaultInclude < ActiveRecord::Base
self.table_name = 'posts'
default_scope includes(:comments)
has_many :comments, :foreign_key => :post_id
+end
+
+class PostWithDefaultScope < ActiveRecord::Base
+ self.table_name = 'posts'
+ default_scope :order => :title
+end
+
+class SpecialPostWithDefaultScope < ActiveRecord::Base
+ self.table_name = 'posts'
+ default_scope where(:id => [1, 5,6])
end \ No newline at end of file
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 3508ec0f34..18164234a5 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.2.0 (unreleased)*
+* ActiveSupport::OrderedHash is now marked as extractable when using Array#extract_options! [Prem Sichanugrist]
+
* Added Array#prepend as an alias for Array#unshift and Array#append as an alias for Array#<< [DHH]
* The definition of blank string for Ruby 1.9 has been extended to Unicode whitespace.
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index ddb4f3012f..9343bb7106 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -97,7 +97,7 @@ module Enumerable
end
# Returns true if the enumerable has more than 1 element. Functionally equivalent to enum.to_a.size > 1.
- # Can be called with a block too, much like any?, so people.many? { |p| p.age > 26 } returns true if more than 1 person is over 26.
+ # Can be called with a block too, much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns true if more than one person is over 26.
def many?
cnt = 0
if block_given?
@@ -110,7 +110,7 @@ module Enumerable
end
end
- # The negative of the Enumerable#include?. Returns true if the collection does not include the object.
+ # The negative of the <tt>Enumerable#include?</tt>. Returns true if the collection does not include the object.
def exclude?(object)
!include?(object)
end
diff --git a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
index 0b368fe7b7..f4cb445444 100644
--- a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
+++ b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
@@ -2,7 +2,7 @@ require 'active_support/hash_with_indifferent_access'
class Hash
- # Returns an +ActiveSupport::HashWithIndifferentAccess+ out of its receiver:
+ # Returns an <tt>ActiveSupport::HashWithIndifferentAccess</tt> out of its receiver:
#
# {:a => 1}.with_indifferent_access["a"] # => 1
#
diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb
index 59ffd24698..636f019cd5 100644
--- a/activesupport/lib/active_support/hash_with_indifferent_access.rb
+++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb
@@ -112,7 +112,7 @@ module ActiveSupport
end
end
- # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
+ # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash.
# Does not overwrite the existing hash.
def merge(hash)
self.dup.update(hash)
diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb
index 3e54134c5c..dcfcf0b63c 100644
--- a/activesupport/lib/active_support/log_subscriber/test_helper.rb
+++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb
@@ -18,8 +18,8 @@ module ActiveSupport
# Developer.all
# wait
# assert_equal 1, @logger.logged(:debug).size
- # assert_match /Developer Load/, @logger.logged(:debug).last
- # assert_match /SELECT \* FROM "developers"/, @logger.logged(:debug).last
+ # assert_match(/Developer Load/, @logger.logged(:debug).last)
+ # assert_match(/SELECT \* FROM "developers"/, @logger.logged(:debug).last)
# end
# end
#
diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb
index 7f70628933..0264133581 100644
--- a/activesupport/lib/active_support/ordered_hash.rb
+++ b/activesupport/lib/active_support/ordered_hash.rb
@@ -47,6 +47,11 @@ module ActiveSupport
self
end
+ # Returns true to make sure that this hash is extractable via <tt>Array#extract_options!</tt>
+ def extractable_options?
+ true
+ end
+
# Hash is ordered in Ruby 1.9!
if RUBY_VERSION < '1.9'
diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb
index 449d3810e2..f11bf3dc69 100644
--- a/activesupport/test/core_ext/module_test.rb
+++ b/activesupport/test/core_ext/module_test.rb
@@ -183,8 +183,9 @@ class ModuleTest < Test::Unit::TestCase
someone.foo
rescue NoMethodError => e
file_and_line = "#{__FILE__}:#{Someone::FAILED_DELEGATE_LINE}"
- assert e.backtrace.first.include?(file_and_line),
- "[#{e.backtrace.first}] did not include [#{file_and_line}]"
+ # We can't simply check the first line of the backtrace, because JRuby reports the call to __send__ in the backtrace.
+ assert e.backtrace.any?{|a| a.include?(file_and_line)},
+ "[#{e.backtrace.inspect}] did not include [#{file_and_line}]"
end
def test_delegation_exception_backtrace_with_allow_nil
@@ -192,8 +193,9 @@ class ModuleTest < Test::Unit::TestCase
someone.bar
rescue NoMethodError => e
file_and_line = "#{__FILE__}:#{Someone::FAILED_DELEGATE_LINE_2}"
- assert e.backtrace.first.include?(file_and_line),
- "[#{e.backtrace.first}] did not include [#{file_and_line}]"
+ # We can't simply check the first line of the backtrace, because JRuby reports the call to __send__ in the backtrace.
+ assert e.backtrace.any?{|a| a.include?(file_and_line)},
+ "[#{e.backtrace.inspect}] did not include [#{file_and_line}]"
end
def test_parent
diff --git a/activesupport/test/ordered_hash_test.rb b/activesupport/test/ordered_hash_test.rb
index bf851dbcbc..0b5f912dc4 100644
--- a/activesupport/test/ordered_hash_test.rb
+++ b/activesupport/test/ordered_hash_test.rb
@@ -329,4 +329,9 @@ class OrderedHashTest < Test::Unit::TestCase
assert_equal expected, @ordered_hash.invert
assert_equal @values.zip(@keys), @ordered_hash.invert.to_a
end
+
+ def test_extractable
+ @ordered_hash[:rails] = "snowman"
+ assert_equal @ordered_hash, [1, 2, @ordered_hash].extract_options!
+ end
end
diff --git a/railties/guides/source/3_1_release_notes.textile b/railties/guides/source/3_1_release_notes.textile
index 7de8866ff6..c4da87dc34 100644
--- a/railties/guides/source/3_1_release_notes.textile
+++ b/railties/guides/source/3_1_release_notes.textile
@@ -271,7 +271,7 @@ Post.new(params[:post], :as => :admin)
* +ConnectionManagement+ middleware is changed to clean up the connection pool after the rack body has been flushed.
-* Added an +update_column+ method on Active Record. This new method updates a given attribute on an object, skipping validations and callbacks. It is not recommended to use +update_attribute+ unless you are sure you do not want to execute any callback, including the modification of the +updated_at+ column. It should not be called on new records.
+* Added an +update_column+ method on Active Record. This new method updates a given attribute on an object, skipping validations and callbacks. It is recommended to use +update_attributes+ or +update_attribute+ unless you are sure you do not want to execute any callback, including the modification of the +updated_at+ column. It should not be called on new records.
* Associations with a +:through+ option can now use any association as the through or source association, including other associations which have a +:through+ option and +has_and_belongs_to_many+ associations.
@@ -315,7 +315,7 @@ end
<ruby>
class MyMigration < ActiveRecord::Migration
def change
- create_table(:horses) do
+ create_table(:horses) do |t|
t.column :content, :text
t.column :remind_at, :datetime
end
diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile
index 073e3bddcf..4e47712636 100644
--- a/railties/guides/source/action_controller_overview.textile
+++ b/railties/guides/source/action_controller_overview.textile
@@ -684,9 +684,11 @@ end
This will read and stream the file 4kB at the time, avoiding loading the entire file into memory at once. You can turn off streaming with the +:stream+ option or adjust the block size with the +:buffer_size+ option.
+If +:type+ is not specified, it will be guessed from the file extension specified in +:filename+. If the content type is not registered for the extension, <tt>application/octet-stream</tt> will be used.
+
WARNING: Be careful when using data coming from the client (params, cookies, etc.) to locate the file on disk, as this is a security risk that might allow someone to gain access to files they are not meant to see.
-TIP: It is not recommended that you stream static files through Rails if you can instead keep them in a public folder on your web server. It is much more efficient to let the user download the file directly using Apache or another web server, keeping the request from unnecessarily going through the whole Rails stack. Although if you do need the request to go through Rails for some reason, you can set the +:x_sendfile+ option to true, and Rails will let the web server handle sending the file to the user, freeing up the Rails process to do other things. Note that your web server needs to support the +X-Sendfile+ header for this to work.
+TIP: It is not recommended that you stream static files through Rails if you can instead keep them in a public folder on your web server. It is much more efficient to let the user download the file directly using Apache or another web server, keeping the request from unnecessarily going through the whole Rails stack.
h4. RESTful Downloads
diff --git a/railties/guides/source/action_mailer_basics.textile b/railties/guides/source/action_mailer_basics.textile
index 142b9dba7e..67761645fa 100644
--- a/railties/guides/source/action_mailer_basics.textile
+++ b/railties/guides/source/action_mailer_basics.textile
@@ -467,7 +467,7 @@ The following configuration options are best made in one of the environment file
h4. Example Action Mailer Configuration
-An example would be adding the following to your appropriate <tt>config/environments/env.rb</tt> file:
+An example would be adding the following to your appropriate <tt>config/environments/$RAILS_ENV.rb</tt> file:
<ruby>
config.action_mailer.delivery_method = :sendmail
@@ -482,7 +482,7 @@ config.action_mailer.raise_delivery_errors = true
h4. Action Mailer Configuration for GMail
-As Action Mailer now uses the Mail gem, this becomes as simple as adding to your <tt>config/environments/env.rb</tt> file:
+As Action Mailer now uses the Mail gem, this becomes as simple as adding to your <tt>config/environments/$RAILS_ENV.rb</tt> file:
<ruby>
config.action_mailer.delivery_method = :smtp
@@ -514,8 +514,8 @@ class UserMailerTest < ActionMailer::TestCase
# Test the body of the sent email contains what we expect it to
assert_equal [user.email], email.to
assert_equal "Welcome to My Awesome Site", email.subject
- assert_match /<h1>Welcome to example.com, #{user.name}<\/h1>/, email.encoded
- assert_match /Welcome to example.com, #{user.name}/, email.encoded
+ assert_match(/<h1>Welcome to example.com, #{user.name}<\/h1>/, email.encoded)
+ assert_match(/Welcome to example.com, #{user.name}/, email.encoded)
end
end
</ruby>
@@ -524,4 +524,5 @@ In the test we send the email and store the returned object in the +email+ varia
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 5a1e8b1247..d1827c649b 100644
--- a/railties/guides/source/action_view_overview.textile
+++ b/railties/guides/source/action_view_overview.textile
@@ -454,6 +454,83 @@ input("post", "title") # =>
<input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
</ruby>
+h4. RecordTagHelper
+
+This module provides methods for generating a container tag, such as a +<div>+, for your record. This is the recommended way of creating a container for render your Active Record object, as it adds an appropriate class and id attributes to that container. You can then refer to those containers easily by following the convention, instead of having to think about which class or id attribute you should use.
+
+h5. content_tag_for
+
+Renders a container tag that relates to your Active Record Object.
+
+For example, given +@post+ is the object of +Post+ class, you can do:
+
+<ruby>
+<%= content_tag_for(:tr, @post) do %>
+ <td><%= @post.title %></td>
+<% end %>
+</ruby>
+
+This will generate this HTML output:
+
+<html>
+<tr id="post_1234" class="post">
+ <td>Hello World!</td>
+</tr>
+</html>
+
+You can also supply HTML attributes as an additional option hash. For example:
+
+<ruby>
+<%= content_tag_for(:tr, @post, :class => "frontpage") do %>
+ <td><%= @post.title %></td>
+<% end %>
+</ruby>
+
+Will generate this HTML output:
+
+<html>
+<tr id="post_1234" class="post frontpage">
+ <td>Hello World!</td>
+</tr>
+</html>
+
+You can pass a collection of Active Record objects. This method will loops through your objects and create a container for each of them. For example, given +@posts+ is an array of two +Post+ objects:
+
+<ruby>
+<%= content_tag_for(:tr, @posts) do |post| %>
+ <td><%= post.title %></td>
+<% end %>
+</ruby>
+
+Will generate this HTML output:
+
+<html>
+<tr id="post_1234" class="post">
+ <td>Hello World!</td>
+</tr>
+<tr id="post_1235" class="post">
+ <td>Ruby on Rails Rocks!</td>
+</tr>
+</html>
+
+h5. div_for
+
+This is actually a convenient method which calls +content_tag_for+ internally with +:div+ as the tag name. You can pass either an Active Record object or a collection of objects. For example:
+
+<ruby>
+<%= div_for(@post, :class => "frontpage") do %>
+ <td><%= @post.title %></td>
+<% end %>
+</ruby>
+
+Will generate this HTML output:
+
+<html>
+<div id="post_1234" class="post frontpage">
+ <td>Hello World!</td>
+</div>
+</html>
+
h4. AssetTagHelper
This module provides methods for generating HTML that links views to assets such as images, JavaScript files, stylesheets, and feeds.
diff --git a/railties/guides/source/active_model_basics.textile b/railties/guides/source/active_model_basics.textile
index 0672669dc5..73df567579 100644
--- a/railties/guides/source/active_model_basics.textile
+++ b/railties/guides/source/active_model_basics.textile
@@ -163,12 +163,14 @@ person.first_name_changed? #=> true
</ruby>
Track what was the previous value of the attribute.
+
<ruby>
#attr_name_was accessor
person.first_name_was #=> "First Name"
</ruby>
Track both previous and current value of the changed attribute. Returns an array if changed else returns nil
+
<ruby>
#attr_name_change
person.first_name_change #=> ["First Name", "First Name 1"]
diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile
index 4e77a6e803..95a7bfebc3 100644
--- a/railties/guides/source/active_record_querying.textile
+++ b/railties/guides/source/active_record_querying.textile
@@ -132,7 +132,7 @@ SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
<tt>Model.last</tt> returns +nil+ if no matching record is found. No exception will be raised.
-h5. +first!+
+h5(#first_1). +first!+
<tt>Model.first!</tt> finds the first record. For example:
@@ -149,7 +149,7 @@ SELECT * FROM clients LIMIT 1
<tt>Model.first!</tt> raises +RecordNotFound+ if no matching record is found.
-h5. +last!+
+h5(#last_1). +last!+
<tt>Model.last!</tt> finds the last record. For example:
diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile
index d621dd5a70..54464cdf4d 100644
--- a/railties/guides/source/asset_pipeline.textile
+++ b/railties/guides/source/asset_pipeline.textile
@@ -13,13 +13,13 @@ endprologue.
h3. What is the Asset Pipeline?
-The asset pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in other languages such as CoffeeScript, SCSS and ERB.
+The asset pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in other languages such as CoffeeScript, Sass and ERB.
-Prior to Rails 3.1 these features were added through third-party Ruby libraries such as Jammit and Sprockets. Rails 3.1 is integrated with Sprockets through ActionPack which depends on the +sprockets+ gem, by default.
+Prior to Rails 3.1 these features were added through third-party Ruby libraries such as Jammit and Sprockets. Rails 3.1 is integrated with Sprockets through Action Pack which depends on the +sprockets+ gem, by default.
By having this as a core feature of Rails, all developers can benefit from the power of having their assets pre-processed, compressed and minified by one central library, Sprockets. This is part of Rails' "Fast by default" strategy as outlined by DHH in his 2011 keynote at Railsconf.
-In new Rails 3.1 application the asset pipeline is enabled by default. It can be disabled in +application.rb+ by putting this line inside the +Application+ class definition:
+In Rails 3.1, the asset pipeline is enabled by default. It can be disabled in +application.rb+ by putting this line inside the +Application+ class definition:
<plain>
config.assets.enabled = false
@@ -36,7 +36,7 @@ The default behavior in Rails 3.1 and onward is to concatenate all files into on
The second feature is to minify or compress assets. For CSS, this usually involves removing whitespace and comments. For JavaScript, more complex processes can be applied. You can choose from a set of built in options or specify your own.
-The third feature is the ability to code these assets using another language, or language extension. These include SCSS or Sass for CSS, CoffeeScript for JavaScript, and ERB for both.
+The third feature is the ability to code these assets using another language, or language extension. These include Sass for CSS, CoffeeScript for JavaScript, and ERB for both.
h4. What is Fingerprinting and Why Should I Care?
@@ -89,10 +89,14 @@ In previous versions of Rails, all assets were located in subdirectories of +pub
This is not to say that assets can (or should) no longer be placed in +public+; they still can be and will be served as static files by the application or web server. You would only use +app/assets+ if you wish your files to undergo some pre-processing before they are served.
-When a scaffold or controller is generated for the application, Rails also generates a JavaScript file (or CoffeeScript file if the +coffee-script+ gem is in the +Gemfile+) and a Cascading Style Sheet file (or SCSS file if +sass-rails+ is in the +Gemfile+) for that controller.
+In production, the default is to precompile these files to +public/assets+ so that they can be more efficiently delivered by the webserver.
+
+When a scaffold or controller is generated for the application, Rails also generates a JavaScript file (or CoffeeScript file if the +coffee-rails+ gem is in the +Gemfile+) and a Cascading Style Sheet file (or SCSS file if +sass-rails+ is in the +Gemfile+) for that controller.
For example, if a +ProjectsController+ is generated, there will be a new file at +app/assets/javascripts/projects.js.coffee+ and another at +app/assets/stylesheets/projects.css.scss+. You should put any JavaScript or CSS unique to a controller inside their respective asset files, as these files can then be loaded just for these controllers with lines such as +<%= javascript_include_tag params[:controller] %>+ or +<%= stylesheet_link_tag params[:controller] %>+.
+NOTE: You will need a "ExecJS":https://github.com/sstephenson/execjs#readme - supported runtime in order to use CoffeeScript. If you are using Mac OS X or Windows you have a JavaScript runtime installed in your operating system. Check "ExecJS":https://github.com/sstephenson/execjs#readme documentation to know all supported JavaScript runtimes.
+
h4. Asset Organization
Assets can be placed inside an application in one of three locations: +app/assets+, +lib/assets+ or +vendor/assets+.
@@ -103,13 +107,17 @@ Assets can be placed inside an application in one of three locations: +app/asset
+vendor/assets+ is for assets that are owned by outside entities, such as code for JavaScript plugins.
-All subdirectories that exist within these three locations are added to the search path for Sprockets (visible by calling +Rails.application.config.assets.paths+ in a console). When an asset is requested, these paths are looked through to see if they contain an asset matching the name specified. Once an asset has been found, it's processed by Sprockets and served.
+All subdirectories that exist within these three locations are added to the search path for Sprockets (visible by calling +Rails.application.config.assets.paths+ in a console). When an asset is requested, these paths are traversed to see if they contain an asset matching the name specified. Once an asset has been found, it's processed by Sprockets and served.
-h4. Coding Links to Assets
+You can add additional (fully qualified) paths to the pipeline in +application.rb+. For example:
+
+<erb>
+config.assets.paths << File.join(Rails.root, 'app', 'assets', 'flash')
+</erb>
-To access assets, you use the same tags that you are generally familiar with:
+h4. Coding Links to Assets
-Sprockets does not add any new methods to require your assets, you still use the familiar +javascript_include_tag+ and +stylesheet_link_tag+.
+Sprockets does not add any new methods to access your assets - you still use the familiar +javascript_include_tag+ and +stylesheet_link_tag+.
<erb>
<%= stylesheet_link_tag "application" %>
@@ -122,49 +130,49 @@ In regular views you can access images in the +assets/images+ directory like thi
<%= image_tag "rails.png" %>
</erb>
-Images can be organized into directories if required, and they can be accessed by specifying the directory's name in the tag:
+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.
+
+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.
+
+Images can also be organized into subdirectories if required, and they can be accessed by specifying the directory's name in the tag:
<erb>
<%= image_tag "icons/rails.png" %>
</erb>
-Providing that assets are enabled within your application (+config.assets.enabled+ in the current environment's file is not set to +false+), this file is served by Sprockets unless a file at +public/assets/rails.png+ exists, in which case that file is served.
-
-Alternatively, a file with an MD5 hash after its name such as +public/assets/rails-af27b6a414e6da00003503148be9b409.png+ is also picked up by Sprockets. How these hashes are generated is covered in the "Production Assets":#production_assets section later on in this guide.
-
-Otherwise, Sprockets looks through the available paths until it finds a file that matches the name and then serves it, first looking in the application's assets directories and then falling back to the various engines of the application.
+h5. CSS and ERB
-If you want to use a "css data URI":http://en.wikipedia.org/wiki/Data_URI_scheme -- a method of embedding the image data directly into the CSS file -- you can use the +asset_data_uri+ helper.
+If you add an +erb+ extension to a CSS asset, making it something such as +application.css.erb+, then you can use the +asset_path+ helper in your CSS rules:
<plain>
-#logo { background: url(<%= asset_data_uri 'logo.png' %>) }
+.class { background-image: url(<%= asset_path 'image.png' %>) }
</plain>
-This inserts a correctly-formatted data URI into the CSS source.
-
-h5. CSS and ERB
+This writes the path to the particular asset being referenced. In this example, it would make sense to have an image in one of the asset load paths, such as +app/assets/images/image.png+, which would be referenced here. If this image is already available in +public/assets+ as a fingerprinted file, then that path is referenced.
-If you add an +erb+ extension to a CSS asset, making it something such as +application.css.erb+, then you can use the +asset_path+ helper in your CSS rules:
+If you want to use a "css data URI":http://en.wikipedia.org/wiki/Data_URI_scheme -- a method of embedding the image data directly into the CSS file -- you can use the +asset_data_uri+ helper.
<plain>
-.class { background-image: <%= asset_path 'image.png' %> }
+#logo { background: url(<%= asset_data_uri 'logo.png' %>) }
</plain>
-This writes the path to the particular asset being referenced. In this example, it would make sense to have an image in one of the asset load paths, such as +app/assets/images/image.png+, which would be referenced here. If this image is already available in +public/assets+ as a fingerprinted file, then that path is referenced.
+This inserts a correctly-formatted data URI into the CSS source.
Note that the closing tag cannot be of the style +-%>+.
-h5. CSS and SCSS
+h5. CSS and Sass
When using the asset pipeline, paths to assets must be re-written and +sass-rails+ provides +_url+ and +_path+ helpers for the following asset classes: image, font, video, audio, javascript, stylesheet.
-* +image_url("rails.png")+ becomes +url(/assets/rails.png)+
-* +image_path("rails.png")+ becomes +"/assets/rails.png"+.
+* +image-url("rails.png")+ becomes +url(/assets/rails.png)+
+* +image-path("rails.png")+ becomes +"/assets/rails.png"+.
The more generic form can also be used but the asset path and class must both be specified:
-* +asset_url("rails.png", "image")+ becomes +url(/assets/rails.png)+
-* +asset_path("rails.png", "image")+ becomes +"/assets/rails.png"+
+* +asset-url("rails.png", image)+ becomes +url(/assets/rails.png)+
+* +asset-path("rails.png", image)+ becomes +"/assets/rails.png"+
h4. Manifest Files and Directives
@@ -222,59 +230,89 @@ Keep in mind that the order of these pre-processors is important. For example, i
h3. In Development
-In the development environment 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.
+In development mode assets are served as separate files in the order they are specified in the manifest file.
-If any of the files in the manifest have changed between requests, the server responds with a new compiled file.
-
-h4. Debugging Assets
-
-You can put +?debug_assets=true+ or +?debug_assets=1+ at the end of a URL or set +config.assets.debug+ and Sprockets expands the lines which load the assets. For example, if you had an +app/assets/javascripts/application.js+ file containing these lines:
+This manifest +application.js+:
<plain>
-//= require "projects"
-//= require "tickets"
+//= require core
+//= require projects
+//= require tickets
</plain>
-By default, this only renders this line when used with +<%= javascript_include_tag "application" %>+ in a view or layout:
+would generate this HTML:
<html>
-<script src='/assets/application.js'></script>
+<script src='/assets/core.js?body=1'></script>
+<script src='/assets/projects.js?body=1'></script>
+<script src='/assets/tickets.js?body=1'></script>
</html>
-When the +debug_assets+ parameter is set, this line is expanded out into three separate lines, separating out the combined file into their parts.
+The +body+ param is required by Sprockets.
+
+h4. Turning Debugging off
+
+You can turn off debug mode by updating +development.rb+ to include:
+
+<erb>
+config.assets.debug = false
+</erb>
+
+When debug mode is off Sprockets will concatenate and run the necessary preprocessors on all files, generating the following HTML:
<html>
<script src='/assets/application.js'></script>
-<script src='/assets/projects.js'></script>
-<script src='/assets/tickets.js'></script>
</html>
-This allows the individual parts of an asset to be rendered and debugged separately.
+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.
+
+If any of the files in the manifest have changed between requests, the server responds with a new compiled file.
+
+You can put +?debug_assets=true+ or +?debug_assets=1+ at the end of a URL to enable debug mode on-demand, and this will render individual tags for each file. This is useful for tracking down exact line numbers when debugging.
+
+Debug can also be set in the Rails helper methods:
+
+<erb>
+<%= stylesheet_link_tag "application", :debug => true %>
+<%= javascript_include_tag "application", :debug => true %>
+</erb>
+
+The +:debug+ option is ignored if the debug mode is off.
+
+You could potentially also enable compression in development mode as a sanity check, and disable it on-demand as required for debugging.
-NOTE. Assets debugging is turned on by default in development and test environments.
h3. In Production
-In the production environment, assets are served slightly differently.
+In the production environment Rails uses the fingerprinting scheme outlined above. By default it is assumed that assets have been precompiled and will be served as static assets by your web server.
-On the first request the assets are compiled and cached as described above, however the manifest names are altered to include an MD5 hash. Files names typically look like these:
+During the precompilation phase an MD5 is generated from the contents of the compiled files, and inserted into the filenames as they are written to disc. These fingerprinted names are used by the Rails helpers in place of the manifest name.
-<plain>
-/assets/application-908e25f4bf641868d8683022a5b62f54.js
-/assets/application-4dd5b109ee3439da54f5bdfd78a80473.css
-</plain>
+For example this:
+
+<erb>
+<%= javascript_include_tag "application" %>
+<%= stylesheet_link_tag "application" %>
+</erb>
-The MD5 is generated from the contents of the compiled files, and is included in the HTTP +Content-MD5+ header.
+generates something like this:
-Sprockets also sets the +Cache-Control+ HTTP header to +max-age=31536000+. This signals all caches between your server and the client browser that this content (the file served) can be cached for 1 year. The effect of this is to reduce the number of requests for this asset from your server; the asset has a good chance of being in the local browser cache or some intermediate cache.
+<html>
+<script src="/assets/application-908e25f4bf641868d8683022a5b62f54.js" type="text/javascript"></script>
+<link href="/assets/application-4dd5b109ee3439da54f5bdfd78a80473.css" media="screen" rel="stylesheet" type="text/css" />
+</html>
+
+The fingerprinting behavior is controlled by the setting of +config.assets.digest+ setting in Rails (which is +true+ for production, +false+ for everything else).
-This behavior is controlled by the setting of +config.assets.digest+ setting in Rails (which is +true+ for production, +false+ for everything else).
+NOTE: Under normal circumstances the default option should not be changed. If there are no digests in the filenames, and far-future headers are set, remote clients will never know to refetch the files when their content changes.
h4. Precompiling Assets
-Even though assets are served by Rack::Cache with far-future headers, in high traffic sites this may not be fast enough.
+Rails comes bundled with a rake task to compile the asset manifests and other files in the pipeline to the disk.
-Rails comes bundled with a rake task to compile the manifests to files on disc. These are located in the +public/assets+ directory where they are served by your web server instead of the Rails application.
+Compiled assets are written to the location specified in +config.assets.prefix+. The default setting will use the +public/assets+ directory.
+
+You must use this task either during deployment or locally if you do not have write access to your production filesystem.
The rake task is:
@@ -288,7 +326,7 @@ Capistrano (v2.8.0+) has a recipe to handle this in deployment. Add the followin
load 'deploy/assets'
</erb>
-This links the folder specified in +config.assets.prefix+ to +shared/assets+. If you already use this folder you'll need to write your own deployment task.
+This links the folder specified in +config.assets.prefix+ to +shared/assets+. If you already use this shared folder you'll need to write your own deployment task.
It is important that this folder is shared between deployments so that remotely cached pages that reference the old compiled assets still work for the life of the cached page.
@@ -298,13 +336,13 @@ The default matcher for compiling files includes +application.js+, +application.
[ /\w+\.(?!js|css).+/, /application.(css|js)$/ ]
</ruby>
-If you have other manifests or individual stylesheets and JavaScript files to include, you can append them to the +precompile+ array:
+If you have other manifests or individual stylesheets and JavaScript files to include, you can add them to the +precompile+ array:
<erb>
config.assets.precompile += ['admin.js', 'admin.css', 'swfObject.js']
</erb>
-The rake task also generates a +manifest.yml+ that contains a list with all your assets and their fingerprints, using this manifest file the assets helpers avoid hitting to Sprockets to recalculate MD5 hashes for files. Manifest file typically look like this:
+The rake task also generates a +manifest.yml+ that contains a list with all your assets and their respective fingerprints. This is used by the Rails helper methods and avoids handing the mapping requests back to Sprockets. Manifest file typically look like this:
<plain>
---
@@ -315,8 +353,17 @@ application.js: application-3fdab497b8fb70d20cfc5495239dfc29.js
application.css: application-8af74128f904600e41a6e39241464e03.css
</plain>
-The manifest file is generated by default in same folder of your precompiled assets, you can change the location of the file setting the +config.assets.manifest+ option with the full path of the folder where you want save it.
+The default location for the manifest is the root of the location specified in +config.assets.prefix+ ('/assets' by default).
+
+This can be changed with the +config.assets.manifest+ option. A fully specified path is required:
+
+<erb>
+config.assets.manifest = '/path/to/some/other/location'
+</erb>
+
+NOTE: If there are missing precompiled files in production you will get an <tt>AssetNoPrecompiledError</tt> exception indicating the name of the missing file(s).
+h5. Server Configuration
Precompiled assets exist on the filesystem and are served directly by your webserver. They do not have far-future headers by default, so to get the benefit of fingerprinting you'll have to update your server configuration to add them.
@@ -338,7 +385,7 @@ For Apache:
TODO: nginx instructions
-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 disc. 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:
+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:
For Apache:
@@ -347,7 +394,7 @@ For Apache:
# 2 lines to serve pre-gzipped version
RewriteCond %{REQUEST_FILENAME}.gz -s
RewriteRule ^(.+) $1.gz [L]
-
+
# without it, Content-Type will be "application/x-gzip"
<FilesMatch .*\.css.gz>
ForceType text/css
@@ -370,14 +417,27 @@ location ~ ^/(assets)/ {
}
</plain>
-By default Rails assumes that you have your files precompiled in the production environment, if you want use live compiling (compile your assets during runtime) in production you must set the +config.assets.compile+ to true. You can use this option to fallback to Sprockets when you are using precompiled assets but there are any missing precompiled files. If +config.assets.compile+ option is set to false and there are missing precompiled files you will get an "AssetNoPrecompiledError" indicating the name of the missing file.
+h4. Live Compilation
-h3. Customizing the Pipeline
+In some circumstances you may wish to use live compilation. In this mode all requests for assets in the pipeline are handled by Sprockets directly.
+
+To enable this option set:
+
+<erb>
+config.assets.compile = true
+</erb>
+
+On the first request the assets are compiled and cached as outlined in development above, and the manifest names used in the helpers are altered to include the MD5 hash.
+
+Sprockets also sets the +Cache-Control+ HTTP header to +max-age=31536000+. This signals all caches between your server and the client browser that this content (the file served) can be cached for 1 year. The effect of this is to reduce the number of requests for this asset from your server; the asset has a good chance of being in the local browser cache or some intermediate cache.
+This mode uses more memory and is lower performance than the default. It is not recommended.
+
+h3. Customizing the Pipeline
h4. CSS Compression
-There is currently one option for compressing CSS - YUI. This Gem extends the CSS syntax and offers minification.
+There is currently one option for compressing CSS, YUI. The "YUI CSS compressor":http://developer.yahoo.com/yui/compressor/css.html provides minification.
The following line enables YUI compression, and requires the +yui-compressor+ gem.
@@ -385,9 +445,9 @@ The following line enables YUI compression, and requires the +yui-compressor+ ge
config.assets.css_compressor = :yui
</erb>
-The +config.assets.compress+ must be set to +true+ to enable CSS compression
+The +config.assets.compress+ must be set to +true+ to enable CSS compression.
-h4. JavaScript
+h4. JavaScript Compression
Possible options for JavaScript compression are +:closure+, +:uglifier+ and +:yui+. These require the use of the +closure-compiler+, +uglifier+ or +yui-compressor+ gems respectively.
@@ -401,6 +461,8 @@ config.assets.js_compressor = :uglifier
The +config.assets.compress+ must be set to +true+ to enable JavaScript compression
+NOTE: You will need a "ExecJS":https://github.com/sstephenson/execjs#readme -- supported runtime in order to use +uglifier+. If you are using Mac OS X or Windows you have installed a JavaScript runtime in your operating system. Check "ExecJS":https://github.com/sstephenson/execjs#readme documentation to know all supported JavaScript runtimes.
+
h4. Using Your Own Compressor
The compressor config settings for CSS and JavaScript also take any Object. This object must have a +compress+ method that takes a string as the sole argument and it must return a string.
@@ -447,7 +509,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 dev and production. The only difference is file names are fingerprinted and get far-future headers in production.
+Sprockets uses the default rails cache store to cache assets in development and production.
TODO: Add more about changing the default store.
@@ -463,7 +525,7 @@ TODO: Registering gems on "Tilt":https://github.com/rtomayko/tilt enabling Sproc
h3. Upgrading from Old Versions of Rails
-There are two issues when upgrading. The first is moving the files to the new locations. See the section above for guidance on the correct locations for different file types.
+There are two issues when upgrading. The first is moving the files to the new locations. See the section above for guidance on the correct locations for different file types.
The second is updating the various environment files with the correct default options. The following changes reflect the defaults in version 3.1.0.
@@ -475,6 +537,9 @@ config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
+
+# Change the path that assets are served from
+# config.assets.prefix = "/assets"
</erb>
In +development.rb+:
@@ -493,10 +558,14 @@ And in +production.rb+:
# Compress JavaScripts and CSS
config.assets.compress = true
+# Choose the compressors to use
+# config.assets.js_compressor = :uglifier
+# config.assets.css_compressor = :yui
+
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false
-# Generate digests for assets URLs
+# Generate digests for assets URLs.
config.assets.digest = true
# Defaults to Rails.root.join("public/assets")
@@ -506,4 +575,16 @@ config.assets.digest = true
# config.assets.precompile += %w( search.js )
</erb>
-There are no changes to +test.rb+.
+There are no changes to +test.rb+. The defaults in the test environment are: +config.assets.compile+ is true and +config.assets.compress+, +config.assets.debug+ and +config.assets.digest+ are false.
+
+The following should also be added to +Gemfile+:
+
+<plain>
+# 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
+</plain>
diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile
index 798f8e405e..ae84bb5b92 100644
--- a/railties/guides/source/configuring.textile
+++ b/railties/guides/source/configuring.textile
@@ -124,7 +124,7 @@ Rails 3.1, by default, is set up to use the +sprockets+ gem to manage assets wit
* +config.assets.compress+ a flag that enables the compression of compiled assets. It is explicitly set to true in +config/production.rb+.
-* +config.assets.css_compressor+ defines the CSS compressor to use. Only supported value at the moment is +:yui+, which uses the +yui-compressor+ gem.
+* +config.assets.css_compressor+ defines the CSS compressor to use. It is set by default by +sass-rails+. The unique alternative value at the moment is +:yui+, which uses the +yui-compressor+ gem.
* +config.assets.js_compressor+ defines the JavaScript compressor to use. Possible values are +:closure+, +:uglifier+ and +:yui+ which require the use of the +closure-compiler+, +uglifier+ or +yui-compressor+ gems respectively.
@@ -134,15 +134,15 @@ Rails 3.1, by default, is set up to use the +sprockets+ gem to manage assets wit
* +config.assets.prefix+ defines the prefix where assets are served from. Defaults to +/assets+.
-* +config.assets.digest+ enables the use of MD5 fingerprints in asset names. Set to +true+ by default in +production.rb+
+* +config.assets.digest+ enables the use of MD5 fingerprints in asset names. Set to +true+ by default in +production.rb+.
-* +config.assets.debug+ disables the concatenation and compression of assets. Set to +false+ by default in +development.rb+
+* +config.assets.debug+ disables the concatenation and compression of assets. Set to +false+ by default in +development.rb+.
-* +config.assets.manifest+ defines the full path to be used for the asset precompiler's manifest file. Defaults to using +config.assets.prefix+
+* +config.assets.manifest+ defines the full path to be used for the asset precompiler's manifest file. Defaults to using +config.assets.prefix+.
* +config.assets.cache_store+ defines the cache store that Sprockets will use. The default is the Rails file store.
-* +config.assets.version+ is an option string that is used in MD5 hash generation. This can be changed to force all files to be recompiled.
+* +config.assets.version+ is an option string that is used in MD5 hash generation. This can be changed to force all files to be recompiled.
* +config.assets.compile+ is a boolean that can be used to turn on live Sprockets compilation in production.
diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile
index 2fa1d6e21d..3f990ef54b 100644
--- a/railties/guides/source/generators.textile
+++ b/railties/guides/source/generators.textile
@@ -449,6 +449,15 @@ The above code will put the following line into +Gemfile+:
gem "devise", :git => "git://github.com/plataformatec/devise", :branch => "master"
</ruby>
+h4. +gem_group+
+
+Wraps gem entries inside a group:
+
+<ruby>
+gem_group :development, :test do
+ gem "rspec-rails"
+end
+</ruby>
h4. +add_source+
diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile
index 256df0eded..6e9613cdae 100644
--- a/railties/guides/source/getting_started.textile
+++ b/railties/guides/source/getting_started.textile
@@ -592,7 +592,7 @@ class CreatePosts < ActiveRecord::Migration
end
</ruby>
-The above migration creates a method name +change+ which will be called when you
+The above migration creates a method named +change+ which will be called when you
run this migration. The action defined in that method is also reversible, which
means Rails knows how to reverse the change made by this migration, in case you
want to reverse it at later date. By default, when you run this migration it
diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile
index 310a70ca9b..f49c2000ee 100644
--- a/railties/guides/source/layouts_and_rendering.textile
+++ b/railties/guides/source/layouts_and_rendering.textile
@@ -515,7 +515,7 @@ h4. Using +redirect_to+
Another way to handle returning responses to an HTTP request is with +redirect_to+. As you've seen, +render+ tells Rails which view (or other asset) to use in constructing a response. The +redirect_to+ method does something completely different: it tells the browser to send a new request for a different URL. For example, you could redirect from wherever you are in your code to the index of photos in your application with this call:
<ruby>
-redirect_to photos_path
+redirect_to photos_url
</ruby>
You can use +redirect_to+ with any arguments that you could use with +link_to+ or +url_for+. In addition, there's a special redirect that sends the user back to the page they just came from:
@@ -1093,6 +1093,13 @@ In Rails 3.0, there is also a shorthand for this. Assuming +@products+ is a coll
Rails determines the name of the partial to use by looking at the model name in the collection. In fact, you can even create a heterogeneous collection and render it this way, and Rails will choose the proper partial for each member of the collection:
+In the event that the collection is empty, +render+ will return nil, so it should be fairly simple to provide alternative content.
+
+<erb>
+<h1>Products</h1>
+<%= render(@products) || 'There are no products available.' %>
+</erb>
+
* +index.html.erb+
<erb>
diff --git a/railties/guides/source/performance_testing.textile b/railties/guides/source/performance_testing.textile
index 75f81cf13d..5947735deb 100644
--- a/railties/guides/source/performance_testing.textile
+++ b/railties/guides/source/performance_testing.textile
@@ -207,7 +207,7 @@ GC Time measures the amount of time spent in GC for the performance test case.
h5. Metric Availability
-h6. Benchmarking
+h6(#benchmarking_1). Benchmarking
|_.Interpreter|_.Wall Time|_.Process Time|_.CPU Time|_.User Time|_.Memory|_.Objects|_.GC Runs|_.GC Time|
|_.MRI | yes | yes | yes | no | yes | yes | yes | yes |
@@ -215,7 +215,7 @@ h6. Benchmarking
|_.Rubinius | yes | no | no | no | yes | yes | yes | yes |
|_.JRuby | yes | no | no | yes | yes | yes | yes | yes |
-h6. Profiling
+h6(#profiling_1). Profiling
|_.Interpreter|_.Wall Time|_.Process Time|_.CPU Time|_.User Time|_.Memory|_.Objects|_.GC Runs|_.GC Time|
|_.MRI | yes | yes | no | no | yes | yes | yes | yes |
diff --git a/railties/guides/source/rails_application_templates.textile b/railties/guides/source/rails_application_templates.textile
index 566f8a0bdd..c3c8af4d3a 100644
--- a/railties/guides/source/rails_application_templates.textile
+++ b/railties/guides/source/rails_application_templates.textile
@@ -60,6 +60,18 @@ Please note that this will NOT install the gems for you and you will have to run
bundle install
</ruby>
+h4. gem_group(*names, &block)
+
+Wraps gem entries inside a group.
+
+For example, if you want to load +rspec-rails+ only in +development+ and +test+ group:
+
+<ruby>
+gem_group :development, :test do
+ gem "rspec-rails"
+end
+</ruby>
+
h4. add_source(source, options = {})
Adds the given source to the generated application's +Gemfile+.
diff --git a/railties/guides/source/testing.textile b/railties/guides/source/testing.textile
index cc55d1f756..caa0d91a83 100644
--- a/railties/guides/source/testing.textile
+++ b/railties/guides/source/testing.textile
@@ -931,7 +931,7 @@ class UserControllerTest < ActionController::TestCase
assert_equal "You have been invited by me@example.com", invite_email.subject
assert_equal 'friend@example.com', invite_email.to[0]
- assert_match /Hi friend@example.com/, invite_email.body
+ assert_match(/Hi friend@example.com/, invite_email.body)
end
end
</ruby>
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index b8541c236e..575f4bb106 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -68,7 +68,32 @@ module Rails
end
in_root do
- append_file "Gemfile", "gem #{parts.join(", ")}\n", :verbose => false
+ str = "gem #{parts.join(", ")}\n"
+ str = " " + str if @in_group
+ append_file "Gemfile", str, :verbose => false
+ end
+ end
+
+ # Wraps gem entries inside a group.
+ #
+ # ==== Example
+ #
+ # gem_group :development, :test do
+ # gem "rspec-rails"
+ # end
+ #
+ def gem_group(*names, &block)
+ name = names.map(&:inspect).join(", ")
+ log :gemfile, "group #{name}"
+
+ in_root do
+ append_file "Gemfile", "\ngroup #{name} do\n", :force => true
+
+ @in_group = true
+ instance_eval &block
+ @in_group = false
+
+ append_file "Gemfile", "end\n", :force => true
end
end
@@ -97,7 +122,7 @@ module Rails
in_root do
if options[:env].nil?
- inject_into_file 'config/application.rb', "\n #{data}", :after => sentinel, :verbose => false
+ inject_into_file 'config/application.rb', "\n #{data}", :after => sentinel, :verbose => false
else
Array.wrap(options[:env]).each do |env|
inject_into_file "config/environments/#{env}.rb", "\n #{data}", :after => env_file_sentinel, :verbose => false
@@ -119,8 +144,8 @@ module Rails
if commands.is_a?(Symbol)
run "git #{commands}"
else
- commands.each do |command, options|
- run "git #{command} #{options}"
+ commands.each do |cmd, options|
+ run "git #{cmd} #{options}"
end
end
end
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index c83e7ddf80..910cd16950 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -10,6 +10,9 @@ source 'http://rubygems.org'
<%= assets_gemfile_entry %>
<%= javascript_gemfile_entry %>
+# To use ActiveModel has_secure_password
+# gem 'bcrypt-ruby', '~> 3.0.0'
+
# Use unicorn as the web server
# gem 'unicorn'
diff --git a/railties/lib/rails/generators/rails/app/templates/public/500.html b/railties/lib/rails/generators/rails/app/templates/public/500.html
index b80307fc16..f3648a0dbc 100644
--- a/railties/lib/rails/generators/rails/app/templates/public/500.html
+++ b/railties/lib/rails/generators/rails/app/templates/public/500.html
@@ -20,7 +20,6 @@
<!-- 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/lib/rails/generators/test_case.rb b/railties/lib/rails/generators/test_case.rb
index ee85b70bb5..7319fb79f6 100644
--- a/railties/lib/rails/generators/test_case.rb
+++ b/railties/lib/rails/generators/test_case.rb
@@ -81,7 +81,7 @@ module Rails
#
# assert_file "app/controller/products_controller.rb" do |controller|
# assert_instance_method :index, content do |index|
- # assert_match /Product\.all/, index
+ # assert_match(/Product\.all/, index)
# end
# end
#
@@ -148,7 +148,7 @@ module Rails
#
# assert_migration "db/migrate/create_products.rb" do |migration|
# assert_class_method :up, migration do |up|
- # assert_match /create_table/, up
+ # assert_match(/create_table/, up)
# end
# end
#
@@ -161,7 +161,7 @@ module Rails
#
# assert_file "app/controller/products_controller.rb" do |controller|
# assert_instance_method :index, content do |index|
- # assert_match /Product\.all/, index
+ # assert_match(/Product\.all/, index)
# end
# end
#
diff --git a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml
index d4138ca2f5..5c8780aa64 100644
--- a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml
+++ b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml
@@ -1,4 +1,4 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
<% unless attributes.empty? -%>
one:
diff --git a/railties/test/application/asset_debugging_test.rb b/railties/test/application/asset_debugging_test.rb
index 707abe7191..1b99af22a4 100644
--- a/railties/test/application/asset_debugging_test.rb
+++ b/railties/test/application/asset_debugging_test.rb
@@ -45,8 +45,8 @@ module ApplicationTests
# the debug_assets params isn't used if compile is off
get '/posts?debug_assets=true'
- assert_match /<script src="\/assets\/application-([0-z]+)\.js" type="text\/javascript"><\/script>/, last_response.body
- assert_no_match /<script src="\/assets\/xmlhr-([0-z]+)\.js" type="text\/javascript"><\/script>/, last_response.body
+ assert_match(/<script src="\/assets\/application-([0-z]+)\.js" type="text\/javascript"><\/script>/, last_response.body)
+ assert_no_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js" type="text\/javascript"><\/script>/, last_response.body)
end
test "assets aren't concatened when compile is true is on and debug_assets params is true" do
@@ -58,8 +58,8 @@ module ApplicationTests
class ::PostsController < ActionController::Base ; end
get '/posts?debug_assets=true'
- assert_match /<script src="\/assets\/application-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body
- assert_match /<script src="\/assets\/xmlhr-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body
+ assert_match(/<script src="\/assets\/application-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body)
+ assert_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body)
end
end
end
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
index a412b7d99b..3c7d178d37 100644
--- a/railties/test/application/assets_test.rb
+++ b/railties/test/application/assets_test.rb
@@ -77,8 +77,8 @@ module ApplicationTests
manifest = "#{app_path}/public/assets/manifest.yml"
assets = YAML.load_file(manifest)
- assert_match /application-([0-z]+)\.js/, assets["application.js"]
- assert_match /application-([0-z]+)\.css/, assets["application.css"]
+ assert_match(/application-([0-z]+)\.js/, assets["application.js"])
+ assert_match(/application-([0-z]+)\.css/, assets["application.css"])
end
test "precompile creates a manifest file in a custom path with all the assets listed" do
@@ -96,8 +96,8 @@ module ApplicationTests
manifest = "#{app_path}/shared/manifest.yml"
assets = YAML.load_file(manifest)
- assert_match /application-([0-z]+)\.js/, assets["application.js"]
- assert_match /application-([0-z]+)\.css/, assets["application.css"]
+ assert_match(/application-([0-z]+)\.js/, assets["application.js"])
+ assert_match(/application-([0-z]+)\.css/, assets["application.css"])
end
@@ -113,7 +113,7 @@ module ApplicationTests
manifest = "#{app_path}/public/x/manifest.yml"
assets = YAML.load_file(manifest)
- assert_match /application-([0-z]+)\.js/, assets["application.js"]
+ assert_match(/application-([0-z]+)\.js/, assets["application.js"])
end
test "precompile does not append asset digests when config.assets.digest is false" do
@@ -176,8 +176,34 @@ module ApplicationTests
class ::PostsController < ActionController::Base ; end
get '/posts'
- assert_match /AssetNotPrecompiledError/, last_response.body
- assert_match /app.js isn't precompiled/, last_response.body
+ assert_match(/AssetNotPrecompiledError/, last_response.body)
+ assert_match(/app.js isn't precompiled/, last_response.body)
+ end
+
+ test "assets raise AssetNotPrecompiledError when manifest file is present and requested file isn't precompiled if digest is disabled" do
+ app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'app' %>"
+ app_file "config/initializers/compile.rb", "Rails.application.config.assets.compile = false"
+
+ app_file "config/routes.rb", <<-RUBY
+ AppTemplate::Application.routes.draw do
+ match '/posts', :to => "posts#index"
+ end
+ RUBY
+
+ ENV["RAILS_ENV"] = "development"
+ capture(:stdout) do
+ Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
+ end
+
+ # Create file after of precompile
+ app_file "app/assets/javascripts/app.js", "alert();"
+
+ require "#{app_path}/config/environment"
+ class ::PostsController < ActionController::Base ; end
+
+ get '/posts'
+ assert_match(/AssetNotPrecompiledError/, last_response.body)
+ assert_match(/app.js isn't precompiled/, last_response.body)
end
test "precompile appends the md5 hash to files referenced with asset_path and run in the provided RAILS_ENV" do
@@ -189,7 +215,7 @@ module ApplicationTests
Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_ENV=test` }
# end
file = Dir["#{app_path}/public/assets/application-*.css"].first
- assert_match /\/assets\/rails-([0-z]+)\.png/, File.read(file)
+ assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file))
end
test "precompile appends the md5 hash to files referenced with asset_path and run in production as default even using RAILS_GROUPS=assets" do
@@ -201,7 +227,7 @@ module ApplicationTests
Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_GROUPS=assets` }
end
file = Dir["#{app_path}/public/assets/application-*.css"].first
- assert_match /\/assets\/rails-([0-z]+)\.png/, File.read(file)
+ assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file))
end
test "assets are cleaned up properly" do
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index cc65a674c9..0e03c3dc2d 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -79,9 +79,9 @@ module ApplicationTests
silence_stderr do
output = Dir.chdir(app_path){ `rake test` }
- assert_match /Errors running test:units! #<ActiveRecord::AdapterNotSpecified/, output
- assert_match /Errors running test:functionals! #<RuntimeError/, output
- assert_match /Errors running test:integration! #<RuntimeError/, output
+ assert_match(/Errors running test:units! #<ActiveRecord::AdapterNotSpecified/, output)
+ assert_match(/Errors running test:functionals! #<RuntimeError/, output)
+ assert_match(/Errors running test:integration! #<RuntimeError/, output)
end
end
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index e4a8000425..94e9abb3cc 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -102,11 +102,25 @@ class ActionsTest < Rails::Generators::TestCase
assert_file 'Gemfile', /gem "rspec-rails"$/
end
+ def test_gem_group_should_wrap_gems_in_a_group
+ run_generator
+
+ action :gem_group, :development, :test do
+ gem 'rspec-rails'
+ end
+
+ action :gem_group, :test do
+ gem 'fakeweb'
+ end
+
+ assert_file 'Gemfile', /\ngroup :development, :test do\n gem "rspec-rails"\nend\n\ngroup :test do\n gem "fakeweb"\nend/
+ end
+
def test_environment_should_include_data_in_environment_initializer_block
run_generator
autoload_paths = 'config.autoload_paths += %w["#{Rails.root}/app/extras"]'
action :environment, autoload_paths
- assert_file 'config/application.rb', /#{Regexp.escape(autoload_paths)}/
+ assert_file 'config/application.rb', / class Application < Rails::Application\n #{Regexp.escape(autoload_paths)}/
end
def test_environment_should_include_data_in_environment_initializer_block_with_env_option
diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb
index b49945f153..9183945619 100644
--- a/railties/test/generators/plugin_new_generator_test.rb
+++ b/railties/test/generators/plugin_new_generator_test.rb
@@ -197,8 +197,8 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase
assert_file "app/helpers/bukkits/application_helper.rb", /module Bukkits\n module ApplicationHelper/
assert_file "app/views/layouts/bukkits/application.html.erb" do |contents|
assert_match "<title>Bukkits</title>", contents
- assert_match /stylesheet_link_tag\s+['"]bukkits\/application['"]/, contents
- assert_match /javascript_include_tag\s+['"]bukkits\/application['"]/, contents
+ assert_match(/stylesheet_link_tag\s+['"]bukkits\/application['"]/, contents)
+ assert_match(/javascript_include_tag\s+['"]bukkits\/application['"]/, contents)
end
end
@@ -241,7 +241,7 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase
run_generator [destination_root, "--skip-test-unit"]
assert_no_file "test"
assert_file "bukkits.gemspec" do |contents|
- assert_no_match /s.test_files = Dir\["test\/\*\*\/\*"\]/, contents
+ assert_no_match(/s.test_files = Dir\["test\/\*\*\/\*"\]/, contents)
end
end
diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb
index d3074afd91..1534f0d828 100644
--- a/railties/test/generators/shared_generator_tests.rb
+++ b/railties/test/generators/shared_generator_tests.rb
@@ -191,11 +191,11 @@ module SharedCustomGeneratorTests
end
def test_builder_option_with_http
- path = "http://gist.github.com/103208.txt"
+ url = "http://gist.github.com/103208.txt"
template = "class #{builder_class}; end"
template.instance_eval "def read; self; end" # Make the string respond to read
- generator([destination_root], :builder => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
+ generator([destination_root], :builder => url).expects(:open).with(url, 'Accept' => 'application/x-thor-template').returns(template)
quietly { generator.invoke_all }
default_files.each{ |path| assert_no_file(path) }
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index 0ff1e0f180..06a60cd858 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -400,7 +400,7 @@ module RailtiesTest
boot_rails
get("/bukkits/posts/new")
- assert_match /name="post\[title\]"/, last_response.body
+ assert_match(/name="post\[title\]"/, last_response.body)
end
test "isolated engine should set correct route module prefix for nested namespace" do
diff --git a/railties/test/railties/shared_tests.rb b/railties/test/railties/shared_tests.rb
index 9a64b7c64e..21fde49ff7 100644
--- a/railties/test/railties/shared_tests.rb
+++ b/railties/test/railties/shared_tests.rb
@@ -61,21 +61,21 @@ module RailtiesTest
assert File.exists?("#{app_path}/db/migrate/2_create_users.rb")
assert File.exists?("#{app_path}/db/migrate/3_add_last_name_to_users.rb")
- assert_match /Copied migration 2_create_users.rb from bukkits/, output
- assert_match /Copied migration 3_add_last_name_to_users.rb from bukkits/, output
- assert_match /NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/, output
+ assert_match(/Copied migration 2_create_users.rb from bukkits/, output)
+ assert_match(/Copied migration 3_add_last_name_to_users.rb from bukkits/, output)
+ assert_match(/NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/, output)
assert_equal 3, Dir["#{app_path}/db/migrate/*.rb"].length
output = `bundle exec rake railties:install:migrations`.split("\n")
assert File.exists?("#{app_path}/db/migrate/4_create_yaffles.rb")
- assert_no_match /2_create_users/, output.join("\n")
+ assert_no_match(/2_create_users/, output.join("\n"))
yaffle_migration_order = output.index(output.detect{|o| /Copied migration 4_create_yaffles.rb from acts_as_yaffle/ =~ o })
bukkits_migration_order = output.index(output.detect{|o| /NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/ =~ o })
assert_not_nil yaffle_migration_order, "Expected migration to be copied"
assert_not_nil bukkits_migration_order, "Expected migration to be skipped"
- assert_equal (railties.index('acts_as_yaffle') > railties.index('bukkits')) , (yaffle_migration_order > bukkits_migration_order)
+ assert_equal(railties.index('acts_as_yaffle') > railties.index('bukkits'), yaffle_migration_order > bukkits_migration_order)
migrations_count = Dir["#{app_path}/db/migrate/*.rb"].length
output = `bundle exec rake railties:install:migrations`