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

This commit is contained in:
David Heinemeier Hansson
2010-06-02 16:18:03 -05:00
25 changed files with 135 additions and 60 deletions

View File

@@ -1,5 +1,7 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
* Remove middleware laziness [José Valim]
* Make session stores rely on request.cookie_jar and change set_session semantics to return the cookie value instead of a boolean. [José Valim]
* OAuth 2: HTTP Token Authorization support to complement Basic and Digest Authorization. [Rick Olson]

View File

@@ -1,4 +1,5 @@
require 'active_support/configurable'
require 'active_support/core_ext/module/anonymous'
module AbstractController
class Error < StandardError; end

View File

@@ -1,4 +1,5 @@
require "abstract_controller/base"
require "action_view"
module AbstractController
class DoubleRenderError < Error

View File

@@ -8,10 +8,10 @@ module ActionController
delegate :headers, :status=, :location=, :content_type=,
:status, :location, :content_type, :to => "@_response"
def dispatch(action, request)
@_response = ActionDispatch::Response.new
@_response.request = request
super
def dispatch(action, request, response = ActionDispatch::Response.new)
@_response ||= response
@_response.request ||= request
super(action, request)
end
def params

View File

@@ -47,6 +47,7 @@ module ActionController #:nodoc:
extend ActiveSupport::Concern
include AbstractController::Helpers
include AbstractController::Callbacks
included do
# Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+

View File

@@ -43,25 +43,25 @@ module ActionView
# ==== Examples
#
# truncate("Once upon a time in a world far far away")
# # => Once upon a time in a worl...
# # => "Once upon a time in a world..."
#
# truncate("Once upon a time in a world far far away", :separator => ' ')
# # => Once upon a time in a world...
# truncate("Once upon a time in a world far far away", :length => 17)
# # => "Once upon a ti..."
#
# truncate("Once upon a time in a world far far away", :length => 14)
# # => Once upon a...
# truncate("Once upon a time in a world far far away", :lenght => 17, :separator => ' ')
# # => "Once upon a..."
#
# truncate("And they found that many people were sleeping better.", :omission => "... (continued)", :length => 25)
# # => And they f... (continued)
# truncate("And they found that many people were sleeping better.", :length => 25, :omission => '... (continued)')
# # => "And they f... (continued)"
#
# You can still use <tt>truncate</tt> with the old API that accepts the
# +length+ as its optional second and the +ellipsis+ as its
# optional third parameter:
# truncate("Once upon a time in a world far far away", 14)
# # => Once upon a...
# # => "Once upon a..."
#
# truncate("And they found that many people were sleeping better.", 25, "... (continued)")
# # => And they f... (continued)
# # => "And they f... (continued)"
def truncate(text, *args)
options = args.extract_options!
unless args.empty?

View File

@@ -31,6 +31,7 @@ module ActionView #:nodoc:
def typecast!
each_with_index do |path, i|
path = path.to_s if path.is_a?(Pathname)
next unless path.is_a?(String)
self[i] = FileSystemResolver.new(path)
end

View File

@@ -435,6 +435,7 @@ namespace :db do
task :create => :environment do
raise "Task unavailable to this database (no migration support)" unless ActiveRecord::Base.connection.supports_migrations?
require 'rails/generators'
Rails::Generators.configure!
require 'rails/generators/rails/session_migration/session_migration_generator'
Rails::Generators::SessionMigrationGenerator.start [ ENV["MIGRATION"] || "add_sessions_table" ]
end

View File

@@ -9,7 +9,7 @@ module ActiveRecord
(ActiveRecord::Relation::ASSOCIATION_METHODS + ActiveRecord::Relation::MULTI_VALUE_METHODS).each do |query_method|
attr_accessor :"#{query_method}_values"
next if [:where, :having].include?(query_method)
next if [:where, :having, :select].include?(query_method)
class_eval <<-CEVAL, __FILE__, __LINE__ + 1
def #{query_method}(*args, &block)
new_relation = clone
@@ -21,6 +21,19 @@ module ActiveRecord
CEVAL
end
class_eval <<-CEVAL, __FILE__, __LINE__ + 1
def select(*args, &block)
if block_given?
to_a.select(&block)
else
new_relation = clone
value = Array.wrap(args.flatten).reject {|x| x.blank? }
new_relation.select_values += value if value.present?
new_relation
end
end
CEVAL
[:where, :having].each do |query_method|
class_eval <<-CEVAL, __FILE__, __LINE__ + 1
def #{query_method}(*args, &block)

View File

