aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb6
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb7
-rw-r--r--actionpack/lib/action_view/helpers/cache_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb2
-rw-r--r--actionpack/test/controller/caching_test.rb49
-rw-r--r--actionpack/test/controller/mime_responds_test.rb2
-rw-r--r--actionpack/test/controller/url_rewriter_test.rb4
-rw-r--r--actionpack/test/dispatch/routing_test.rb48
-rw-r--r--actionpack/test/fixtures/functional_caching/fragment_cached.html.erb1
-rw-r--r--actionpack/test/template/number_helper_test.rb1
-rw-r--r--activemodel/lib/active_model/serialization.rb2
-rw-r--r--activemodel/test/cases/serialization_test.rb8
-rw-r--r--activerecord/CHANGELOG11
-rw-r--r--activerecord/lib/active_record.rb1
-rw-r--r--activerecord/lib/active_record/base.rb2
-rw-r--r--activerecord/lib/active_record/errors.rb10
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb4
-rw-r--r--activerecord/lib/active_record/store.rb49
-rw-r--r--activerecord/test/cases/locking_test.rb19
-rw-r--r--activerecord/test/cases/store_test.rb29
-rw-r--r--activerecord/test/models/admin/user.rb3
-rw-r--r--activerecord/test/schema/schema.rb1
-rw-r--r--activeresource/CHANGELOG13
-rw-r--r--activeresource/lib/active_resource/base.rb4
-rw-r--r--activeresource/lib/active_resource/connection.rb2
-rw-r--r--activeresource/test/cases/connection_test.rb19
-rw-r--r--railties/guides/source/engines.textile2
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb5
-rw-r--r--railties/test/generators/app_generator_test.rb10
32 files changed, 302 insertions, 26 deletions
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index f10287afb4..00bd1706e7 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -42,8 +42,8 @@ module ActionController #:nodoc:
def respond_to(*mimes)
options = mimes.extract_options!
- only_actions = Array(options.delete(:only))
- except_actions = Array(options.delete(:except))
+ only_actions = Array(options.delete(:only)).map(&:to_s)
+ except_actions = Array(options.delete(:except)).map(&:to_s)
new = mimes_for_respond_to.dup
mimes.each do |mime|
@@ -245,7 +245,7 @@ module ActionController #:nodoc:
# current action.
#
def collect_mimes_from_class_level #:nodoc:
- action = action_name.to_sym
+ action = action_name.to_s
self.class.mimes_for_respond_to.keys.select do |mime|
config = self.class.mimes_for_respond_to[mime]
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index 170c68f3e0..c8ddd07bfa 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -45,7 +45,7 @@ module ActionDispatch
rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path)
rewritten_url << "?#{params.to_query}" unless params.empty?
- rewritten_url << "##{Journey::Router::Utils.escape_uri(options[:anchor].to_param.to_s)}" if options[:anchor]
+ rewritten_url << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor]
rewritten_url
end
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index 2adbce031b..e59404ef68 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -70,6 +70,10 @@ module ActionDispatch
end
end
+ # Implementation detail: please do not change the signature of the
+ # FlashHash class. Doing that will likely affect all Rails apps in
+ # production as the FlashHash currently stored in their sessions will
+ # become invalid.
class FlashHash
include Enumerable
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index cd59b13c42..ef31d1e004 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -49,7 +49,7 @@ module ActionDispatch
class Mapping #:nodoc:
IGNORE_OPTIONS = [:to, :as, :via, :on, :constraints, :defaults, :only, :except, :anchor, :shallow, :shallow_path, :shallow_prefix]
ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
- SHORTHAND_REGEX = %r{^/[\w/]+$}
+ SHORTHAND_REGEX = %r{/[\w/]+$}
WILDCARD_PATH = %r{\*([^/\)]+)\)?$}
def initialize(set, scope, path, options)
@@ -70,7 +70,7 @@ module ActionDispatch
if using_match_shorthand?(path_without_format, @options)
to_shorthand = @options[:to].blank?
- @options[:to] ||= path_without_format[1..-1].sub(%r{/([^/]*)$}, '#\1')
+ @options[:to] ||= path_without_format.gsub(/\(.*\)/, "")[1..-1].sub(%r{/([^/]*)$}, '#\1')
end
@options.merge!(default_controller_and_action(to_shorthand))
@@ -90,7 +90,7 @@ module ActionDispatch
# match "account/overview"
def using_match_shorthand?(path, options)
- path && options.except(:via, :anchor, :to, :as).empty? && path =~ SHORTHAND_REGEX
+ path && (options[:to] || options[:action]).nil? && path =~ SHORTHAND_REGEX
end
def normalize_path(path)
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index bc956ef216..e7bc431783 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -394,10 +394,9 @@ module ActionDispatch
if name == :controller
value
elsif value.is_a?(Array)
- value.map { |v| Journey::Router::Utils.escape_uri(v.to_param) }.join('/')
- else
- return nil unless param = value.to_param
- param.split('/').map { |v| Journey::Router::Utils.escape_uri(v) }.join("/")
+ value.map { |v| v.to_param }.join('/')
+ elsif param = value.to_param
+ param
end
end
diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb
index f81ce3e31c..850dd5f448 100644
--- a/actionpack/lib/action_view/helpers/cache_helper.rb
+++ b/actionpack/lib/action_view/helpers/cache_helper.rb
@@ -54,7 +54,7 @@ module ActionView
output_safe = output_buffer.html_safe?
fragment = output_buffer.slice!(pos..-1)
if output_safe
- self.output_buffer = output_buffer.html_safe
+ self.output_buffer = output_buffer.class.new(output_buffer)
end
controller.write_fragment(name, fragment, options)
end
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index ec6c2c8db3..7031694af4 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -69,7 +69,7 @@ module ActionView
number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3")
else
number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
- number.slice!(0, 1) if number.starts_with?('-')
+ number.slice!(0, 1) if number.starts_with?(delimiter) && !delimiter.blank?
end
str = []
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index f3b180283f..618e7b77b2 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -745,6 +745,7 @@ class FunctionalFragmentCachingTest < ActionController::TestCase
expected_body = <<-CACHED
Hello
This bit's fragment cached
+Ciao
CACHED
assert_equal expected_body, @response.body
@@ -786,3 +787,51 @@ CACHED
assert_equal " <p>Builder</p>\n", @store.read('views/test.host/functional_caching/formatted_fragment_cached')
end
end
+
+class CacheHelperOutputBufferTest < ActionController::TestCase
+
+ class MockController
+ def read_fragment(name, options)
+ return false
+ end
+
+ def write_fragment(name, fragment, options)
+ fragment
+ end
+ end
+
+ def setup
+ super
+ end
+
+ def test_output_buffer
+ output_buffer = ActionView::OutputBuffer.new
+ controller = MockController.new
+ cache_helper = Object.new
+ cache_helper.extend(ActionView::Helpers::CacheHelper)
+ cache_helper.expects(:controller).returns(controller).at_least(0)
+ cache_helper.expects(:output_buffer).returns(output_buffer).at_least(0)
+ # if the output_buffer is changed, the new one should be html_safe and of the same type
+ cache_helper.expects(:output_buffer=).with(responds_with(:html_safe?, true)).with(instance_of(output_buffer.class)).at_least(0)
+
+ assert_nothing_raised do
+ cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil }
+ end
+ end
+
+ def test_safe_buffer
+ output_buffer = ActiveSupport::SafeBuffer.new
+ controller = MockController.new
+ cache_helper = Object.new
+ cache_helper.extend(ActionView::Helpers::CacheHelper)
+ cache_helper.expects(:controller).returns(controller).at_least(0)
+ cache_helper.expects(:output_buffer).returns(output_buffer).at_least(0)
+ # if the output_buffer is changed, the new one should be html_safe and of the same type
+ cache_helper.expects(:output_buffer=).with(responds_with(:html_safe?, true)).with(instance_of(output_buffer.class)).at_least(0)
+
+ assert_nothing_raised do
+ cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil }
+ end
+ end
+
+end
diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb
index afdab30eaf..2aa73f1650 100644
--- a/actionpack/test/controller/mime_responds_test.rb
+++ b/actionpack/test/controller/mime_responds_test.rb
@@ -509,7 +509,7 @@ end
class RespondWithController < ActionController::Base
respond_to :html, :json
respond_to :xml, :except => :using_resource_with_block
- respond_to :js, :only => [ :using_resource_with_block, :using_resource, :using_hash_resource ]
+ respond_to :js, :only => [ :using_resource_with_block, :using_resource, 'using_hash_resource' ]
def using_resource
respond_with(resource)
diff --git a/actionpack/test/controller/url_rewriter_test.rb b/actionpack/test/controller/url_rewriter_test.rb
index 89de4c1da4..f88903b10e 100644
--- a/actionpack/test/controller/url_rewriter_test.rb
+++ b/actionpack/test/controller/url_rewriter_test.rb
@@ -70,9 +70,9 @@ class UrlRewriterTests < ActionController::TestCase
)
end
- def test_anchor_should_be_cgi_escaped
+ def test_anchor_should_be_uri_escaped
assert_equal(
- 'http://test.host/c/a/i#anc%2Fhor',
+ 'http://test.host/c/a/i#anc/hor',
@rewriter.rewrite(@routes, :controller => 'c', :action => 'a', :id => 'i', :anchor => Struct.new(:to_param).new('anc/hor'))
)
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index c0b74bc9f9..cf22731823 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -339,6 +339,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
scope '(:locale)', :locale => /en|pl/ do
+ get "registrations/new"
resources :descriptions
root :to => 'projects#index'
end
@@ -1471,6 +1472,16 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_nested_optional_path_shorthand
+ with_test_routes do
+ get '/registrations/new'
+ assert @request.params[:locale].nil?
+
+ get '/en/registrations/new'
+ assert 'en', @request.params[:locale]
+ end
+ end
+
def test_default_params
with_test_routes do
get '/inline_pages'
@@ -2517,3 +2528,40 @@ class TestHttpMethods < ActionDispatch::IntegrationTest
end
end
end
+
+class TestUriPathEscaping < ActionDispatch::IntegrationTest
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ match '/:segment' => lambda { |env|
+ path_params = env['action_dispatch.request.path_parameters']
+ [200, { 'Content-Type' => 'text/plain' }, [path_params[:segment]]]
+ }, :as => :segment
+
+ match '/*splat' => lambda { |env|
+ path_params = env['action_dispatch.request.path_parameters']
+ [200, { 'Content-Type' => 'text/plain' }, [path_params[:splat]]]
+ }, :as => :splat
+ end
+ end
+
+ include Routes.url_helpers
+ def app; Routes end
+
+ test 'escapes generated path segment' do
+ assert_equal '/a%20b/c+d', segment_path(:segment => 'a b/c+d')
+ end
+
+ test 'unescapes recognized path segment' do
+ get '/a%20b%2Fc+d'
+ assert_equal 'a b/c+d', @response.body
+ end
+
+ test 'escapes generated path splat' do
+ assert_equal '/a%20b/c+d', splat_path(:splat => 'a b/c+d')
+ end
+
+ test 'unescapes recognized path splat' do
+ get '/a%20b/c+d'
+ assert_equal 'a b/c+d', @response.body
+ end
+end
diff --git a/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb b/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb
index c479adb897..fa5e6bd318 100644
--- a/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb
+++ b/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb
@@ -1,2 +1,3 @@
Hello
<%= cache do %>This bit's fragment cached<% end %>
+<%= 'Ciao' %>
diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb
index 0e3475d98b..8d679aac1d 100644
--- a/actionpack/test/template/number_helper_test.rb
+++ b/actionpack/test/template/number_helper_test.rb
@@ -27,6 +27,7 @@ class NumberHelperTest < ActionView::TestCase
assert_equal("800 555 1212", number_to_phone(8005551212, {:delimiter => " "}))
assert_equal("(800) 555-1212 x 123", number_to_phone(8005551212, {:area_code => true, :extension => 123}))
assert_equal("800-555-1212", number_to_phone(8005551212, :extension => " "))
+ assert_equal("555.1212", number_to_phone(5551212, :delimiter => '.'))
assert_equal("800-555-1212", number_to_phone("8005551212"))
assert_equal("+1-800-555-1212", number_to_phone(8005551212, :country_code => 1))
assert_equal("+18005551212", number_to_phone(8005551212, :country_code => 1, :delimiter => ''))
diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb
index 7bc3f997b5..a4b58ab456 100644
--- a/activemodel/lib/active_model/serialization.rb
+++ b/activemodel/lib/active_model/serialization.rb
@@ -126,7 +126,7 @@ module ActiveModel
return unless include = options[:include]
unless include.is_a?(Hash)
- include = Hash[Array.wrap(include).map { |n| [n, {}] }]
+ include = Hash[Array.wrap(include).map { |n| n.is_a?(Hash) ? n.to_a.first : [n, {}] }]
end
include.each do |association, opts|
diff --git a/activemodel/test/cases/serialization_test.rb b/activemodel/test/cases/serialization_test.rb
index 1ec915d245..b8dad9d51f 100644
--- a/activemodel/test/cases/serialization_test.rb
+++ b/activemodel/test/cases/serialization_test.rb
@@ -140,4 +140,12 @@ class SerializationTest < ActiveModel::TestCase
assert_equal expected , @user.serializable_hash(:except => :gender, :include => {:friends => {:except => :gender}})
end
+ def test_multiple_includes_with_options
+ expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
+ :address=>{"street"=>"123 Lane"},
+ :friends=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'},
+ {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]}
+ assert_equal expected , @user.serializable_hash(:include => [{:address => {:only => "street"}}, :friends])
+ end
+
end
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 50203608c2..0f6a31d679 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,16 @@
*Rails 3.2.0 (unreleased)*
+* Added ActiveRecord::Base.store for declaring simple single-column key/value stores [DHH]
+
+ class User < ActiveRecord::Base
+ store :settings, accessors: [ :color, :homepage ]
+ end
+
+ u = User.new(color: 'black', homepage: '37signals.com')
+ u.color # Accessor stored attribute
+ u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
+
+
* MySQL: case-insensitive uniqueness validation avoids calling LOWER when
the column already uses a case-insensitive collation. Fixes #561.
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index 132dc12680..3572c640eb 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -69,6 +69,7 @@ module ActiveRecord
autoload :Schema
autoload :SchemaDumper
autoload :Serialization
+ autoload :Store
autoload :SessionStore
autoload :Timestamp
autoload :Transactions
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 7a9654ffd8..360e494af1 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -2145,7 +2145,7 @@ MSG
# AutosaveAssociation needs to be included before Transactions, because we want
# #save_with_autosave_associations to be wrapped inside a transaction.
include AutosaveAssociation, NestedAttributes
- include Aggregations, Transactions, Reflection, Serialization
+ include Aggregations, Transactions, Reflection, Serialization, Store
NilClass.add_whiner(self) if NilClass.respond_to?(:add_whiner)
diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb
index 96870cb338..fc80f3081e 100644
--- a/activerecord/lib/active_record/errors.rb
+++ b/activerecord/lib/active_record/errors.rb
@@ -99,6 +99,16 @@ module ActiveRecord
#
# Read more about optimistic locking in ActiveRecord::Locking module RDoc.
class StaleObjectError < ActiveRecordError
+ attr_reader :record, :attempted_action
+
+ def initialize(record, attempted_action)
+ @record = record
+ @attempted_action = attempted_action
+ end
+
+ def message
+ "Attempted to #{attempted_action} a stale object: #{record.class.name}"
+ end
end
# Raised when association is being configured improperly or
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index d9ad7e4132..2df3309648 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -103,7 +103,7 @@ module ActiveRecord
affected_rows = connection.update stmt
unless affected_rows == 1
- raise ActiveRecord::StaleObjectError, "Attempted to update a stale object: #{self.class.name}"
+ raise ActiveRecord::StaleObjectError.new(self, "update")
end
affected_rows
@@ -127,7 +127,7 @@ module ActiveRecord
affected_rows = self.class.unscoped.where(predicate).delete_all
unless affected_rows == 1
- raise ActiveRecord::StaleObjectError, "Attempted to delete a stale object: #{self.class.name}"
+ raise ActiveRecord::StaleObjectError.new(self, "destroy")
end
end
diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb
new file mode 100644
index 0000000000..d5910df891
--- /dev/null
+++ b/activerecord/lib/active_record/store.rb
@@ -0,0 +1,49 @@
+module ActiveRecord
+ # Store gives you a thin wrapper around serialize for the purpose of storing hashes in a single column.
+ # It's like a simple key/value store backed into your record when you don't care about being able to
+ # query that store outside the context of a single record.
+ #
+ # You can then declare accessors to this store that are then accessible just like any other attribute
+ # of the model. This is very helpful for easily exposing store keys to a form or elsewhere that's
+ # already built around just accessing attributes on the model.
+ #
+ # Make sure that you declare the database column used for the serialized store as a text, so there's
+ # plenty of room.
+ #
+ # Examples:
+ #
+ # class User < ActiveRecord::Base
+ # store :settings, accessors: [ :color, :homepage ]
+ # end
+ #
+ # u = User.new(color: 'black', homepage: '37signals.com')
+ # u.color # Accessor stored attribute
+ # u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
+ #
+ # # Add additional accessors to an existing store through store_accessor
+ # class SuperUser < User
+ # store_accessor :settings, :privileges, :servants
+ # end
+ module Store
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def store(store_attribute, options = {})
+ serialize store_attribute, Hash
+ store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors
+ end
+
+ def store_accessor(store_attribute, *keys)
+ Array(keys).flatten.each do |key|
+ define_method("#{key}=") do |value|
+ send(store_attribute)[key] = value
+ end
+
+ define_method(key) do
+ send(store_attribute)[key]
+ end
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index 61baa55027..e9bd7f07b6 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -125,6 +125,24 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
end
+ def test_lock_exception_record
+ p1 = Person.new(:first_name => 'mira')
+ assert_equal 0, p1.lock_version
+
+ p1.first_name = 'mira2'
+ p1.save!
+ p2 = Person.find(p1.id)
+ assert_equal 0, p1.lock_version
+ assert_equal 0, p2.lock_version
+
+ p1.first_name = 'mira3'
+ p1.save!
+
+ p2.first_name = 'sue'
+ error = assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
+ assert_equal(error.record.object_id, p2.object_id)
+ end
+
def test_lock_new_with_nil
p1 = Person.new(:first_name => 'anika')
p1.save!
@@ -141,7 +159,6 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_equal 1, p1.lock_version
end
-
def test_lock_column_name_existing
t1 = LegacyThing.find(1)
t2 = LegacyThing.find(1)
diff --git a/activerecord/test/cases/store_test.rb b/activerecord/test/cases/store_test.rb
new file mode 100644
index 0000000000..fb77220875
--- /dev/null
+++ b/activerecord/test/cases/store_test.rb
@@ -0,0 +1,29 @@
+require 'cases/helper'
+require 'models/admin'
+require 'models/admin/user'
+
+class StoreTest < ActiveRecord::TestCase
+ setup do
+ @john = Admin::User.create(:name => 'John Doe', :color => 'black')
+ end
+
+ test "reading store attributes through accessors" do
+ assert_equal 'black', @john.color
+ assert_nil @john.homepage
+ end
+
+ test "writing store attributes through accessors" do
+ @john.color = 'red'
+ @john.homepage = '37signals.com'
+
+ assert_equal 'red', @john.color
+ assert_equal '37signals.com', @john.homepage
+ end
+
+ test "accessing attributes not exposed by accessors" do
+ @john.settings[:icecream] = 'graeters'
+ @john.save
+
+ assert 'graeters', @john.reload.settings[:icecream]
+ end
+end
diff --git a/activerecord/test/models/admin/user.rb b/activerecord/test/models/admin/user.rb
index 74bb21551e..c12c88e195 100644
--- a/activerecord/test/models/admin/user.rb
+++ b/activerecord/test/models/admin/user.rb
@@ -1,3 +1,4 @@
class Admin::User < ActiveRecord::Base
belongs_to :account
-end \ No newline at end of file
+ store :settings, :accessors => [ :color, :homepage ]
+end
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 9d5ad16a3c..bb08f5c181 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -37,6 +37,7 @@ ActiveRecord::Schema.define do
create_table :admin_users, :force => true do |t|
t.string :name
+ t.text :settings
t.references :account
end
diff --git a/activeresource/CHANGELOG b/activeresource/CHANGELOG
index fe356d7691..bd496a1263 100644
--- a/activeresource/CHANGELOG
+++ b/activeresource/CHANGELOG
@@ -1,3 +1,16 @@
+*Rails 3.2.0 (unreleased)*
+
+* Redirect responses: 303 See Other and 307 Temporary Redirect now behave like
+ 301 Moved Permanently and 302 Found. GH #3302.
+
+ [Jim Herz]
+
+
+*Rails 3.1.1 (October 7, 2011)*
+
+* No changes.
+
+
*Rails 3.1.0 (August 30, 2011)*
* The default format has been changed to JSON for all requests. If you want to continue to use XML you will need to set `self.format = :xml` in the class. eg.
diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb
index fa5c4470eb..10cc727bd9 100644
--- a/activeresource/lib/active_resource/base.rb
+++ b/activeresource/lib/active_resource/base.rb
@@ -170,8 +170,8 @@ module ActiveResource
# <tt>404</tt> is just one of the HTTP error response codes that Active Resource will handle with its own exception. The
# following HTTP response codes will also result in these exceptions:
#
- # * 200..399 - Valid response, no exception (other than 301, 302)
- # * 301, 302 - ActiveResource::Redirection
+ # * 200..399 - Valid response. No exceptions, other than these redirects:
+ # * 301, 302, 303, 307 - ActiveResource::Redirection
# * 400 - ActiveResource::BadRequest
# * 401 - ActiveResource::UnauthorizedAccess
# * 403 - ActiveResource::ForbiddenAccess
diff --git a/activeresource/lib/active_resource/connection.rb b/activeresource/lib/active_resource/connection.rb
index 592fca96a4..94839c8c25 100644
--- a/activeresource/lib/active_resource/connection.rb
+++ b/activeresource/lib/active_resource/connection.rb
@@ -122,7 +122,7 @@ module ActiveResource
# Handles response and error codes from the remote service.
def handle_response(response)
case response.code.to_i
- when 301,302
+ when 301, 302, 303, 307
raise(Redirection.new(response))
when 200...400
response
diff --git a/activeresource/test/cases/connection_test.rb b/activeresource/test/cases/connection_test.rb
index 09df0fb678..535107aeef 100644
--- a/activeresource/test/cases/connection_test.rb
+++ b/activeresource/test/cases/connection_test.rb
@@ -2,6 +2,7 @@ require 'abstract_unit'
class ConnectionTest < Test::Unit::TestCase
ResponseCodeStub = Struct.new(:code)
+ RedirectResponseStub = Struct.new(:code, :Location)
def setup
@conn = ActiveResource::Connection.new('http://localhost')
@@ -38,6 +39,18 @@ class ConnectionTest < Test::Unit::TestCase
assert_equal expected, handle_response(expected)
end
+ # 301 is moved permanently (redirect)
+ assert_redirect_raises 301
+
+ # 302 is found (redirect)
+ assert_redirect_raises 302
+
+ # 303 is see other (redirect)
+ assert_redirect_raises 303
+
+ # 307 is temporary redirect
+ assert_redirect_raises 307
+
# 400 is a bad request (e.g. malformed URI or missing request parameter)
assert_response_raises ActiveResource::BadRequest, 400
@@ -247,6 +260,12 @@ class ConnectionTest < Test::Unit::TestCase
end
end
+ def assert_redirect_raises(code)
+ assert_raise(ActiveResource::Redirection, "Expected response code #{code} to raise ActiveResource::Redirection") do
+ handle_response RedirectResponseStub.new(code, 'http://example.com/')
+ end
+ end
+
def handle_response(response)
@conn.__send__(:handle_response, response)
end
diff --git a/railties/guides/source/engines.textile b/railties/guides/source/engines.textile
index 1eb0dcb77b..126d09ab87 100644
--- a/railties/guides/source/engines.textile
+++ b/railties/guides/source/engines.textile
@@ -12,7 +12,7 @@ endprologue.
h3. What are engines?
-Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a "supercharged" engine, with the +Rails::Application+ class inheriting from +Rails::Engine+. Therefore, engines and applications share common functionality but are at the same time two separate beasts. Engines and applications also share a common structure, as you'll see througout this guide.
+Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a "supercharged" engine, with the +Rails::Application+ class inheriting from +Rails::Engine+. Therefore, engines and applications share common functionality but are at the same time two separate beasts. Engines and applications also share a common structure, as you'll see throughout this guide.
Engines are also closely related to plugins where the two share a common +lib+ directory structure and are both generated using the +rails plugin new+ generator.
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index 9cbda6649d..c8648d19f8 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -122,10 +122,15 @@ module Rails
end
def vendor
+ vendor_javascripts
vendor_stylesheets
vendor_plugins
end
+ def vendor_javascripts
+ empty_directory_with_gitkeep "vendor/assets/javascripts"
+ end
+
def vendor_stylesheets
empty_directory_with_gitkeep "vendor/assets/stylesheets"
end
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 1b48c80042..133efb872f 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -203,6 +203,16 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file 'test'
end
+ def test_creation_of_vendor_assets_javascripts_directory
+ run_generator
+ assert_file "vendor/assets/javascripts"
+ end
+
+ def test_creation_of_vendor_assets_stylesheets_directory
+ run_generator
+ assert_file "vendor/assets/stylesheets"
+ end
+
def test_jquery_is_the_default_javascript_library
run_generator
assert_file "app/assets/javascripts/application.js" do |contents|