diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index b7a824d559f0fcf9779d032d3ac96401d94ffb5f..4ed39133dbfcbe077a1cd2fb56441a06d51a430b 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,3 +1,8 @@
+*2.3.0/3.0*
+
+* Fixed RedCloth and BlueCloth shouldn't preload. Instead just assume that they're available if you want to use textilize and markdown and let autoload require them [DHH]
+
+
*2.2.1 [RC2] (November 14th, 2008)*
* Restore backwards compatible functionality for setting relative_url_root. Include deprecation
diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb
index 8ca3a703416ace454045491c4d4e7377a64a366d..6923a13f3f5235d8045260f4370f522d0559548a 100644
--- a/actionpack/lib/action_controller/mime_type.rb
+++ b/actionpack/lib/action_controller/mime_type.rb
@@ -25,7 +25,7 @@ class Type
# These are the content types which browsers can generate without using ajax, flash, etc
# i.e. following a link, getting an image or posting a form. CSRF protection
# only needs to protect against these types.
- @@browser_generated_types = Set.new [:html, :url_encoded_form, :multipart_form]
+ @@browser_generated_types = Set.new [:html, :url_encoded_form, :multipart_form, :text]
cattr_reader :browser_generated_types
@@ -177,7 +177,7 @@ def ==(mime_type)
end
# Returns true if Action Pack should check requests using this Mime Type for possible request forgery. See
- # ActionController::RequestForgerProtection.
+ # ActionController::RequestForgeryProtection.
def verify_request?
browser_generated?
end
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index 9bd3d63423b51d5908b3f0cd84cc0d7f46820963..510c1a6a76616709743fe4c008105691aab4b2b9 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -226,91 +226,79 @@ def word_wrap(text, *args)
end * "\n"
end
- begin
- require_library_or_gem "redcloth" unless Object.const_defined?(:RedCloth)
-
- # Returns the text with all the Textile[http://www.textism.com/tools/textile] codes turned into HTML tags.
- #
- # You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
- # This method is only available if RedCloth[http://whytheluckystiff.net/ruby/redcloth/]
- # is available.
- #
- # ==== Examples
- # textilize("*This is Textile!* Rejoice!")
- # # => "
This is Textile! Rejoice!
"
- #
- # textilize("I _love_ ROR(Ruby on Rails)!")
- # # => "I love ROR!
"
- #
- # textilize("h2. Textile makes markup -easy- simple!")
- # # => "Textile makes markup easy simple!
"
- #
- # textilize("Visit the Rails website "here":http://www.rubyonrails.org/.)
- # # => "Visit the Rails website here.
"
- def textilize(text)
- if text.blank?
- ""
- else
- textilized = RedCloth.new(text, [ :hard_breaks ])
- textilized.hard_breaks = true if textilized.respond_to?(:hard_breaks=)
- textilized.to_html
- end
+ # Returns the text with all the Textile[http://www.textism.com/tools/textile] codes turned into HTML tags.
+ #
+ # You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
+ # This method is only available if RedCloth[http://whytheluckystiff.net/ruby/redcloth/]
+ # is available.
+ #
+ # ==== Examples
+ # textilize("*This is Textile!* Rejoice!")
+ # # => "This is Textile! Rejoice!
"
+ #
+ # textilize("I _love_ ROR(Ruby on Rails)!")
+ # # => "I love ROR!
"
+ #
+ # textilize("h2. Textile makes markup -easy- simple!")
+ # # => "Textile makes markup easy simple!
"
+ #
+ # textilize("Visit the Rails website "here":http://www.rubyonrails.org/.)
+ # # => "Visit the Rails website here.
"
+ def textilize(text)
+ if text.blank?
+ ""
+ else
+ textilized = RedCloth.new(text, [ :hard_breaks ])
+ textilized.hard_breaks = true if textilized.respond_to?(:hard_breaks=)
+ textilized.to_html
end
+ end
- # Returns the text with all the Textile codes turned into HTML tags,
- # but without the bounding tag that RedCloth adds.
- #
- # You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
- # This method is only available if RedCloth[http://whytheluckystiff.net/ruby/redcloth/]
- # is available.
- #
- # ==== Examples
- # textilize_without_paragraph("*This is Textile!* Rejoice!")
- # # => "This is Textile! Rejoice!"
- #
- # textilize_without_paragraph("I _love_ ROR(Ruby on Rails)!")
- # # => "I love ROR!"
- #
- # textilize_without_paragraph("h2. Textile makes markup -easy- simple!")
- # # => "
Textile makes markup easy simple!
"
- #
- # textilize_without_paragraph("Visit the Rails website "here":http://www.rubyonrails.org/.)
- # # => "Visit the Rails website here."
- def textilize_without_paragraph(text)
- textiled = textilize(text)
- if textiled[0..2] == "" then textiled = textiled[3..-1] end
- if textiled[-4..-1] == "
" then textiled = textiled[0..-5] end
- return textiled
- end
- rescue LoadError
- # We can't really help what's not there
+ # Returns the text with all the Textile codes turned into HTML tags,
+ # but without the bounding tag that RedCloth adds.
+ #
+ # You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
+ # This method is requires RedCloth[http://whytheluckystiff.net/ruby/redcloth/]
+ # to be available.
+ #
+ # ==== Examples
+ # textilize_without_paragraph("*This is Textile!* Rejoice!")
+ # # => "This is Textile! Rejoice!"
+ #
+ # textilize_without_paragraph("I _love_ ROR(Ruby on Rails)!")
+ # # => "I love ROR!"
+ #
+ # textilize_without_paragraph("h2. Textile makes markup -easy- simple!")
+ # # => "
Textile makes markup easy simple!
"
+ #
+ # textilize_without_paragraph("Visit the Rails website "here":http://www.rubyonrails.org/.)
+ # # => "Visit the Rails website here."
+ def textilize_without_paragraph(text)
+ textiled = textilize(text)
+ if textiled[0..2] == "" then textiled = textiled[3..-1] end
+ if textiled[-4..-1] == "
" then textiled = textiled[0..-5] end
+ return textiled
end
- begin
- require_library_or_gem "bluecloth" unless Object.const_defined?(:BlueCloth)
-
- # Returns the text with all the Markdown codes turned into HTML tags.
- # This method is only available if BlueCloth[http://www.deveiate.org/projects/BlueCloth]
- # is available.
- #
- # ==== Examples
- # markdown("We are using __Markdown__ now!")
- # # => "We are using Markdown now!
"
- #
- # markdown("We like to _write_ `code`, not just _read_ it!")
- # # => "We like to write code
, not just read it!
"
- #
- # markdown("The [Markdown website](http://daringfireball.net/projects/markdown/) has more information.")
- # # => "The Markdown website
- # # has more information.
"
- #
- # markdown('![The ROR logo](http://rubyonrails.com/images/rails.png "Ruby on Rails")')
- # # => '![Ruby on Rails The ROR logo](http://rubyonrails.com/images/rails.png)
'
- def markdown(text)
- text.blank? ? "" : BlueCloth.new(text).to_html
- end
- rescue LoadError
- # We can't really help what's not there
+ # Returns the text with all the Markdown codes turned into HTML tags.
+ # This method requires BlueCloth[http://www.deveiate.org/projects/BlueCloth]
+ # to be available.
+ #
+ # ==== Examples
+ # markdown("We are using __Markdown__ now!")
+ # # => "We are using Markdown now!
"
+ #
+ # markdown("We like to _write_ `code`, not just _read_ it!")
+ # # => "We like to write code
, not just read it!
"
+ #
+ # markdown("The [Markdown website](http://daringfireball.net/projects/markdown/) has more information.")
+ # # => "The Markdown website
+ # # has more information.
"
+ #
+ # markdown('![The ROR logo](http://rubyonrails.com/images/rails.png "Ruby on Rails")')
+ # # => '![Ruby on Rails The ROR logo](http://rubyonrails.com/images/rails.png)
'
+ def markdown(text)
+ text.blank? ? "" : BlueCloth.new(text).to_html
end
# Returns +text+ transformed into HTML using simple formatting rules.
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index c2299b56add2346514beb9090d6f3655b8313385..c1d7297260f69c9e5d16079179fa072dea06f373 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,3 +1,19 @@
+*2.3.0/3.0*
+
+* Added default_scope to Base #1381 [Paweł Kondzior]. Example:
+
+ class Person < ActiveRecord::Base
+ default_scope :order => 'last_name, first_name'
+ end
+
+ class Company < ActiveRecord::Base
+ has_many :people
+ end
+
+ Person.all # => Person.find(:all, :order => 'last_name, first_name')
+ Company.find(1).people # => Person.find(:all, :order => 'last_name, first_name', :conditions => { :company_id => 1 })
+
+
*2.2.1 [RC2] (November 14th, 2008)*
* Ensure indices don't flip order in schema.rb #1266 [Jordi Bunster]
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index dcc82778490327f502bc854055ee653a4964d105..68f44ef0f680228ccd32e4dc5d527dffbba5d0b7 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -495,6 +495,10 @@ def self.reset_subclasses #:nodoc:
superclass_delegating_accessor :store_full_sti_class
self.store_full_sti_class = false
+ # Stores the default scope for the class
+ class_inheritable_accessor :default_scoping, :instance_writer => false
+ self.default_scoping = []
+
class << self # Class methods
# Find operates with four different retrieval approaches:
#
@@ -2016,6 +2020,16 @@ def subclasses #:nodoc:
@@subclasses[self] + extra = @@subclasses[self].inject([]) {|list, subclass| list + subclass.subclasses }
end
+ # Sets the default options for the model. The format of the
+ # method_scoping argument is the same as in with_scope.
+ #
+ # class Person < ActiveRecord::Base
+ # default_scope :find => { :order => 'last_name, first_name' }
+ # end
+ def default_scope(options = {})
+ self.default_scoping << { :find => options, :create => options.is_a?(Hash) ? options[:conditions] : {} }
+ end
+
# Test whether the given method and optional key are scoped.
def scoped?(method, key = nil) #:nodoc:
if current_scoped_methods && (scope = current_scoped_methods[method])
@@ -2031,7 +2045,7 @@ def scope(method, key = nil) #:nodoc:
end
def scoped_methods #:nodoc:
- Thread.current[:"#{self}_scoped_methods"] ||= []
+ Thread.current[:"#{self}_scoped_methods"] ||= self.default_scoping.dup
end
def current_scoped_methods #:nodoc:
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index a09f58fc23eeb2815e55cefac9e7db5bbb00e346..9a82ff2ed40a7ca88f2ddc121724842634e44e92 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -925,6 +925,7 @@ def setup_fixtures
end
@fixture_cache = {}
+ @@already_loaded_fixtures ||= {}
# Load fixtures once and begin transaction.
if use_transactional_fixtures?
@@ -939,7 +940,6 @@ def setup_fixtures
# Load fixtures for every test.
else
Fixtures.reset_cache
- @@already_loaded_fixtures ||= {}
@@already_loaded_fixtures[self.class] = nil
load_fixtures
end
diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb
index ff10bfaf3e2f58c990b4c099e46b8b446e35e1ca..4ac0018144ec8ccce76fbf441c898bbfda723897 100644
--- a/activerecord/test/cases/method_scoping_test.rb
+++ b/activerecord/test/cases/method_scoping_test.rb
@@ -522,6 +522,67 @@ def test_nested_scope
end
+class DefaultScopingTest < ActiveRecord::TestCase
+ fixtures :developers
+
+ def test_default_scope
+ expected = Developer.find(:all, :order => 'salary DESC').collect { |dev| dev.salary }
+ received = DeveloperOrderedBySalary.find(:all).collect { |dev| dev.salary }
+ assert_equal expected, received
+ end
+
+ def test_default_scoping_with_threads
+ scope = [{:create=>nil, :find=>{:order=>"salary DESC"}}]
+
+ 2.times do
+ Thread.new { assert_equal scope, DeveloperOrderedBySalary.send(:scoped_methods) }.join
+ end
+ end
+
+ def test_default_scoping_with_inheritance
+ scope = [{:create=>nil, :find=>{:order=>"salary DESC"}}]
+
+ # Inherit a class having a default scope and define a new default scope
+ klass = Class.new(DeveloperOrderedBySalary)
+ klass.send :default_scope, {}
+
+ # Scopes added on children should append to parent scope
+ expected_klass_scope = [{:create=>nil, :find=>{:order=>"salary DESC"}}, {:create=>nil, :find=>{}}]
+ assert_equal expected_klass_scope, klass.send(:scoped_methods)
+
+ # Parent should still have the original scope
+ assert_equal scope, DeveloperOrderedBySalary.send(:scoped_methods)
+ end
+
+ def test_method_scope
+ expected = Developer.find(:all, :order => 'name DESC').collect { |dev| dev.salary }
+ received = DeveloperOrderedBySalary.all_ordered_by_name.collect { |dev| dev.salary }
+ assert_equal expected, received
+ end
+
+ def test_nested_scope
+ expected = Developer.find(:all, :order => 'name DESC').collect { |dev| dev.salary }
+ received = DeveloperOrderedBySalary.with_scope(:find => { :order => 'name DESC'}) do
+ DeveloperOrderedBySalary.find(:all).collect { |dev| dev.salary }
+ end
+ assert_equal expected, received
+ end
+
+ def test_nested_exclusive_scope
+ expected = Developer.find(:all, :limit => 100).collect { |dev| dev.salary }
+ received = DeveloperOrderedBySalary.with_exclusive_scope(:find => { :limit => 100 }) do
+ DeveloperOrderedBySalary.find(:all).collect { |dev| dev.salary }
+ end
+ assert_equal expected, received
+ end
+
+ def test_overwriting_default_scope
+ expected = Developer.find(:all, :order => 'salary').collect { |dev| dev.salary }
+ received = DeveloperOrderedBySalary.find(:all, :order => 'salary').collect { |dev| dev.salary }
+ assert_equal expected, received
+ end
+end
+
=begin
# We disabled the scoping for has_one and belongs_to as we can't think of a proper use case
diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb
index c08476f728fb66eaeff965d8053854e07f424ef0..0c20f97502a313265ada9757aae6e52278917e06 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -77,3 +77,15 @@ def raise_if_projects_empty!
raise if projects.empty?
end
end
+
+class DeveloperOrderedBySalary < ActiveRecord::Base
+ self.table_name = 'developers'
+ default_scope :order => "salary DESC"
+
+ def self.all_ordered_by_name
+ with_scope(:find => { :order => "name DESC" }) do
+ find(:all)
+ end
+ end
+
+end
diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb
index ba52e41c08a9db29f01f56635f9b3d906eb51cd3..ad2660e6c854c1422620df69b5f053c95c4f5019 100644
--- a/activesupport/lib/active_support/inflector.rb
+++ b/activesupport/lib/active_support/inflector.rb
@@ -134,7 +134,6 @@ def inflections
# "octopus".pluralize # => "octopi"
# "sheep".pluralize # => "sheep"
# "words".pluralize # => "words"
- # "the blue mailman".pluralize # => "the blue mailmen"
# "CamelOctopus".pluralize # => "CamelOctopi"
def pluralize(word)
result = word.to_s.dup
@@ -154,7 +153,6 @@ def pluralize(word)
# "octopi".singularize # => "octopus"
# "sheep".singluarize # => "sheep"
# "word".singularize # => "word"
- # "the blue mailmen".singularize # => "the blue mailman"
# "CamelOctopi".singularize # => "CamelOctopus"
def singularize(word)
result = word.to_s.dup