@@ -112,6 +112,11 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 4, developers.map(&:salary).uniq.size
end
def test_select_with_block
even_ids = Developer.scoped.select {|d| d.id % 2 == 0 }.map(&:id)
assert_equal [2, 4, 6, 8, 10], even_ids
end
def test_finding_with_hash_conditions_on_joined_table
firms = DependentFirm.joins(:account).where({:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}).to_a
assert_equal 1, firms.size

View File

@@ -20,25 +20,21 @@ class String
self
end
# Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>.
# The last characters will be replaced with the <tt>:omission</tt> (defaults to "...")
# for a total length not exceeding <tt>:length</tt>.
# Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
#
# Pass a <tt>:separator</tt> to truncate +text+ at a natural break.
# "Once upon a time in a world far far away".truncate(27)
# # => "Once upon a time in a wo..."
#
# ==== Examples
# The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
# for a total length not exceeding <tt>:length</tt>:
#
# "Once upon a time in a world far far away".truncate(30)
# # => Once upon a time in a worl...
# "Once upon a time in a world far far away".truncate(27, :separator => ' ')
# # => "Once upon a time in a..."
#
# "Once upon a time in a world far far away".truncate(30, :separator => ' ')
# # => Once upon a time in a world...
#
# "Once upon a time in a world far far away".truncate(14)
# # => Once upon a...
# Pass a <tt>:separator</tt> to truncate +text+ at a natural break:
#
# "And they found that many people were sleeping better.".truncate(25, :omission => "... (continued)")
# # => And they f... (continued)
# # => "And they f... (continued)"
def truncate(length, options = {})
text = self.dup
options[:omission] ||= "..."

View File

@@ -1,7 +1,7 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
* Version bump
* Removed Rails Metal [YK & JV].
*Rails 3.0.0 [beta 3] (April 13th, 2010)*

View File

@@ -699,7 +699,7 @@ Creates a scope around a specific model object like form_for, but doesnt crea
First name: <%= person_form.text_field :first_name %>
Last name : <%= person_form.text_field :last_name %>
<% fields_for @person.permission do |permission_fields| %>
<%= fields_for @person.permission do |permission_fields| %>
Admin? : <%= permission_fields.check_box :admin %>
<% end %>
<% end %>

View File

@@ -1254,6 +1254,39 @@ There's also the destructive version +String#squish!+.
NOTE: Defined in +active_support/core_ext/string/filters.rb+.
h4. +truncate+
The method +truncate+ returns a copy of its receiver truncated after a given +length+:
<ruby>
"Oh dear! Oh dear! I shall be late!".truncate(20)
# => "Oh dear! Oh dear!..."
</ruby>
Ellipsis can be customized with the +:omission+ option:
<ruby>
"Oh dear! Oh dear! I shall be late!".truncate(20, :omission => '&hellip;')
# => "Oh dear! Oh &hellip;"
</ruby>
Note in particular that truncation takes into account the length of the omission string.
Pass a +:separator+ to truncate the string at a natural break:
<ruby>
"Oh dear! Oh dear! I shall be late!".truncate(18)
# => "Oh dear! Oh dea..."
"Oh dear! Oh dear! I shall be late!".truncate(18, :separator => ' ')
# => "Oh dear! Oh..."
</ruby>
In the above example "dear" gets cut first, but then +:separator+ prevents it.
WARNING: The option +:separator+ can't be a regexp.
NOTE: Defined in +active_support/core_ext/string/filters.rb+.
h4. Key-based Interpolation
In Ruby 1.9 the <tt>%</tt> string operator supports key-based interpolation, both formatted and unformatted:

View File

@@ -879,32 +879,28 @@ Here is a list with all the available Active Record callbacks, listed in the sam
h4. Creating an Object
* +before_validation+
* +before_validation_on_create+
* +after_validation+
* +after_validation_on_create+
* +before_save+
* +before_create+
* INSERT OPERATION
* +after_create+
* +after_save+
* +before_create+
* +around_create+
* +after_create+
h4. Updating an Object
* +before_validation+
* +before_validation_on_update+
* +after_validation+
* +after_validation_on_update+
* +before_save+
* +before_update+
* UPDATE OPERATION
* +after_update+
* +after_save+
* +before_update+
* +around_update+
* +after_update+
h4. Destroying an Object
* +before_destroy+
* DELETE OPERATION
* +after_destroy+
* +around_destroy+
WARNING. +after_save+ runs both on create and update, but always _after_ the more specific callbacks +after_create+ and +after_update+, no matter the order in which the macro calls were executed.

View File

@@ -322,16 +322,12 @@ config.generators do |g|
g.template_engine :erb
g.test_framework :shoulda, :fixture => false
g.stylesheets false
# Add a fallback!
g.fallbacks[:should] = :test_unit
end
</ruby>
And at the end of the same file:
<ruby>
require 'rails/generators'
Rails::Generators.fallbacks[:shoulda] = :test_unit
</ruby>
Now, if create a Comment scaffold, you will see that shoulda generators are being invoked, and at the end, they are just falling back to test unit generators:
<shell>
@@ -361,7 +357,7 @@ $ rails generate scaffold Comment body:text
create test/unit/helpers/comments_helper_test.rb
</shell>
Such tool allows your generators to have single responsibility, increasing the code reuse and reducing the amount of code duplication.
Such tool allows your generators to have single responsibility, increasing the code reuse and reducing the amount of duplication.
h3. Changelog

View File

@@ -1342,7 +1342,7 @@ We also add a <tt>@post.tags.build</tt> at the top of this form, this is to make
Now create the folder <tt>app/views/tags</tt> and make a file in there called <tt>_form.html.erb</tt> which contains the form for the tag:
<erb>
<% form.fields_for :tags do |tag_form| %>
<%= form.fields_for :tags do |tag_form| %>
<div class="field">
<%= tag_form.label :name, 'Tag:' %>
<%= tag_form.text_field :name %>

View File

@@ -143,7 +143,7 @@ Now add a nested form for the +address+ association:
<%= form_for @person do |f| %>
<%= f.text_field :name %>
<% f.fields_for :address do |af| %>
<%= f.fields_for :address do |af| %>
<%= f.text_field :street %>
<% end %>
<% end %>
@@ -184,7 +184,7 @@ The form code for an association collection is pretty similar to that of a singl
<%= form_for @person do |f| %>
<%= f.text_field :name %>
<% f.fields_for :projects do |pf| %>
<%= f.fields_for :projects do |pf| %>
<%= f.text_field :name %>
<% end %>
<% end %>

View File

@@ -67,6 +67,7 @@ module Rails
raise "You cannot have more than one Rails::Application" if Rails.application
super
Rails.application = base.instance
Rails.application.add_lib_to_load_paths!
ActiveSupport.run_load_hooks(:before_configuration, base.instance)
end
@@ -83,11 +84,21 @@ module Rails
delegate :middleware, :to => :config
def add_lib_to_load_paths!
path = config.root.join('lib').to_s
$LOAD_PATH.unshift(path) if File.exists?(path)
end
def require_environment!
environment = paths.config.environment.to_a.first
require environment if environment
end
def eager_load!
railties.all(&:eager_load!)
super
end
def routes
@routes ||= ActionDispatch::Routing::RouteSet.new
end

View File

@@ -38,7 +38,7 @@ module Rails
initializer :eager_load! do
if config.cache_classes && !$rails_rake_task
ActiveSupport.run_load_hooks(:before_eager_load, self)
railties.all(&:eager_load!)
eager_load!
end
end

View File

@@ -1,4 +1,5 @@
require 'rails/generators'
Rails::Generators.configure!
if [nil, "-h", "--help"].include?(ARGV.first)
Rails::Generators.help 'destroy'

View File

@@ -1,4 +1,5 @@
require 'rails/generators'
Rails::Generators.configure!
if [nil, "-h", "--help"].include?(ARGV.first)
Rails::Generators.help 'generate'

View File

@@ -68,6 +68,7 @@ module Rails
options.deep_merge! config.options
fallbacks.merge! config.fallbacks
templates_path.concat config.templates
templates_path.uniq!
end
def self.templates_path
@@ -328,10 +329,5 @@ module Rails
paths.uniq!
paths
end
end
end
# If the application was already defined, configure generators,
# otherwise you have to configure it by hand.
Rails::Generators.configure! if Rails.respond_to?(:application) && Rails.application
end

View File

@@ -19,6 +19,23 @@ module ApplicationTests
assert $:.include?("#{app_path}/app/models")
end
test "initializing an application adds lib path on inheritance hook" do
app_file "lib/foo.rb", <<-RUBY
module Foo; end
RUBY
add_to_config <<-RUBY
require "foo"
raise "Expected Foo to be defined" unless defined?(Foo)
RUBY
assert_nothing_raised do
require "#{app_path}/config/environment"
end
assert $:.include?("#{app_path}/lib")
end
test "initializing an application eager load any path under app" do
app_file "app/anything/foo.rb", <<-RUBY
module Foo; end

View File

@@ -1,4 +1,6 @@
require 'abstract_unit'
require 'rails/generators'
require 'rails/generators/test_case'
module Rails
def self.root
@@ -8,8 +10,9 @@ end
Rails.application.config.root = Rails.root
Rails.application.config.generators.templates = [File.join(Rails.root, "lib", "templates")]
require 'rails/generators'
require 'rails/generators/test_case'
# Call configure to load the settings from
# Rails.application.config.generators to Rails::Generators
Rails::Generators.configure!
require 'active_record'
require 'action_dispatch'