Merge remote branch 'rails/master'
This commit is contained in:
commit
919eb200a9
58
README.rdoc
Normal file
58
README.rdoc
Normal file
@ -0,0 +1,58 @@
|
||||
== Welcome to Rails
|
||||
|
||||
Rails is a web-application framework that includes everything needed to create
|
||||
database-backed web applications according to the Model-View-Control pattern.
|
||||
|
||||
This pattern splits the view (also called the presentation) into "dumb"
|
||||
templates that are primarily responsible for inserting pre-built data in between
|
||||
HTML tags. The model contains the "smart" domain objects (such as Account,
|
||||
Product, Person, Post) that holds all the business logic and knows how to
|
||||
persist themselves to a database. The controller handles the incoming requests
|
||||
(such as Save New Account, Update Product, Show Post) by manipulating the model
|
||||
and directing data to the view.
|
||||
|
||||
In Rails, the model is handled by what's called an object-relational mapping
|
||||
layer entitled Active Record. This layer allows you to present the data from
|
||||
database rows as objects and embellish these data objects with business logic
|
||||
methods. You can read more about Active Record in
|
||||
link:files/vendor/rails/activerecord/README.html.
|
||||
|
||||
The controller and view are handled by the Action Pack, which handles both
|
||||
layers by its two parts: Action View and Action Controller. These two layers
|
||||
are bundled in a single package due to their heavy interdependence. This is
|
||||
unlike the relationship between the Active Record and Action Pack that is much
|
||||
more separate. Each of these packages can be used independently outside of
|
||||
Rails. You can read more about Action Pack in
|
||||
link:files/vendor/rails/actionpack/README.html.
|
||||
|
||||
|
||||
== Getting Started
|
||||
|
||||
1. Install Rails at the command prompt if you haven't yet:
|
||||
<tt>gem install rails</tt>
|
||||
|
||||
2. At the command prompt, create a new Rails application:
|
||||
<tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name)
|
||||
|
||||
3. Change directory to <tt>myapp</tt> and start the web server:
|
||||
<tt>cd myapp; rails server</tt> (run with --help for options)
|
||||
|
||||
4. Go to http://localhost:3000/ and you'll see:
|
||||
"Welcome aboard: You're riding Ruby on Rails!"
|
||||
|
||||
5. Follow the guidelines to start developing your application. You can find
|
||||
the following resources handy:
|
||||
|
||||
* The README file created within your application
|
||||
* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html
|
||||
* Ruby on Rails Tutorial Book: http://www.railstutorial.org/
|
||||
|
||||
|
||||
== Contributing
|
||||
|
||||
Check out the contributing guide at http://edgeguides.rubyonrails.org/contributing_to_rails.html
|
||||
|
||||
|
||||
== License
|
||||
|
||||
Ruby on Rails is released under the MIT license.
|
16
Rakefile
16
Rakefile
@ -69,7 +69,7 @@ Rake::RDocTask.new do |rdoc|
|
||||
rdoc.options << '--line-numbers' << '--inline-source'
|
||||
rdoc.options << '-A cattr_accessor=object'
|
||||
rdoc.options << '--charset' << 'utf-8'
|
||||
rdoc.options << '--main' << 'railties/README'
|
||||
rdoc.options << '--main' << 'README.rdoc'
|
||||
|
||||
# Workaround: RDoc assumes that rdoc.template can be required, and that
|
||||
# rdoc.template.upcase is a constant living in RDoc::Generator::HTML
|
||||
@ -83,38 +83,38 @@ Rake::RDocTask.new do |rdoc|
|
||||
|
||||
rdoc.rdoc_files.include('railties/CHANGELOG')
|
||||
rdoc.rdoc_files.include('railties/MIT-LICENSE')
|
||||
rdoc.rdoc_files.include('railties/README')
|
||||
rdoc.rdoc_files.include('railties/README.rdoc')
|
||||
rdoc.rdoc_files.include('railties/lib/**/*.rb')
|
||||
rdoc.rdoc_files.exclude('railties/lib/rails/generators/**/templates/*')
|
||||
|
||||
rdoc.rdoc_files.include('activerecord/README')
|
||||
rdoc.rdoc_files.include('activerecord/README.rdoc')
|
||||
rdoc.rdoc_files.include('activerecord/CHANGELOG')
|
||||
rdoc.rdoc_files.include('activerecord/lib/active_record/**/*.rb')
|
||||
rdoc.rdoc_files.exclude('activerecord/lib/active_record/vendor/*')
|
||||
|
||||
rdoc.rdoc_files.include('activeresource/README')
|
||||
rdoc.rdoc_files.include('activeresource/README.rdoc')
|
||||
rdoc.rdoc_files.include('activeresource/CHANGELOG')
|
||||
rdoc.rdoc_files.include('activeresource/lib/active_resource.rb')
|
||||
rdoc.rdoc_files.include('activeresource/lib/active_resource/*')
|
||||
|
||||
rdoc.rdoc_files.include('actionpack/README')
|
||||
rdoc.rdoc_files.include('actionpack/README.rdoc')
|
||||
rdoc.rdoc_files.include('actionpack/CHANGELOG')
|
||||
rdoc.rdoc_files.include('actionpack/lib/action_controller/**/*.rb')
|
||||
rdoc.rdoc_files.include('actionpack/lib/action_dispatch/**/*.rb')
|
||||
rdoc.rdoc_files.include('actionpack/lib/action_view/**/*.rb')
|
||||
rdoc.rdoc_files.exclude('actionpack/lib/action_controller/vendor/*')
|
||||
|
||||
rdoc.rdoc_files.include('actionmailer/README')
|
||||
rdoc.rdoc_files.include('actionmailer/README.rdoc')
|
||||
rdoc.rdoc_files.include('actionmailer/CHANGELOG')
|
||||
rdoc.rdoc_files.include('actionmailer/lib/action_mailer/base.rb')
|
||||
rdoc.rdoc_files.exclude('actionmailer/lib/action_mailer/vendor/*')
|
||||
|
||||
rdoc.rdoc_files.include('activesupport/README')
|
||||
rdoc.rdoc_files.include('activesupport/README.rdoc')
|
||||
rdoc.rdoc_files.include('activesupport/CHANGELOG')
|
||||
rdoc.rdoc_files.include('activesupport/lib/active_support/**/*.rb')
|
||||
rdoc.rdoc_files.exclude('activesupport/lib/active_support/vendor/*')
|
||||
|
||||
rdoc.rdoc_files.include('activemodel/README')
|
||||
rdoc.rdoc_files.include('activemodel/README.rdoc')
|
||||
rdoc.rdoc_files.include('activemodel/CHANGELOG')
|
||||
rdoc.rdoc_files.include('activemodel/lib/active_model/**/*.rb')
|
||||
end
|
||||
|
@ -126,36 +126,20 @@ or is accessible as a GEM.
|
||||
|
||||
Additionally, Action Mailer requires the Mail gem, http://github.com/mikel/mail
|
||||
|
||||
== Bundled software
|
||||
|
||||
* Text::Format 0.63 by Austin Ziegler released under OpenSource
|
||||
Read more on http://www.halostatue.ca/ruby/Text__Format.html
|
||||
|
||||
== Download
|
||||
|
||||
The latest version of Action Mailer can be found at
|
||||
The latest version of Action Mailer can be installed with Rubygems:
|
||||
|
||||
* http://rubyforge.org/project/showfiles.php?group_id=361
|
||||
* gem install actionmailer
|
||||
|
||||
Documentation can be found at
|
||||
|
||||
* http://actionmailer.rubyonrails.org
|
||||
|
||||
|
||||
== Installation
|
||||
|
||||
You can install Action Mailer with the following command.
|
||||
|
||||
% [sudo] ruby install.rb
|
||||
|
||||
from its distribution directory.
|
||||
|
||||
* http://api.rubyonrails.org
|
||||
|
||||
== License
|
||||
|
||||
Action Mailer is released under the MIT license.
|
||||
|
||||
|
||||
== Support
|
||||
|
||||
The Action Mailer homepage is http://www.rubyonrails.org. You can find
|
@ -32,7 +32,7 @@ Rake::RDocTask.new { |rdoc|
|
||||
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
||||
rdoc.options << '--charset' << 'utf-8'
|
||||
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
|
||||
rdoc.rdoc_files.include('README', 'CHANGELOG')
|
||||
rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG')
|
||||
rdoc.rdoc_files.include('lib/action_mailer.rb')
|
||||
rdoc.rdoc_files.include('lib/action_mailer/*.rb')
|
||||
rdoc.rdoc_files.include('lib/action_mailer/delivery_method/*.rb')
|
||||
|
@ -13,7 +13,7 @@
|
||||
s.homepage = 'http://www.rubyonrails.org'
|
||||
s.rubyforge_project = 'actionmailer'
|
||||
|
||||
s.files = Dir['CHANGELOG', 'README', 'MIT-LICENSE', 'lib/**/*']
|
||||
s.files = Dir['CHANGELOG', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*']
|
||||
s.require_path = 'lib'
|
||||
s.requirements << 'none'
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
require 'rbconfig'
|
||||
require 'find'
|
||||
require 'ftools'
|
||||
|
||||
include Config
|
||||
|
||||
# this was adapted from rdoc's install.rb by way of Log4r
|
||||
|
||||
$sitedir = CONFIG["sitelibdir"]
|
||||
unless $sitedir
|
||||
version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
|
||||
$libdir = File.join(CONFIG["libdir"], "ruby", version)
|
||||
$sitedir = $:.find {|x| x =~ /site_ruby/ }
|
||||
if !$sitedir
|
||||
$sitedir = File.join($libdir, "site_ruby")
|
||||
elsif $sitedir !~ Regexp.quote(version)
|
||||
$sitedir = File.join($sitedir, version)
|
||||
end
|
||||
end
|
||||
|
||||
# the actual gruntwork
|
||||
Dir.chdir("lib")
|
||||
|
||||
Find.find("action_mailer", "action_mailer.rb") { |f|
|
||||
if f[-3..-1] == ".rb"
|
||||
File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
|
||||
else
|
||||
File::makedirs(File.join($sitedir, *f.split(/\//)))
|
||||
end
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
*Rails 3.0.0 [Release Candidate] (unreleased)*
|
||||
|
||||
* Allow stylesheet/javascript extensions to be changed through railties. [Josh Kalderimis]
|
||||
|
||||
* link_to, button_to, and tag/tag_options now rely on html_escape instead of escape_once. [fxn]
|
||||
|
||||
* url_for returns always unescaped strings, and the :escape option is gone. [fxn]
|
||||
|
@ -19,15 +19,6 @@ the HTML. To avoid cluttering the templates with code, a bunch of helper
|
||||
classes provide common behavior for forms, dates, and strings. And it's easy
|
||||
to add specific helpers to keep the separation as the application evolves.
|
||||
|
||||
Note: Some of the features, such as scaffolding and form building, are tied to
|
||||
ActiveRecord[http://activerecord.rubyonrails.org] (an object-relational
|
||||
mapping package), but that doesn't mean that Action Pack depends on Active
|
||||
Record. Action Pack is an independent package that can be used with any sort
|
||||
of backend (Instiki[http://www.instiki.org], which is based on an older version
|
||||
of Action Pack, used Madeleine for example). Read more about the role Action
|
||||
Pack can play when used together with Active Record on
|
||||
http://www.rubyonrails.org.
|
||||
|
||||
A short rundown of the major features:
|
||||
|
||||
* Actions grouped in controller as methods instead of separate command objects
|
||||
@ -366,22 +357,13 @@ an URL such as /weblog/5 (where 5 is the id of the post).
|
||||
|
||||
== Download
|
||||
|
||||
The latest version of Action Pack can be found at
|
||||
The latest version of Action Pack can be installed with Rubygems:
|
||||
|
||||
* http://rubyforge.org/project/showfiles.php?group_id=249
|
||||
* gem install actionpack
|
||||
|
||||
Documentation can be found at
|
||||
Documentation can be found at
|
||||
|
||||
* http://api.rubyonrails.com
|
||||
|
||||
|
||||
== Installation
|
||||
|
||||
You can install Action Pack with the following command.
|
||||
|
||||
% [sudo] ruby install.rb
|
||||
|
||||
from its distribution directory.
|
||||
* http://api.rubyonrails.org
|
||||
|
||||
|
||||
== License
|
@ -47,7 +47,7 @@ Rake::RDocTask.new { |rdoc|
|
||||
if ENV['DOC_FILES']
|
||||
rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
|
||||
else
|
||||
rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
|
||||
rdoc.rdoc_files.include('README.rdoc', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
|
||||
rdoc.rdoc_files.include(Dir['lib/**/*.rb'] -
|
||||
Dir['lib/*/vendor/**/*.rb'])
|
||||
rdoc.rdoc_files.exclude('lib/actionpack.rb')
|
||||
|
@ -13,7 +13,7 @@
|
||||
s.homepage = 'http://www.rubyonrails.org'
|
||||
s.rubyforge_project = 'actionpack'
|
||||
|
||||
s.files = Dir['CHANGELOG', 'README', 'MIT-LICENSE', 'lib/**/*']
|
||||
s.files = Dir['CHANGELOG', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*']
|
||||
s.require_path = 'lib'
|
||||
s.requirements << 'none'
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
require 'rbconfig'
|
||||
require 'find'
|
||||
require 'ftools'
|
||||
|
||||
include Config
|
||||
|
||||
# this was adapted from rdoc's install.rb by way of Log4r
|
||||
|
||||
$sitedir = CONFIG["sitelibdir"]
|
||||
unless $sitedir
|
||||
version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
|
||||
$libdir = File.join(CONFIG["libdir"], "ruby", version)
|
||||
$sitedir = $:.find {|x| x =~ /site_ruby/ }
|
||||
if !$sitedir
|
||||
$sitedir = File.join($libdir, "site_ruby")
|
||||
elsif $sitedir !~ Regexp.quote(version)
|
||||
$sitedir = File.join($sitedir, version)
|
||||
end
|
||||
end
|
||||
|
||||
# the actual gruntwork
|
||||
Dir.chdir("lib")
|
||||
|
||||
Find.find("action_controller", "action_controller.rb", "action_view", "action_view.rb") { |f|
|
||||
if f[-3..-1] == ".rb"
|
||||
File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
|
||||
else
|
||||
File::makedirs(File.join($sitedir, *f.split(/\//)))
|
||||
end
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
|
||||
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
|
||||
|
||||
require 'action_pack'
|
||||
require 'active_support/ruby/shim'
|
||||
require 'active_support/dependencies/autoload'
|
||||
require 'active_support/core_ext/class/attribute'
|
||||
|
@ -6,7 +6,6 @@ module ActionController
|
||||
|
||||
autoload :Base
|
||||
autoload :Caching
|
||||
autoload :PolymorphicRoutes
|
||||
autoload :Metal
|
||||
autoload :Middleware
|
||||
|
||||
|
@ -28,7 +28,6 @@ def self.without_modules(*modules)
|
||||
SessionManagement,
|
||||
Caching,
|
||||
MimeResponds,
|
||||
PolymorphicRoutes,
|
||||
ImplicitRender,
|
||||
|
||||
Cookies,
|
||||
@ -69,4 +68,4 @@ def self.inherited(klass)
|
||||
end
|
||||
end
|
||||
|
||||
require "action_controller/deprecated/base"
|
||||
require "action_controller/deprecated/base"
|
||||
|
@ -1,3 +1,4 @@
|
||||
require 'benchmark'
|
||||
require 'abstract_controller/logger'
|
||||
|
||||
module ActionController
|
||||
|
@ -3,6 +3,15 @@ module Rescue
|
||||
extend ActiveSupport::Concern
|
||||
include ActiveSupport::Rescuable
|
||||
|
||||
def rescue_with_handler(exception)
|
||||
if (exception.respond_to?(:original_exception) &&
|
||||
(orig_exception = exception.original_exception) &&
|
||||
handler_for_rescue(orig_exception))
|
||||
exception = orig_exception
|
||||
end
|
||||
super(exception)
|
||||
end
|
||||
|
||||
private
|
||||
def process_action(*args)
|
||||
super
|
||||
|
@ -1,3 +1,5 @@
|
||||
require 'active_support/core_ext/file/path'
|
||||
|
||||
module ActionController #:nodoc:
|
||||
# Methods for sending arbitrary data and for streaming files to the browser,
|
||||
# instead of rendering.
|
||||
|
@ -1,183 +0,0 @@
|
||||
module ActionController
|
||||
# Polymorphic URL helpers are methods for smart resolution to a named route call when
|
||||
# given an Active Record model instance. They are to be used in combination with
|
||||
# ActionController::Resources.
|
||||
#
|
||||
# These methods are useful when you want to generate correct URL or path to a RESTful
|
||||
# resource without having to know the exact type of the record in question.
|
||||
#
|
||||
# Nested resources and/or namespaces are also supported, as illustrated in the example:
|
||||
#
|
||||
# polymorphic_url([:admin, @article, @comment])
|
||||
#
|
||||
# results in:
|
||||
#
|
||||
# admin_article_comment_url(@article, @comment)
|
||||
#
|
||||
# == Usage within the framework
|
||||
#
|
||||
# Polymorphic URL helpers are used in a number of places throughout the Rails framework:
|
||||
#
|
||||
# * <tt>url_for</tt>, so you can use it with a record as the argument, e.g.
|
||||
# <tt>url_for(@article)</tt>;
|
||||
# * ActionView::Helpers::FormHelper uses <tt>polymorphic_path</tt>, so you can write
|
||||
# <tt>form_for(@article)</tt> without having to specify <tt>:url</tt> parameter for the form
|
||||
# action;
|
||||
# * <tt>redirect_to</tt> (which, in fact, uses <tt>url_for</tt>) so you can write
|
||||
# <tt>redirect_to(post)</tt> in your controllers;
|
||||
# * ActionView::Helpers::AtomFeedHelper, so you don't have to explicitly specify URLs
|
||||
# for feed entries.
|
||||
#
|
||||
# == Prefixed polymorphic helpers
|
||||
#
|
||||
# In addition to <tt>polymorphic_url</tt> and <tt>polymorphic_path</tt> methods, a
|
||||
# number of prefixed helpers are available as a shorthand to <tt>:action => "..."</tt>
|
||||
# in options. Those are:
|
||||
#
|
||||
# * <tt>edit_polymorphic_url</tt>, <tt>edit_polymorphic_path</tt>
|
||||
# * <tt>new_polymorphic_url</tt>, <tt>new_polymorphic_path</tt>
|
||||
#
|
||||
# Example usage:
|
||||
#
|
||||
# edit_polymorphic_path(@post) # => "/posts/1/edit"
|
||||
# polymorphic_path(@post, :format => :pdf) # => "/posts/1.pdf"
|
||||
module PolymorphicRoutes
|
||||
# Constructs a call to a named RESTful route for the given record and returns the
|
||||
# resulting URL string. For example:
|
||||
#
|
||||
# # calls post_url(post)
|
||||
# polymorphic_url(post) # => "http://example.com/posts/1"
|
||||
# polymorphic_url([blog, post]) # => "http://example.com/blogs/1/posts/1"
|
||||
# polymorphic_url([:admin, blog, post]) # => "http://example.com/admin/blogs/1/posts/1"
|
||||
# polymorphic_url([user, :blog, post]) # => "http://example.com/users/1/blog/posts/1"
|
||||
# polymorphic_url(Comment) # => "http://example.com/comments"
|
||||
#
|
||||
# ==== Options
|
||||
#
|
||||
# * <tt>:action</tt> - Specifies the action prefix for the named route:
|
||||
# <tt>:new</tt> or <tt>:edit</tt>. Default is no prefix.
|
||||
# * <tt>:routing_type</tt> - Allowed values are <tt>:path</tt> or <tt>:url</tt>.
|
||||
# Default is <tt>:url</tt>.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# # an Article record
|
||||
# polymorphic_url(record) # same as article_url(record)
|
||||
#
|
||||
# # a Comment record
|
||||
# polymorphic_url(record) # same as comment_url(record)
|
||||
#
|
||||
# # it recognizes new records and maps to the collection
|
||||
# record = Comment.new
|
||||
# polymorphic_url(record) # same as comments_url()
|
||||
#
|
||||
# # the class of a record will also map to the collection
|
||||
# polymorphic_url(Comment) # same as comments_url()
|
||||
#
|
||||
def polymorphic_url(record_or_hash_or_array, options = {})
|
||||
if record_or_hash_or_array.kind_of?(Array)
|
||||
record_or_hash_or_array = record_or_hash_or_array.compact
|
||||
record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1
|
||||
end
|
||||
|
||||
record = extract_record(record_or_hash_or_array)
|
||||
record = record.to_model if record.respond_to?(:to_model)
|
||||
|
||||
args = case record_or_hash_or_array
|
||||
when Hash; [ record_or_hash_or_array ]
|
||||
when Array; record_or_hash_or_array.dup
|
||||
else [ record_or_hash_or_array ]
|
||||
end
|
||||
|
||||
inflection = if options[:action].to_s == "new"
|
||||
args.pop
|
||||
:singular
|
||||
elsif (record.respond_to?(:persisted?) && !record.persisted?)
|
||||
args.pop
|
||||
:plural
|
||||
elsif record.is_a?(Class)
|
||||
args.pop
|
||||
:plural
|
||||
else
|
||||
:singular
|
||||
end
|
||||
|
||||
args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
|
||||
named_route = build_named_route_call(record_or_hash_or_array, inflection, options)
|
||||
|
||||
url_options = options.except(:action, :routing_type)
|
||||
unless url_options.empty?
|
||||
args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options
|
||||
end
|
||||
|
||||
__send__(named_route, *args)
|
||||
end
|
||||
|
||||
# Returns the path component of a URL for the given record. It uses
|
||||
# <tt>polymorphic_url</tt> with <tt>:routing_type => :path</tt>.
|
||||
def polymorphic_path(record_or_hash_or_array, options = {})
|
||||
polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path))
|
||||
end
|
||||
|
||||
%w(edit new).each do |action|
|
||||
module_eval <<-EOT, __FILE__, __LINE__ + 1
|
||||
def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {})
|
||||
polymorphic_url( # polymorphic_url(
|
||||
record_or_hash, # record_or_hash,
|
||||
options.merge(:action => "#{action}")) # options.merge(:action => "edit"))
|
||||
end # end
|
||||
#
|
||||
def #{action}_polymorphic_path(record_or_hash, options = {}) # def edit_polymorphic_path(record_or_hash, options = {})
|
||||
polymorphic_url( # polymorphic_url(
|
||||
record_or_hash, # record_or_hash,
|
||||
options.merge(:action => "#{action}", :routing_type => :path)) # options.merge(:action => "edit", :routing_type => :path))
|
||||
end # end
|
||||
EOT
|
||||
end
|
||||
|
||||
private
|
||||
def action_prefix(options)
|
||||
options[:action] ? "#{options[:action]}_" : ''
|
||||
end
|
||||
|
||||
def routing_type(options)
|
||||
options[:routing_type] || :url
|
||||
end
|
||||
|
||||
def build_named_route_call(records, inflection, options = {})
|
||||
unless records.is_a?(Array)
|
||||
record = extract_record(records)
|
||||
route = ''
|
||||
else
|
||||
record = records.pop
|
||||
route = records.inject("") do |string, parent|
|
||||
if parent.is_a?(Symbol) || parent.is_a?(String)
|
||||
string << "#{parent}_"
|
||||
else
|
||||
string << RecordIdentifier.__send__("plural_class_name", parent).singularize
|
||||
string << "_"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if record.is_a?(Symbol) || record.is_a?(String)
|
||||
route << "#{record}_"
|
||||
else
|
||||
route << RecordIdentifier.__send__("plural_class_name", record)
|
||||
route = route.singularize if inflection == :singular
|
||||
route << "_"
|
||||
route << "index_" if RecordIdentifier.uncountable?(record) && inflection == :plural
|
||||
end
|
||||
|
||||
action_prefix(options) + route + routing_type(options).to_s
|
||||
end
|
||||
|
||||
def extract_record(record_or_hash_or_array)
|
||||
case record_or_hash_or_array
|
||||
when Array; record_or_hash_or_array.last
|
||||
when Hash; record_or_hash_or_array[:id]
|
||||
else record_or_hash_or_array
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -46,7 +46,7 @@ module RecordIdentifier
|
||||
# dom_class(post, :edit) # => "edit_post"
|
||||
# dom_class(Person, :edit) # => "edit_person"
|
||||
def dom_class(record_or_class, prefix = nil)
|
||||
singular = singular_class_name(record_or_class)
|
||||
singular = ActiveModel::Naming.singular(record_or_class)
|
||||
prefix ? "#{prefix}#{JOIN}#{singular}" : singular
|
||||
end
|
||||
|
||||
@ -67,6 +67,8 @@ def dom_id(record, prefix = nil)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Returns a string representation of the key attribute(s) that is suitable for use in an HTML DOM id.
|
||||
# This can be overwritten to customize the default generated string representation if desired.
|
||||
# If you need to read back a key from a dom_id in order to query for the underlying database record,
|
||||
@ -85,34 +87,5 @@ def record_key_for_dom_id(record)
|
||||
def sanitize_dom_id(candidate_id)
|
||||
candidate_id # TODO implement conversion to valid DOM id values
|
||||
end
|
||||
|
||||
# Returns the plural class name of a record or class. Examples:
|
||||
#
|
||||
# plural_class_name(post) # => "posts"
|
||||
# plural_class_name(Highrise::Person) # => "highrise_people"
|
||||
def plural_class_name(record_or_class)
|
||||
model_name_from_record_or_class(record_or_class).plural
|
||||
end
|
||||
|
||||
# Returns the singular class name of a record or class. Examples:
|
||||
#
|
||||
# singular_class_name(post) # => "post"
|
||||
# singular_class_name(Highrise::Person) # => "highrise_person"
|
||||
def singular_class_name(record_or_class)
|
||||
model_name_from_record_or_class(record_or_class).singular
|
||||
end
|
||||
|
||||
# Identifies whether the class name of a record or class is uncountable. Examples:
|
||||
#
|
||||
# uncountable?(Sheep) # => true
|
||||
# uncountable?(Post) => false
|
||||
def uncountable?(record_or_class)
|
||||
plural_class_name(record_or_class) == singular_class_name(record_or_class)
|
||||
end
|
||||
|
||||
private
|
||||
def model_name_from_record_or_class(record_or_class)
|
||||
(record_or_class.is_a?(Class) ? record_or_class : record_or_class.class).model_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -24,9 +24,14 @@
|
||||
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
|
||||
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
|
||||
|
||||
activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
|
||||
$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
|
||||
|
||||
require 'active_support'
|
||||
require 'active_support/dependencies/autoload'
|
||||
|
||||
require 'action_pack'
|
||||
require 'active_model'
|
||||
require 'rack'
|
||||
|
||||
module Rack
|
||||
@ -63,6 +68,7 @@ module Http
|
||||
autoload :Headers
|
||||
autoload :MimeNegotiation
|
||||
autoload :Parameters
|
||||
autoload :ParameterFilter
|
||||
autoload :FilterParameters
|
||||
autoload :Upload
|
||||
autoload :UploadedFile, 'action_dispatch/http/upload'
|
||||
|
@ -26,88 +26,32 @@ module Http
|
||||
module FilterParameters
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
@@compiled_parameter_filter_for = {}
|
||||
@@parameter_filter_for = {}
|
||||
|
||||
# Return a hash of parameters with all sensitive data replaced.
|
||||
def filtered_parameters
|
||||
@filtered_parameters ||= if filtering_parameters?
|
||||
process_parameter_filter(parameters)
|
||||
else
|
||||
parameters.dup
|
||||
end
|
||||
@filtered_parameters ||= parameter_filter.filter(parameters)
|
||||
end
|
||||
alias :fitered_params :filtered_parameters
|
||||
|
||||
# Return a hash of request.env with all sensitive data replaced.
|
||||
def filtered_env
|
||||
filtered_env = @env.dup
|
||||
filtered_env.each do |key, value|
|
||||
if (key =~ /RAW_POST_DATA/i)
|
||||
filtered_env[key] = '[FILTERED]'
|
||||
elsif value.is_a?(Hash)
|
||||
filtered_env[key] = process_parameter_filter(value)
|
||||
end
|
||||
end
|
||||
filtered_env
|
||||
@filtered_env ||= env_filter.filter(@env)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def filtering_parameters? #:nodoc:
|
||||
@env["action_dispatch.parameter_filter"].present?
|
||||
def parameter_filter
|
||||
parameter_filter_for(@env["action_dispatch.parameter_filter"])
|
||||
end
|
||||
|
||||
def process_parameter_filter(params) #:nodoc:
|
||||
compiled_parameter_filter_for(@env["action_dispatch.parameter_filter"]).call(params)
|
||||
def env_filter
|
||||
parameter_filter_for(Array.wrap(@env["action_dispatch.parameter_filter"]) << /RAW_POST_DATA/)
|
||||
end
|
||||
|
||||
def compile_parameter_filter(filters) #:nodoc:
|
||||
strings, regexps, blocks = [], [], []
|
||||
|
||||
filters.each do |item|
|
||||
case item
|
||||
when NilClass
|
||||
when Proc
|
||||
blocks << item
|
||||
when Regexp
|
||||
regexps << item
|
||||
else
|
||||
strings << item.to_s
|
||||
end
|
||||
end
|
||||
|
||||
regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
|
||||
[regexps, blocks]
|
||||
end
|
||||
|
||||
def compiled_parameter_filter_for(filters) #:nodoc:
|
||||
@@compiled_parameter_filter_for[filters] ||= begin
|
||||
regexps, blocks = compile_parameter_filter(filters)
|
||||
|
||||
lambda do |original_params|
|
||||
filtered_params = {}
|
||||
|
||||
original_params.each do |key, value|
|
||||
if regexps.find { |r| key =~ r }
|
||||
value = '[FILTERED]'
|
||||
elsif value.is_a?(Hash)
|
||||
value = process_parameter_filter(value)
|
||||
elsif value.is_a?(Array)
|
||||
value = value.map { |v| v.is_a?(Hash) ? process_parameter_filter(v) : v }
|
||||
elsif blocks.present?
|
||||
key = key.dup
|
||||
value = value.dup if value.duplicable?
|
||||
blocks.each { |b| b.call(key, value) }
|
||||
end
|
||||
|
||||
filtered_params[key] = value
|
||||
end
|
||||
|
||||
filtered_params
|
||||
end
|
||||
end
|
||||
def parameter_filter_for(filters)
|
||||
@@parameter_filter_for[filters] ||= ParameterFilter.new(filters)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
72
actionpack/lib/action_dispatch/http/parameter_filter.rb
Normal file
72
actionpack/lib/action_dispatch/http/parameter_filter.rb
Normal file
@ -0,0 +1,72 @@
|
||||
module ActionDispatch
|
||||
module Http
|
||||
class ParameterFilter
|
||||
|
||||
def initialize(filters)
|
||||
@filters = filters
|
||||
end
|
||||
|
||||
def filter(params)
|
||||
if enabled?
|
||||
compiled_filter.call(params)
|
||||
else
|
||||
params.dup
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def enabled?
|
||||
@filters.present?
|
||||
end
|
||||
|
||||
def compiled_filter
|
||||
@compiled_filter ||= begin
|
||||
regexps, blocks = compile_filter
|
||||
|
||||
lambda do |original_params|
|
||||
filtered_params = {}
|
||||
|
||||
original_params.each do |key, value|
|
||||
if regexps.find { |r| key =~ r }
|
||||
value = '[FILTERED]'
|
||||
elsif value.is_a?(Hash)
|
||||
value = filter(value)
|
||||
elsif value.is_a?(Array)
|
||||
value = value.map { |v| v.is_a?(Hash) ? filter(v) : v }
|
||||
elsif blocks.present?
|
||||
key = key.dup
|
||||
value = value.dup if value.duplicable?
|
||||
blocks.each { |b| b.call(key, value) }
|
||||
end
|
||||
|
||||
filtered_params[key] = value
|
||||
end
|
||||
|
||||
filtered_params
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def compile_filter
|
||||
strings, regexps, blocks = [], [], []
|
||||
|
||||
@filters.each do |item|
|
||||
case item
|
||||
when NilClass
|
||||
when Proc
|
||||
blocks << item
|
||||
when Regexp
|
||||
regexps << item
|
||||
else
|
||||
strings << item.to_s
|
||||
end
|
||||
end
|
||||
|
||||
regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
|
||||
[regexps, blocks]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -24,9 +24,9 @@ def initialize(by, env, default_options)
|
||||
|
||||
def [](key)
|
||||
if key == :id
|
||||
load_session_id! unless super(:id) || has_session_id?
|
||||
load_session_id! unless key?(:id) || has_session_id?
|
||||
end
|
||||
super(key)
|
||||
super
|
||||
end
|
||||
|
||||
private
|
||||
@ -191,8 +191,11 @@ def set_cookie(request, options)
|
||||
|
||||
def load_session(env)
|
||||
stale_session_check! do
|
||||
sid = current_session_id(env)
|
||||
sid, session = get_session(env, sid)
|
||||
if sid = current_session_id(env)
|
||||
sid, session = get_session(env, sid)
|
||||
else
|
||||
sid, session = generate_sid, {}
|
||||
end
|
||||
[sid, session]
|
||||
end
|
||||
end
|
||||
|
@ -25,7 +25,6 @@ def initialize(app, options = {})
|
||||
|
||||
private
|
||||
def get_session(env, sid)
|
||||
sid ||= generate_sid
|
||||
begin
|
||||
session = @pool.get(sid) || {}
|
||||
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
|
||||
|
@ -46,7 +46,7 @@ def initialize(*args, &block)
|
||||
end
|
||||
|
||||
def insert(index, *args, &block)
|
||||
index = self.index(index) unless index.is_a?(Integer)
|
||||
index = assert_index(index, :before)
|
||||
middleware = self.class::Middleware.new(*args, &block)
|
||||
super(index, middleware)
|
||||
end
|
||||
@ -54,9 +54,8 @@ def insert(index, *args, &block)
|
||||
alias_method :insert_before, :insert
|
||||
|
||||
def insert_after(index, *args, &block)
|
||||
i = index.is_a?(Integer) ? index : self.index(index)
|
||||
raise "No such middleware to insert after: #{index.inspect}" unless i
|
||||
insert(i + 1, *args, &block)
|
||||
index = assert_index(index, :after)
|
||||
insert(index + 1, *args, &block)
|
||||
end
|
||||
|
||||
def swap(target, *args, &block)
|
||||
@ -79,5 +78,13 @@ def build(app = nil, &block)
|
||||
raise "MiddlewareStack#build requires an app" unless app
|
||||
reverse.inject(app) { |a, e| e.build(a) }
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def assert_index(index, where)
|
||||
i = index.is_a?(Integer) ? index : self.index(index)
|
||||
raise "No such middleware to insert #{where}: #{index.inspect}" unless i
|
||||
i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,5 @@
|
||||
require 'active_support/core_ext/object/to_param'
|
||||
require 'active_support/core_ext/regexp'
|
||||
require 'action_controller/polymorphic_routes'
|
||||
|
||||
module ActionDispatch
|
||||
# = Routing
|
||||
@ -217,13 +216,14 @@ module Routing
|
||||
autoload :Route, 'action_dispatch/routing/route'
|
||||
autoload :RouteSet, 'action_dispatch/routing/route_set'
|
||||
autoload :UrlFor, 'action_dispatch/routing/url_for'
|
||||
autoload :PolymorphicRoutes, 'action_dispatch/routing/polymorphic_routes'
|
||||
|
||||
SEPARATORS = %w( / . ? ) #:nodoc:
|
||||
HTTP_METHODS = [:get, :head, :post, :put, :delete, :options] #:nodoc:
|
||||
|
||||
# A helper module to hold URL related helpers.
|
||||
module Helpers #:nodoc:
|
||||
include ActionController::PolymorphicRoutes
|
||||
include PolymorphicRoutes
|
||||
end
|
||||
end
|
||||
end
|
||||
|
186
actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
Normal file
186
actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
Normal file
@ -0,0 +1,186 @@
|
||||
module ActionDispatch
|
||||
module Routing
|
||||
# Polymorphic URL helpers are methods for smart resolution to a named route call when
|
||||
# given an Active Record model instance. They are to be used in combination with
|
||||
# ActionController::Resources.
|
||||
#
|
||||
# These methods are useful when you want to generate correct URL or path to a RESTful
|
||||
# resource without having to know the exact type of the record in question.
|
||||
#
|
||||
# Nested resources and/or namespaces are also supported, as illustrated in the example:
|
||||
#
|
||||
# polymorphic_url([:admin, @article, @comment])
|
||||
#
|
||||
# results in:
|
||||
#
|
||||
# admin_article_comment_url(@article, @comment)
|
||||
#
|
||||
# == Usage within the framework
|
||||
#
|
||||
# Polymorphic URL helpers are used in a number of places throughout the Rails framework:
|
||||
#
|
||||
# * <tt>url_for</tt>, so you can use it with a record as the argument, e.g.
|
||||
# <tt>url_for(@article)</tt>;
|
||||
# * ActionView::Helpers::FormHelper uses <tt>polymorphic_path</tt>, so you can write
|
||||
# <tt>form_for(@article)</tt> without having to specify <tt>:url</tt> parameter for the form
|
||||
# action;
|
||||
# * <tt>redirect_to</tt> (which, in fact, uses <tt>url_for</tt>) so you can write
|
||||
# <tt>redirect_to(post)</tt> in your controllers;
|
||||
# * ActionView::Helpers::AtomFeedHelper, so you don't have to explicitly specify URLs
|
||||
# for feed entries.
|
||||
#
|
||||
# == Prefixed polymorphic helpers
|
||||
#
|
||||
# In addition to <tt>polymorphic_url</tt> and <tt>polymorphic_path</tt> methods, a
|
||||
# number of prefixed helpers are available as a shorthand to <tt>:action => "..."</tt>
|
||||
# in options. Those are:
|
||||
#
|
||||
# * <tt>edit_polymorphic_url</tt>, <tt>edit_polymorphic_path</tt>
|
||||
# * <tt>new_polymorphic_url</tt>, <tt>new_polymorphic_path</tt>
|
||||
#
|
||||
# Example usage:
|
||||
#
|
||||
# edit_polymorphic_path(@post) # => "/posts/1/edit"
|
||||
# polymorphic_path(@post, :format => :pdf) # => "/posts/1.pdf"
|
||||
module PolymorphicRoutes
|
||||
# Constructs a call to a named RESTful route for the given record and returns the
|
||||
# resulting URL string. For example:
|
||||
#
|
||||
# # calls post_url(post)
|
||||
# polymorphic_url(post) # => "http://example.com/posts/1"
|
||||
# polymorphic_url([blog, post]) # => "http://example.com/blogs/1/posts/1"
|
||||
# polymorphic_url([:admin, blog, post]) # => "http://example.com/admin/blogs/1/posts/1"
|
||||
# polymorphic_url([user, :blog, post]) # => "http://example.com/users/1/blog/posts/1"
|
||||
# polymorphic_url(Comment) # => "http://example.com/comments"
|
||||
#
|
||||
# ==== Options
|
||||
#
|
||||
# * <tt>:action</tt> - Specifies the action prefix for the named route:
|
||||
# <tt>:new</tt> or <tt>:edit</tt>. Default is no prefix.
|
||||
# * <tt>:routing_type</tt> - Allowed values are <tt>:path</tt> or <tt>:url</tt>.
|
||||
# Default is <tt>:url</tt>.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# # an Article record
|
||||
# polymorphic_url(record) # same as article_url(record)
|
||||
#
|
||||
# # a Comment record
|
||||
# polymorphic_url(record) # same as comment_url(record)
|
||||
#
|
||||
# # it recognizes new records and maps to the collection
|
||||
# record = Comment.new
|
||||
# polymorphic_url(record) # same as comments_url()
|
||||
#
|
||||
# # the class of a record will also map to the collection
|
||||
# polymorphic_url(Comment) # same as comments_url()
|
||||
#
|
||||
def polymorphic_url(record_or_hash_or_array, options = {})
|
||||
if record_or_hash_or_array.kind_of?(Array)
|
||||
record_or_hash_or_array = record_or_hash_or_array.compact
|
||||
record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1
|
||||
end
|
||||
|
||||
record = extract_record(record_or_hash_or_array)
|
||||
record = record.to_model if record.respond_to?(:to_model)
|
||||
|
||||
args = case record_or_hash_or_array
|
||||
when Hash; [ record_or_hash_or_array ]
|
||||
when Array; record_or_hash_or_array.dup
|
||||
else [ record_or_hash_or_array ]
|
||||
end
|
||||
|
||||
inflection = if options[:action].to_s == "new"
|
||||
args.pop
|
||||
:singular
|
||||
elsif (record.respond_to?(:persisted?) && !record.persisted?)
|
||||
args.pop
|
||||
:plural
|
||||
elsif record.is_a?(Class)
|
||||
args.pop
|
||||
:plural
|
||||
else
|
||||
:singular
|
||||
end
|
||||
|
||||
args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
|
||||
named_route = build_named_route_call(record_or_hash_or_array, inflection, options)
|
||||
|
||||
url_options = options.except(:action, :routing_type)
|
||||
unless url_options.empty?
|
||||
args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options
|
||||
end
|
||||
|
||||
send(named_route, *args)
|
||||
end
|
||||
|
||||
# Returns the path component of a URL for the given record. It uses
|
||||
# <tt>polymorphic_url</tt> with <tt>:routing_type => :path</tt>.
|
||||
def polymorphic_path(record_or_hash_or_array, options = {})
|
||||
polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path))
|
||||
end
|
||||
|
||||
%w(edit new).each do |action|
|
||||
module_eval <<-EOT, __FILE__, __LINE__ + 1
|
||||
def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {})
|
||||
polymorphic_url( # polymorphic_url(
|
||||
record_or_hash, # record_or_hash,
|
||||
options.merge(:action => "#{action}")) # options.merge(:action => "edit"))
|
||||
end # end
|
||||
#
|
||||
def #{action}_polymorphic_path(record_or_hash, options = {}) # def edit_polymorphic_path(record_or_hash, options = {})
|
||||
polymorphic_url( # polymorphic_url(
|
||||
record_or_hash, # record_or_hash,
|
||||
options.merge(:action => "#{action}", :routing_type => :path)) # options.merge(:action => "edit", :routing_type => :path))
|
||||
end # end
|
||||
EOT
|
||||
end
|
||||
|
||||
private
|
||||
def action_prefix(options)
|
||||
options[:action] ? "#{options[:action]}_" : ''
|
||||
end
|
||||
|
||||
def routing_type(options)
|
||||
options[:routing_type] || :url
|
||||
end
|
||||
|
||||
def build_named_route_call(records, inflection, options = {})
|
||||
unless records.is_a?(Array)
|
||||
record = extract_record(records)
|
||||
route = ''
|
||||
else
|
||||
record = records.pop
|
||||
route = records.inject("") do |string, parent|
|
||||
if parent.is_a?(Symbol) || parent.is_a?(String)
|
||||
string << "#{parent}_"
|
||||
else
|
||||
string << ActiveModel::Naming.plural(parent).singularize
|
||||
string << "_"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if record.is_a?(Symbol) || record.is_a?(String)
|
||||
route << "#{record}_"
|
||||
else
|
||||
route << ActiveModel::Naming.plural(record)
|
||||
route = route.singularize if inflection == :singular
|
||||
route << "_"
|
||||
route << "index_" if ActiveModel::Naming.uncountable?(record) && inflection == :plural
|
||||
end
|
||||
|
||||
action_prefix(options) + route + routing_type(options).to_s
|
||||
end
|
||||
|
||||
def extract_record(record_or_hash_or_array)
|
||||
case record_or_hash_or_array
|
||||
when Array; record_or_hash_or_array.last
|
||||
when Hash; record_or_hash_or_array[:id]
|
||||
else record_or_hash_or_array
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -414,7 +414,8 @@ def opts
|
||||
elsif value.is_a?(Array)
|
||||
value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
|
||||
else
|
||||
Rack::Mount::Utils.escape_uri(value.to_param)
|
||||
return nil unless param = value.to_param
|
||||
param.split('/').map { |v| Rack::Mount::Utils.escape_uri(v) }.join("/")
|
||||
end
|
||||
end
|
||||
{:parameterize => parameterize}
|
||||
|
@ -82,6 +82,7 @@ module Routing
|
||||
#
|
||||
module UrlFor
|
||||
extend ActiveSupport::Concern
|
||||
include PolymorphicRoutes
|
||||
|
||||
included do
|
||||
# TODO: with_routing extends @controller with url_helpers, trickling down to including this module which overrides its default_url_options
|
||||
|
@ -1,7 +1,6 @@
|
||||
module ActionDispatch
|
||||
module Assertions
|
||||
autoload :DomAssertions, 'action_dispatch/testing/assertions/dom'
|
||||
autoload :ModelAssertions, 'action_dispatch/testing/assertions/model'
|
||||
autoload :ResponseAssertions, 'action_dispatch/testing/assertions/response'
|
||||
autoload :RoutingAssertions, 'action_dispatch/testing/assertions/routing'
|
||||
autoload :SelectorAssertions, 'action_dispatch/testing/assertions/selector'
|
||||
@ -11,7 +10,6 @@ module Assertions
|
||||
|
||||
included do
|
||||
include DomAssertions
|
||||
include ModelAssertions
|
||||
include ResponseAssertions
|
||||
include RoutingAssertions
|
||||
include SelectorAssertions
|
||||
|
@ -1,19 +0,0 @@
|
||||
module ActionDispatch
|
||||
module Assertions
|
||||
module ModelAssertions
|
||||
# Ensures that the passed record is valid by Active Record standards and
|
||||
# returns any error messages if it is not.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# # assert that a newly created record is valid
|
||||
# model = Model.new
|
||||
# assert_valid(model)
|
||||
#
|
||||
def assert_valid(record)
|
||||
::ActiveSupport::Deprecation.warn("assert_valid is deprecated. Use assert record.valid? instead", caller)
|
||||
assert record.valid?, record.errors.full_messages.join("\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -23,6 +23,7 @@
|
||||
|
||||
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
|
||||
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
|
||||
|
||||
require 'active_support/ruby/shim'
|
||||
require 'active_support/core_ext/class/attribute_accessors'
|
||||
|
||||
|
@ -20,7 +20,6 @@ module Helpers #:nodoc:
|
||||
autoload :NumberHelper
|
||||
autoload :PrototypeHelper
|
||||
autoload :RawOutputHelper
|
||||
autoload :RecordIdentificationHelper
|
||||
autoload :RecordTagHelper
|
||||
autoload :SanitizeHelper
|
||||
autoload :ScriptaculousHelper
|
||||
@ -51,7 +50,6 @@ module Helpers #:nodoc:
|
||||
include NumberHelper
|
||||
include PrototypeHelper
|
||||
include RawOutputHelper
|
||||
include RecordIdentificationHelper
|
||||
include RecordTagHelper
|
||||
include SanitizeHelper
|
||||
include ScriptaculousHelper
|
||||
|
@ -800,7 +800,8 @@ def build_options(selected, options = {})
|
||||
start = options.delete(:start) || 0
|
||||
stop = options.delete(:end) || 59
|
||||
step = options.delete(:step) || 1
|
||||
leading_zeros = options.delete(:leading_zeros).nil? ? true : false
|
||||
options.reverse_merge!({:leading_zeros => true})
|
||||
leading_zeros = options.delete(:leading_zeros)
|
||||
|
||||
select_options = []
|
||||
start.step(stop, step) do |i|
|
||||
|
@ -298,12 +298,12 @@ def form_for(record_or_name_or_array, *args, &proc)
|
||||
object_name = record_or_name_or_array
|
||||
when Array
|
||||
object = record_or_name_or_array.last
|
||||
object_name = options[:as] || ActionController::RecordIdentifier.singular_class_name(object)
|
||||
object_name = options[:as] || ActiveModel::Naming.singular(object)
|
||||
apply_form_for_options!(record_or_name_or_array, options)
|
||||
args.unshift object
|
||||
else
|
||||
object = record_or_name_or_array
|
||||
object_name = options[:as] || ActionController::RecordIdentifier.singular_class_name(object)
|
||||
object_name = options[:as] || ActiveModel::Naming.singular(object)
|
||||
apply_form_for_options!([object], options)
|
||||
args.unshift object
|
||||
end
|
||||
@ -529,7 +529,7 @@ def fields_for(record_or_name_or_array, *args, &block)
|
||||
object = args.first
|
||||
else
|
||||
object = record_or_name_or_array
|
||||
object_name = ActionController::RecordIdentifier.singular_class_name(object)
|
||||
object_name = ActiveModel::Naming.singular(object)
|
||||
end
|
||||
|
||||
builder = options[:builder] || ActionView::Base.default_form_builder
|
||||
@ -1152,11 +1152,11 @@ def fields_for(record_or_name_or_array, *args, &block)
|
||||
end
|
||||
when Array
|
||||
object = record_or_name_or_array.last
|
||||
name = "#{object_name}#{index}[#{ActionController::RecordIdentifier.singular_class_name(object)}]"
|
||||
name = "#{object_name}#{index}[#{ActiveModel::Naming.singular(object)}]"
|
||||
args.unshift(object)
|
||||
else
|
||||
object = record_or_name_or_array
|
||||
name = "#{object_name}#{index}[#{ActionController::RecordIdentifier.singular_class_name(object)}]"
|
||||
name = "#{object_name}#{index}[#{ActiveModel::Naming.singular(object)}]"
|
||||
args.unshift(object)
|
||||
end
|
||||
|
||||
|
@ -447,7 +447,7 @@ def option_groups_from_collection_for_select(collection, group_method, group_lab
|
||||
# wrap the output in an appropriate <tt><select></tt> tag.
|
||||
def grouped_options_for_select(grouped_options, selected_key = nil, prompt = nil)
|
||||
body = ''
|
||||
body << content_tag(:option, prompt, :value => "") if prompt
|
||||
body << content_tag(:option, prompt, { :value => "" }, true) if prompt
|
||||
|
||||
grouped_options = grouped_options.sort if grouped_options.is_a?(Hash)
|
||||
|
||||
@ -593,11 +593,11 @@ def to_time_zone_select_tag(priority_zones, options, html_options)
|
||||
private
|
||||
def add_options(option_tags, options, value = nil)
|
||||
if options[:include_blank]
|
||||
option_tags = "<option value=\"\">#{options[:include_blank] if options[:include_blank].kind_of?(String)}</option>\n" + option_tags
|
||||
option_tags = "<option value=\"\">#{html_escape(options[:include_blank]) if options[:include_blank].kind_of?(String)}</option>\n" + option_tags
|
||||
end
|
||||
if value.blank? && options[:prompt]
|
||||
prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('helpers.select.prompt', :default => 'Please select')
|
||||
option_tags = "<option value=\"\">#{prompt}</option>\n" + option_tags
|
||||
option_tags = "<option value=\"\">#{html_escape(prompt)}</option>\n" + option_tags
|
||||
end
|
||||
option_tags.html_safe
|
||||
end
|
||||
|
@ -139,7 +139,7 @@ def remote_function(options)
|
||||
function = "if (#{options[:condition]}) { #{function}; }" if options[:condition]
|
||||
function = "if (confirm('#{escape_javascript(options[:confirm])}')) { #{function}; }" if options[:confirm]
|
||||
|
||||
return function
|
||||
return function.html_safe
|
||||
end
|
||||
|
||||
# All the methods were moved to GeneratorMethods so that
|
||||
|
@ -1,23 +0,0 @@
|
||||
module ActionView
|
||||
# = Action View Record Identification Helpers
|
||||
#
|
||||
# See ActionController::RecordIdentifier for documentation on these methods.
|
||||
module Helpers
|
||||
module RecordIdentificationHelper
|
||||
# See ActionController::RecordIdentifier.partial_path -- this is just a delegate to that for convenient access in the view.
|
||||
def partial_path(*args, &block)
|
||||
ActionController::RecordIdentifier.partial_path(*args, &block)
|
||||
end
|
||||
|
||||
# See ActionController::RecordIdentifier.dom_class -- this is just a delegate to that for convenient access in the view.
|
||||
def dom_class(*args, &block)
|
||||
ActionController::RecordIdentifier.dom_class(*args, &block)
|
||||
end
|
||||
|
||||
# See ActionController::RecordIdentifier.dom_id -- this is just a delegate to that for convenient access in the view.
|
||||
def dom_id(*args, &block)
|
||||
ActionController::RecordIdentifier.dom_id(*args, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,7 +1,11 @@
|
||||
require 'action_controller/record_identifier'
|
||||
|
||||
module ActionView
|
||||
# = Action View Record Tag Helpers
|
||||
module Helpers
|
||||
module RecordTagHelper
|
||||
include ActionController::RecordIdentifier
|
||||
|
||||
# Produces a wrapper DIV element with id and class parameters that
|
||||
# relate to the specified Active Record object. Usage example:
|
||||
#
|
||||
|
@ -398,7 +398,7 @@ def link_to_unless_current(name, options = {}, html_options = {}, &block)
|
||||
def link_to_unless(condition, name, options = {}, html_options = {}, &block)
|
||||
if condition
|
||||
if block_given?
|
||||
block.arity <= 1 ? yield(name) : yield(name, options, html_options)
|
||||
block.arity <= 1 ? capture(name, &block) : capture(name, options, html_options, &block)
|
||||
else
|
||||
name
|
||||
end
|
||||
|
@ -37,7 +37,7 @@ module Behavior
|
||||
include ActionController::TemplateAssertions
|
||||
include ActionView::Context
|
||||
|
||||
include ActionController::PolymorphicRoutes
|
||||
include ActionDispatch::Routing::PolymorphicRoutes
|
||||
include ActionController::RecordIdentifier
|
||||
|
||||
include AbstractController::Helpers
|
||||
|
@ -482,21 +482,6 @@ def test_redirected_to_with_nested_controller
|
||||
assert_redirected_to :controller => 'admin/user'
|
||||
end
|
||||
|
||||
def test_assert_valid
|
||||
get :get_valid_record
|
||||
assert_deprecated { assert_valid assigns('record') }
|
||||
end
|
||||
|
||||
def test_assert_valid_failing
|
||||
get :get_invalid_record
|
||||
|
||||
begin
|
||||
assert_deprecated { assert_valid assigns('record') }
|
||||
assert false
|
||||
rescue ActiveSupport::TestCase::Assertion => e
|
||||
end
|
||||
end
|
||||
|
||||
def test_assert_response_uses_exception_message
|
||||
@controller = AssertResponseWithUnexpectedErrorController.new
|
||||
get :index
|
||||
|
@ -26,20 +26,6 @@ def name
|
||||
end
|
||||
end
|
||||
|
||||
class Comment::Nested < Comment; end
|
||||
|
||||
class Test::Unit::TestCase
|
||||
protected
|
||||
def comments_url
|
||||
'http://www.example.com/comments'
|
||||
end
|
||||
|
||||
def comment_url(comment)
|
||||
"http://www.example.com/comments/#{comment.id}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class RecordIdentifierTest < Test::Unit::TestCase
|
||||
include ActionController::RecordIdentifier
|
||||
|
||||
@ -76,30 +62,4 @@ def test_dom_class
|
||||
def test_dom_class_with_prefix
|
||||
assert_equal "custom_prefix_#{@singular}", dom_class(@record, :custom_prefix)
|
||||
end
|
||||
|
||||
def test_singular_class_name
|
||||
assert_equal @singular, singular_class_name(@record)
|
||||
end
|
||||
|
||||
def test_singular_class_name_for_class
|
||||
assert_equal @singular, singular_class_name(@klass)
|
||||
end
|
||||
|
||||
def test_plural_class_name
|
||||
assert_equal @plural, plural_class_name(@record)
|
||||
end
|
||||
|
||||
def test_plural_class_name_for_class
|
||||
assert_equal @plural, plural_class_name(@klass)
|
||||
end
|
||||
|
||||
def test_uncountable
|
||||
assert_equal true, uncountable?(@uncountable)
|
||||
assert_equal false, uncountable?(@klass)
|
||||
end
|
||||
|
||||
private
|
||||
def method_missing(method, *args)
|
||||
RecordIdentifier.send(method, *args)
|
||||
end
|
||||
end
|
||||
|
@ -79,6 +79,14 @@ class ResourceUnavailableToRescueAsString < StandardError
|
||||
render :text => 'no way'
|
||||
end
|
||||
|
||||
rescue_from ActionView::TemplateError do
|
||||
render :text => 'action_view templater error'
|
||||
end
|
||||
|
||||
rescue_from IOError do
|
||||
render :text => 'io error'
|
||||
end
|
||||
|
||||
before_filter(:only => :before_filter_raises) { raise 'umm nice' }
|
||||
|
||||
def before_filter_raises
|
||||
@ -141,6 +149,14 @@ def resource_unavailable_raise_as_string
|
||||
|
||||
def missing_template
|
||||
end
|
||||
|
||||
def io_error_in_view
|
||||
raise ActionView::TemplateError.new(nil, {}, IOError.new('this is io error'))
|
||||
end
|
||||
|
||||
def zero_division_error_in_view
|
||||
raise ActionView::TemplateError.new(nil, {}, ZeroDivisionError.new('this is zero division error'))
|
||||
end
|
||||
|
||||
protected
|
||||
def deny_access
|
||||
@ -228,6 +244,17 @@ def test_exception_in_parent_controller
|
||||
end
|
||||
|
||||
class RescueControllerTest < ActionController::TestCase
|
||||
|
||||
def test_io_error_in_view
|
||||
get :io_error_in_view
|
||||
assert_equal 'io error', @response.body
|
||||
end
|
||||
|
||||
def test_zero_division_error_in_view
|
||||
get :zero_division_error_in_view
|
||||
assert_equal 'action_view templater error', @response.body
|
||||
end
|
||||
|
||||
def test_rescue_handler
|
||||
get :not_authorized
|
||||
assert_response :forbidden
|
||||
|
@ -461,6 +461,13 @@ def test_assert_routing_with_method
|
||||
def test_assert_routing_in_module
|
||||
assert_routing 'admin/user', :controller => 'admin/user', :action => 'index'
|
||||
end
|
||||
|
||||
def test_assert_routing_with_glob
|
||||
with_routing do |set|
|
||||
set.draw { |map| match('*path' => "pages#show") }
|
||||
assert_routing('/company/about', { :controller => 'pages', :action => 'show', :path => 'company/about' })
|
||||
end
|
||||
end
|
||||
|
||||
def test_params_passing
|
||||
get :test_params, :page => {:name => "Page name", :month => '4', :year => '2004', :day => '6'}
|
||||
|
@ -66,6 +66,16 @@ def setup
|
||||
assert_equal BazMiddleware, @stack[0].klass
|
||||
end
|
||||
|
||||
test "raise an error on invalid index" do
|
||||
assert_raise RuntimeError do
|
||||
@stack.insert("HiyaMiddleware", BazMiddleware)
|
||||
end
|
||||
|
||||
assert_raise RuntimeError do
|
||||
@stack.insert_after("HiyaMiddleware", BazMiddleware)
|
||||
end
|
||||
end
|
||||
|
||||
test "lazy evaluates middleware class" do
|
||||
assert_difference "@stack.size" do
|
||||
@stack.use "MiddlewareStackTest::BazMiddleware"
|
||||
|
@ -392,19 +392,19 @@ class RequestTest < ActiveSupport::TestCase
|
||||
[{'baz'=>[{'foo'=>'baz'}, "1"]}, {'baz'=>[{'foo'=>'[FILTERED]'}, "1"]}, [/foo/]]]
|
||||
|
||||
test_hashes.each do |before_filter, after_filter, filter_words|
|
||||
request = stub_request('action_dispatch.parameter_filter' => filter_words)
|
||||
assert_equal after_filter, request.send(:process_parameter_filter, before_filter)
|
||||
parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words)
|
||||
assert_equal after_filter, parameter_filter.filter(before_filter)
|
||||
|
||||
filter_words << 'blah'
|
||||
filter_words << lambda { |key, value|
|
||||
value.reverse! if key =~ /bargain/
|
||||
}
|
||||
|
||||
request = stub_request('action_dispatch.parameter_filter' => filter_words)
|
||||
parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words)
|
||||
before_filter['barg'] = {'bargain'=>'gain', 'blah'=>'bar', 'bar'=>{'bargain'=>{'blah'=>'foo'}}}
|
||||
after_filter['barg'] = {'bargain'=>'niag', 'blah'=>'[FILTERED]', 'bar'=>{'bargain'=>{'blah'=>'[FILTERED]'}}}
|
||||
|
||||
assert_equal after_filter, request.send(:process_parameter_filter, before_filter)
|
||||
assert_equal after_filter, parameter_filter.filter(before_filter)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -44,7 +44,12 @@ def raise_data_overflow
|
||||
session[:foo] = 'bye!' * 1024
|
||||
head :ok
|
||||
end
|
||||
|
||||
|
||||
def change_session_id
|
||||
request.session_options[:id] = nil
|
||||
get_session_id
|
||||
end
|
||||
|
||||
def rescue_action(e) raise end
|
||||
end
|
||||
|
||||
@ -212,6 +217,19 @@ def test_persistent_session_id
|
||||
end
|
||||
end
|
||||
|
||||
def test_setting_session_id_to_nil_is_respected
|
||||
with_test_route_set do
|
||||
cookies[SessionKey] = SignedBar
|
||||
|
||||
get "/get_session_id"
|
||||
sid = response.body
|
||||
assert_equal sid.size, 36
|
||||
|
||||
get "/change_session_id"
|
||||
assert_not_equal sid, response.body
|
||||
end
|
||||
end
|
||||
|
||||
def test_session_store_with_expire_after
|
||||
with_test_route_set(:expire_after => 5.hours) do
|
||||
# First request accesses the session
|
||||
|
@ -210,6 +210,12 @@ def test_grouped_options_for_select_returns_html_safe_string
|
||||
assert grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]]).html_safe?
|
||||
end
|
||||
|
||||
def test_grouped_options_for_select_with_prompt_returns_html_escaped_string
|
||||
assert_dom_equal(
|
||||
"<option value=\"\"><Choose One></option><optgroup label=\"Hats\"><option value=\"Baseball Cap\">Baseball Cap</option>\n<option value=\"Cowboy Hat\">Cowboy Hat</option></optgroup>",
|
||||
grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], nil, '<Choose One>'))
|
||||
end
|
||||
|
||||
def test_optgroups_with_with_options_with_hash
|
||||
assert_dom_equal(
|
||||
"<optgroup label=\"Europe\"><option value=\"Denmark\">Denmark</option>\n<option value=\"Germany\">Germany</option></optgroup><optgroup label=\"North America\"><option value=\"United States\">United States</option>\n<option value=\"Canada\">Canada</option></optgroup>",
|
||||
@ -367,6 +373,15 @@ def test_select_with_blank_as_string
|
||||
)
|
||||
end
|
||||
|
||||
def test_select_with_blank_as_string_escaped
|
||||
@post = Post.new
|
||||
@post.category = "<mus>"
|
||||
assert_dom_equal(
|
||||
"<select id=\"post_category\" name=\"post[category]\"><option value=\"\"><None></option>\n<option value=\"abe\">abe</option>\n<option value=\"<mus>\" selected=\"selected\"><mus></option>\n<option value=\"hest\">hest</option></select>",
|
||||
select("post", "category", %w( abe <mus> hest), :include_blank => '<None>')
|
||||
)
|
||||
end
|
||||
|
||||
def test_select_with_default_prompt
|
||||
@post = Post.new
|
||||
@post.category = ""
|
||||
@ -394,6 +409,14 @@ def test_select_with_given_prompt
|
||||
)
|
||||
end
|
||||
|
||||
def test_select_with_given_prompt_escaped
|
||||
@post = Post.new
|
||||
assert_dom_equal(
|
||||
"<select id=\"post_category\" name=\"post[category]\"><option value=\"\"><The prompt></option>\n<option value=\"abe\">abe</option>\n<option value=\"<mus>\"><mus></option>\n<option value=\"hest\">hest</option></select>",
|
||||
select("post", "category", %w( abe <mus> hest), :prompt => '<The prompt>')
|
||||
)
|
||||
end
|
||||
|
||||
def test_select_with_prompt_and_blank
|
||||
@post = Post.new
|
||||
@post.category = ""
|
||||
|
@ -104,6 +104,12 @@ def test_update_page_tag_with_html_options
|
||||
assert_equal javascript_tag(create_generator(&block).to_s, {:defer => 'true'}), update_page_tag({:defer => 'true'}, &block)
|
||||
end
|
||||
|
||||
def test_remote_function
|
||||
res = remote_function(:url => authors_path, :with => "'author[name]='+$F('author_name')+'&author[dob]='+$F('author_dob')")
|
||||
assert_equal "new Ajax.Request('/authors', {asynchronous:true, evalScripts:true, parameters:'author[name]='+$F('author_name')+'&author[dob]='+$F('author_dob')})", res
|
||||
assert res.html_safe?
|
||||
end
|
||||
|
||||
protected
|
||||
def author_path(record)
|
||||
"/authors/#{record.id}"
|
||||
|
@ -1,3 +1,8 @@
|
||||
*Rails 3.0.0 [Release Candidate] (unreleased)*
|
||||
|
||||
* Added ActiveModel::MassAssignmentSecurity [Eric Chapweske, Josh Kalderimis]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 4] (June 8th, 2010)*
|
||||
|
||||
* JSON supports a custom root option: to_json(:root => 'custom') #4515 [Jatinder Singh]
|
||||
|
@ -32,7 +32,7 @@ Rake::RDocTask.new do |rdoc|
|
||||
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
||||
rdoc.options << '--charset' << 'utf-8'
|
||||
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
|
||||
rdoc.rdoc_files.include("README", "CHANGELOG")
|
||||
rdoc.rdoc_files.include("README.rdoc", "CHANGELOG")
|
||||
rdoc.rdoc_files.include("lib/**/*.rb")
|
||||
end
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
s.homepage = 'http://www.rubyonrails.org'
|
||||
s.rubyforge_project = 'activemodel'
|
||||
|
||||
s.files = Dir['CHANGELOG', 'MIT-LICENSE', 'README', 'lib/**/*']
|
||||
s.files = Dir['CHANGELOG', 'MIT-LICENSE', 'README.rdoc', 'lib/**/*']
|
||||
s.require_path = 'lib'
|
||||
|
||||
s.has_rdoc = true
|
||||
|
@ -57,6 +57,35 @@ module Naming
|
||||
def model_name
|
||||
@_model_name ||= ActiveModel::Name.new(self)
|
||||
end
|
||||
|
||||
# Returns the plural class name of a record or class. Examples:
|
||||
#
|
||||
# ActiveModel::Naming.plural(post) # => "posts"
|
||||
# ActiveModel::Naming.plural(Highrise::Person) # => "highrise_people"
|
||||
def self.plural(record_or_class)
|
||||
model_name_from_record_or_class(record_or_class).plural
|
||||
end
|
||||
|
||||
# Returns the singular class name of a record or class. Examples:
|
||||
#
|
||||
# ActiveModel::Naming.singular(post) # => "post"
|
||||
# ActiveModel::Naming.singular(Highrise::Person) # => "highrise_person"
|
||||
def self.singular(record_or_class)
|
||||
model_name_from_record_or_class(record_or_class).singular
|
||||
end
|
||||
|
||||
# Identifies whether the class name of a record or class is uncountable. Examples:
|
||||
#
|
||||
# ActiveModel::Naming.uncountable?(Sheep) # => true
|
||||
# ActiveModel::Naming.uncountable?(Post) => false
|
||||
def self.uncountable?(record_or_class)
|
||||
plural(record_or_class) == singular(record_or_class)
|
||||
end
|
||||
|
||||
private
|
||||
def self.model_name_from_record_or_class(record_or_class)
|
||||
(record_or_class.is_a?(Class) ? record_or_class : record_or_class.class).model_name
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,4 +1,6 @@
|
||||
require 'cases/helper'
|
||||
require 'models/contact'
|
||||
require 'models/sheep'
|
||||
require 'models/track_back'
|
||||
|
||||
class NamingTest < ActiveModel::TestCase
|
||||
@ -26,3 +28,40 @@ def test_partial_path
|
||||
assert_equal 'post/track_backs/track_back', @model_name.partial_path
|
||||
end
|
||||
end
|
||||
|
||||
class NamingHelpersTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@klass = Contact
|
||||
@record = @klass.new
|
||||
@singular = 'contact'
|
||||
@plural = 'contacts'
|
||||
@uncountable = Sheep
|
||||
end
|
||||
|
||||
def test_singular
|
||||
assert_equal @singular, singular(@record)
|
||||
end
|
||||
|
||||
def test_singular_for_class
|
||||
assert_equal @singular, singular(@klass)
|
||||
end
|
||||
|
||||
def test_plural
|
||||
assert_equal @plural, plural(@record)
|
||||
end
|
||||
|
||||
def test_plural_for_class
|
||||
assert_equal @plural, plural(@klass)
|
||||
end
|
||||
|
||||
def test_uncountable
|
||||
assert uncountable?(@uncountable), "Expected 'sheep' to be uncoutable"
|
||||
assert !uncountable?(@klass), "Expected 'contact' to be countable"
|
||||
end
|
||||
|
||||
private
|
||||
def method_missing(method, *args)
|
||||
ActiveModel::Naming.send(method, *args)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
class Contact
|
||||
extend ActiveModel::Naming
|
||||
include ActiveModel::Conversion
|
||||
|
||||
attr_accessor :id, :name, :age, :created_at, :awesome, :preferences
|
||||
|
4
activemodel/test/models/sheep.rb
Normal file
4
activemodel/test/models/sheep.rb
Normal file
@ -0,0 +1,4 @@
|
||||
class Sheep
|
||||
extend ActiveModel::Naming
|
||||
end
|
||||
|
@ -1,5 +1,7 @@
|
||||
*Rails 3.0.0 [RC1] (unreleased)*
|
||||
|
||||
* Changed update_attribute to not run callbacks and update the record directly in the database [Neeraj Singh]
|
||||
|
||||
* Add scoping and unscoped as the syntax to replace the old with_scope and with_exclusive_scope [José Valim]
|
||||
|
||||
* New rake task, db:migrate:status, displays status of migrations #4947 [Kevin Skoglund]
|
||||
|
@ -309,28 +309,13 @@ Admit the Database:
|
||||
|
||||
== Download
|
||||
|
||||
The latest version of Active Record can be found at
|
||||
The latest version of Active Record can be installed with Rubygems:
|
||||
|
||||
* http://rubyforge.org/project/showfiles.php?group_id=182
|
||||
* gem install activerecord
|
||||
|
||||
Documentation can be found at
|
||||
|
||||
* http://ar.rubyonrails.com
|
||||
|
||||
|
||||
== Installation
|
||||
|
||||
The prefered method of installing Active Record is through its GEM file. You'll need to have
|
||||
RubyGems[http://rubygems.rubyforge.org/wiki/wiki.pl] installed for that, though. If you have,
|
||||
then use:
|
||||
|
||||
% [sudo] gem install activerecord-1.10.0.gem
|
||||
|
||||
You can also install Active Record the old-fashioned way with the following command:
|
||||
|
||||
% [sudo] ruby install.rb
|
||||
|
||||
from its distribution directory.
|
||||
* http://api.rubyonrails.org
|
||||
|
||||
|
||||
== License
|
@ -172,7 +172,7 @@ Rake::RDocTask.new { |rdoc|
|
||||
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
||||
rdoc.options << '--charset' << 'utf-8'
|
||||
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
|
||||
rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
|
||||
rdoc.rdoc_files.include('README.rdoc', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
rdoc.rdoc_files.exclude('lib/active_record/vendor/*')
|
||||
rdoc.rdoc_files.include('dev-utils/*.rb')
|
||||
|
@ -14,12 +14,12 @@
|
||||
s.homepage = 'http://www.rubyonrails.org'
|
||||
s.rubyforge_project = 'activerecord'
|
||||
|
||||
s.files = Dir['CHANGELOG', 'README', 'examples/**/*', 'lib/**/*']
|
||||
s.files = Dir['CHANGELOG', 'README.rdoc', 'examples/**/*', 'lib/**/*']
|
||||
s.require_path = 'lib'
|
||||
|
||||
s.has_rdoc = true
|
||||
s.extra_rdoc_files = %w( README )
|
||||
s.rdoc_options.concat ['--main', 'README']
|
||||
s.extra_rdoc_files = %w( README.rdoc )
|
||||
s.rdoc_options.concat ['--main', 'README.rdoc']
|
||||
|
||||
s.add_dependency('activesupport', version)
|
||||
s.add_dependency('activemodel', version)
|
||||
|
@ -1,30 +0,0 @@
|
||||
require 'rbconfig'
|
||||
require 'find'
|
||||
require 'ftools'
|
||||
|
||||
include Config
|
||||
|
||||
# this was adapted from rdoc's install.rb by ways of Log4r
|
||||
|
||||
$sitedir = CONFIG["sitelibdir"]
|
||||
unless $sitedir
|
||||
version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
|
||||
$libdir = File.join(CONFIG["libdir"], "ruby", version)
|
||||
$sitedir = $:.find {|x| x =~ /site_ruby/ }
|
||||
if !$sitedir
|
||||
$sitedir = File.join($libdir, "site_ruby")
|
||||
elsif $sitedir !~ Regexp.quote(version)
|
||||
$sitedir = File.join($sitedir, version)
|
||||
end
|
||||
end
|
||||
|
||||
# the actual gruntwork
|
||||
Dir.chdir("lib")
|
||||
|
||||
Find.find("active_record", "active_record.rb") { |f|
|
||||
if f[-3..-1] == ".rb"
|
||||
File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
|
||||
else
|
||||
File::makedirs(File.join($sitedir, *f.split(/\//)))
|
||||
end
|
||||
}
|
@ -112,13 +112,13 @@ def preload_one_association(records, association, preload_options={})
|
||||
# Not all records have the same class, so group then preload
|
||||
# group on the reflection itself so that if various subclass share the same association then we do not split them
|
||||
# unnecessarily
|
||||
records.group_by {|record| class_to_reflection[record.class] ||= record.class.reflections[association]}.each do |reflection, records|
|
||||
records.group_by { |record| class_to_reflection[record.class] ||= record.class.reflections[association]}.each do |reflection, _records|
|
||||
raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?" unless reflection
|
||||
|
||||
# 'reflection.macro' can return 'belongs_to', 'has_many', etc. Thus,
|
||||
# the following could call 'preload_belongs_to_association',
|
||||
# 'preload_has_many_association', etc.
|
||||
send("preload_#{reflection.macro}_association", records, reflection, preload_options)
|
||||
send("preload_#{reflection.macro}_association", _records, reflection, preload_options)
|
||||
end
|
||||
end
|
||||
|
||||
@ -378,7 +378,7 @@ def find_associated_records(ids, reflection, preload_options)
|
||||
:order => preload_options[:order] || options[:order]
|
||||
}
|
||||
|
||||
reflection.klass.unscoped.apply_finder_options(find_options).to_a
|
||||
reflection.klass.scoped.apply_finder_options(find_options).to_a
|
||||
end
|
||||
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
require 'active_support/core_ext/module/delegation'
|
||||
require 'active_support/core_ext/object/blank'
|
||||
require 'active_support/core_ext/string/conversions'
|
||||
require 'active_support/core_ext/module/remove_method'
|
||||
|
||||
module ActiveRecord
|
||||
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
|
||||
@ -1354,7 +1355,7 @@ def join_table_name(first_table_name, second_table_name)
|
||||
end
|
||||
|
||||
def association_accessor_methods(reflection, association_proxy_class)
|
||||
define_method(reflection.name) do |*params|
|
||||
redefine_method(reflection.name) do |*params|
|
||||
force_reload = params.first unless params.empty?
|
||||
association = association_instance_get(reflection.name)
|
||||
|
||||
@ -1371,12 +1372,12 @@ def association_accessor_methods(reflection, association_proxy_class)
|
||||
association.target.nil? ? nil : association
|
||||
end
|
||||
|
||||
define_method("loaded_#{reflection.name}?") do
|
||||
redefine_method("loaded_#{reflection.name}?") do
|
||||
association = association_instance_get(reflection.name)
|
||||
association && association.loaded?
|
||||
end
|
||||
|
||||
define_method("#{reflection.name}=") do |new_value|
|
||||
|
||||
redefine_method("#{reflection.name}=") do |new_value|
|
||||
association = association_instance_get(reflection.name)
|
||||
|
||||
if association.nil? || association.target != new_value
|
||||
@ -1386,8 +1387,8 @@ def association_accessor_methods(reflection, association_proxy_class)
|
||||
association.replace(new_value)
|
||||
association_instance_set(reflection.name, new_value.nil? ? nil : association)
|
||||
end
|
||||
|
||||
define_method("set_#{reflection.name}_target") do |target|
|
||||
|
||||
redefine_method("set_#{reflection.name}_target") do |target|
|
||||
return if target.nil? and association_proxy_class == BelongsToAssociation
|
||||
association = association_proxy_class.new(self, reflection)
|
||||
association.target = target
|
||||
@ -1396,7 +1397,7 @@ def association_accessor_methods(reflection, association_proxy_class)
|
||||
end
|
||||
|
||||
def collection_reader_method(reflection, association_proxy_class)
|
||||
define_method(reflection.name) do |*params|
|
||||
redefine_method(reflection.name) do |*params|
|
||||
force_reload = params.first unless params.empty?
|
||||
association = association_instance_get(reflection.name)
|
||||
|
||||
@ -1409,8 +1410,8 @@ def collection_reader_method(reflection, association_proxy_class)
|
||||
|
||||
association
|
||||
end
|
||||
|
||||
define_method("#{reflection.name.to_s.singularize}_ids") do
|
||||
|
||||
redefine_method("#{reflection.name.to_s.singularize}_ids") do
|
||||
if send(reflection.name).loaded? || reflection.options[:finder_sql]
|
||||
send(reflection.name).map(&:id)
|
||||
else
|
||||
@ -1430,14 +1431,14 @@ def collection_accessor_methods(reflection, association_proxy_class, writer = tr
|
||||
collection_reader_method(reflection, association_proxy_class)
|
||||
|
||||
if writer
|
||||
define_method("#{reflection.name}=") do |new_value|
|
||||
redefine_method("#{reflection.name}=") do |new_value|
|
||||
# Loads proxy class instance (defined in collection_reader_method) if not already loaded
|
||||
association = send(reflection.name)
|
||||
association.replace(new_value)
|
||||
association
|
||||
end
|
||||
|
||||
define_method("#{reflection.name.to_s.singularize}_ids=") do |new_value|
|
||||
|
||||
redefine_method("#{reflection.name.to_s.singularize}_ids=") do |new_value|
|
||||
ids = (new_value || []).reject { |nid| nid.blank? }.map(&:to_i)
|
||||
send("#{reflection.name}=", reflection.klass.find(ids).index_by(&:id).values_at(*ids))
|
||||
end
|
||||
@ -1445,7 +1446,7 @@ def collection_accessor_methods(reflection, association_proxy_class, writer = tr
|
||||
end
|
||||
|
||||
def association_constructor_method(constructor, reflection, association_proxy_class)
|
||||
define_method("#{constructor}_#{reflection.name}") do |*params|
|
||||
redefine_method("#{constructor}_#{reflection.name}") do |*params|
|
||||
attributees = params.first unless params.empty?
|
||||
replace_existing = params[1].nil? ? true : params[1]
|
||||
association = association_instance_get(reflection.name)
|
||||
@ -1486,8 +1487,8 @@ def add_counter_cache_callbacks(reflection)
|
||||
end
|
||||
|
||||
def add_touch_callbacks(reflection, touch_attribute)
|
||||
method_name = "belongs_to_touch_after_save_or_destroy_for_#{reflection.name}".to_sym
|
||||
define_method(method_name) do
|
||||
method_name = :"belongs_to_touch_after_save_or_destroy_for_#{reflection.name}"
|
||||
redefine_method(method_name) do
|
||||
association = send(reflection.name)
|
||||
|
||||
if touch_attribute == true
|
||||
|
@ -218,9 +218,9 @@ def count(column_name = nil, options = {})
|
||||
# are actually removed from the database, that depends precisely on
|
||||
# +delete_records+. They are in any case removed from the collection.
|
||||
def delete(*records)
|
||||
remove_records(records) do |records, old_records|
|
||||
remove_records(records) do |_records, old_records|
|
||||
delete_records(old_records) if old_records.any?
|
||||
records.each { |record| @target.delete(record) }
|
||||
_records.each { |record| @target.delete(record) }
|
||||
end
|
||||
end
|
||||
|
||||
@ -231,7 +231,7 @@ def delete(*records)
|
||||
# ignoring the +:dependent+ option.
|
||||
def destroy(*records)
|
||||
records = find(records) if records.any? {|record| record.kind_of?(Fixnum) || record.kind_of?(String)}
|
||||
remove_records(records) do |records, old_records|
|
||||
remove_records(records) do |_records, old_records|
|
||||
old_records.each { |record| record.destroy }
|
||||
end
|
||||
|
||||
@ -396,11 +396,12 @@ def load_target
|
||||
if @target.is_a?(Array) && @target.any?
|
||||
@target = find_target.map do |f|
|
||||
i = @target.index(f)
|
||||
t = @target.delete_at(i) if i
|
||||
if t && t.changed?
|
||||
t
|
||||
if i
|
||||
@target.delete_at(i).tap do |t|
|
||||
keys = ["id"] + t.changes.keys + (f.attribute_names - t.attribute_names)
|
||||
t.attributes = f.attributes.except(*keys)
|
||||
end
|
||||
else
|
||||
f.mark_for_destruction if t && t.marked_for_destruction?
|
||||
f
|
||||
end
|
||||
end + @target
|
||||
@ -477,7 +478,14 @@ def add_record_to_target_with_callbacks(record)
|
||||
callback(:before_add, record)
|
||||
yield(record) if block_given?
|
||||
@target ||= [] unless loaded?
|
||||
@target << record unless @reflection.options[:uniq] && @target.include?(record)
|
||||
index = @target.index(record)
|
||||
unless @reflection.options[:uniq] && index
|
||||
if index
|
||||
@target[index] = record
|
||||
else
|
||||
@target << record
|
||||
end
|
||||
end
|
||||
callback(:after_add, record)
|
||||
set_inverse_instance(record, @owner)
|
||||
record
|
||||
|
@ -45,17 +45,23 @@ def insert_record(record, force = true, validate = true)
|
||||
if @reflection.options[:insert_sql]
|
||||
@owner.connection.insert(interpolate_sql(@reflection.options[:insert_sql], record))
|
||||
else
|
||||
relation = Arel::Table.new(@reflection.options[:join_table])
|
||||
relation = Arel::Table.new(@reflection.options[:join_table])
|
||||
timestamps = record_timestamp_columns(record)
|
||||
timezone = record.send(:current_time_from_proper_timezone) if timestamps.any?
|
||||
|
||||
attributes = columns.inject({}) do |attrs, column|
|
||||
case column.name.to_s
|
||||
name = column.name
|
||||
case name.to_s
|
||||
when @reflection.primary_key_name.to_s
|
||||
attrs[relation[column.name]] = owner_quoted_id
|
||||
attrs[relation[name]] = @owner.id
|
||||
when @reflection.association_foreign_key.to_s
|
||||
attrs[relation[column.name]] = record.quoted_id
|
||||
attrs[relation[name]] = record.id
|
||||
when *timestamps
|
||||
attrs[relation[name]] = timezone
|
||||
else
|
||||
if record.has_attribute?(column.name)
|
||||
value = @owner.send(:quote_value, record[column.name], column)
|
||||
attrs[relation[column.name]] = value unless value.nil?
|
||||
if record.has_attribute?(name)
|
||||
value = @owner.send(:quote_value, record[name], column)
|
||||
attrs[relation[name]] = value unless value.nil?
|
||||
end
|
||||
end
|
||||
attrs
|
||||
@ -117,6 +123,14 @@ def create_record(attributes, &block)
|
||||
build_record(attributes, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def record_timestamp_columns(record)
|
||||
if record.record_timestamps
|
||||
record.send(:all_timestamp_attributes).map(&:to_s)
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -199,11 +199,14 @@ def current_savepoint_name
|
||||
|
||||
def log(sql, name)
|
||||
name ||= "SQL"
|
||||
result = nil
|
||||
ActiveSupport::Notifications.instrument("sql.active_record",
|
||||
:sql => sql, :name => name, :connection_id => self.object_id) do
|
||||
@runtime += Benchmark.ms { result = yield }
|
||||
instrumenter = ActiveSupport::Notifications.instrumenter
|
||||
|
||||
result = instrumenter.instrument("sql.active_record",
|
||||
:sql => sql, :name => name, :connection_id => object_id) do
|
||||
yield
|
||||
end
|
||||
@runtime += instrumenter.elapsed
|
||||
|
||||
result
|
||||
rescue Exception => e
|
||||
message = "#{e.class.name}: #{e.message}: #{sql}"
|
||||
|
@ -871,7 +871,7 @@ def setup_fixture_accessors(table_names = nil)
|
||||
table_names.each do |table_name|
|
||||
table_name = table_name.to_s.tr('./', '_')
|
||||
|
||||
define_method(table_name) do |*fixtures|
|
||||
redefine_method(table_name) do |*fixtures|
|
||||
force_reload = fixtures.pop if fixtures.last == true || fixtures.last == :reload
|
||||
|
||||
@fixture_cache[table_name] ||= {}
|
||||
|
@ -6,14 +6,16 @@ def initialize
|
||||
end
|
||||
|
||||
def sql(event)
|
||||
return unless logger.debug?
|
||||
|
||||
name = '%s (%.1fms)' % [event.payload[:name], event.duration]
|
||||
sql = event.payload[:sql].squeeze(' ')
|
||||
|
||||
if odd?
|
||||
name = color(name, :cyan, true)
|
||||
name = color(name, CYAN, true)
|
||||
sql = color(sql, nil, true)
|
||||
else
|
||||
name = color(name, :magenta, true)
|
||||
name = color(name, MAGENTA, true)
|
||||
end
|
||||
|
||||
debug " #{name} #{sql}"
|
||||
@ -29,4 +31,4 @@ def logger
|
||||
end
|
||||
end
|
||||
|
||||
ActiveRecord::LogSubscriber.attach_to :active_record
|
||||
ActiveRecord::LogSubscriber.attach_to :active_record
|
||||
|
@ -26,7 +26,7 @@ module ClassMethods
|
||||
# You can define a \scope that applies to all finders using
|
||||
# ActiveRecord::Base.default_scope.
|
||||
def scoped(options = nil)
|
||||
if options.present?
|
||||
if options
|
||||
scoped.apply_finder_options(options)
|
||||
else
|
||||
current_scoped_methods ? relation.merge(current_scoped_methods) : relation.clone
|
||||
@ -105,7 +105,7 @@ def scope(name, scope_options = {}, &block)
|
||||
extension ? relation.extending(extension) : relation
|
||||
end
|
||||
|
||||
singleton_class.send :define_method, name, &scopes[name]
|
||||
singleton_class.send(:redefine_method, name, &scopes[name])
|
||||
end
|
||||
|
||||
def named_scope(*args, &block)
|
||||
|
@ -112,6 +112,8 @@ def becomes(klass)
|
||||
# * does not work on attr_accessor attributes. The attribute that is being updated must be column name.
|
||||
#
|
||||
def update_attribute(name, value)
|
||||
raise ActiveRecordError, "#{name.to_s} is marked as readonly" if self.class.readonly_attributes.include? name.to_s
|
||||
|
||||
changes = record_update_timestamps || {}
|
||||
|
||||
if name
|
||||
|
@ -22,6 +22,12 @@ class Railtie < Rails::Railtie
|
||||
load "active_record/railties/databases.rake"
|
||||
end
|
||||
|
||||
# When loading console, force ActiveRecord to be loaded to avoid cross
|
||||
# references when loading a constant for the first time.
|
||||
console do
|
||||
ActiveRecord::Base
|
||||
end
|
||||
|
||||
initializer "active_record.initialize_timezone" do
|
||||
ActiveSupport.on_load(:active_record) do
|
||||
self.time_zone_aware_attributes = true
|
||||
|
@ -274,7 +274,7 @@ namespace :db do
|
||||
task :setup => [ 'db:create', 'db:schema:load', 'db:seed' ]
|
||||
|
||||
desc 'Load the seed data from db/seeds.rb'
|
||||
task :seed => :environment do
|
||||
task :seed => 'db:abort_if_pending_migrations' do
|
||||
seed_file = File.join(Rails.root, 'db', 'seeds.rb')
|
||||
load(seed_file) if File.exist?(seed_file)
|
||||
end
|
||||
|
@ -13,14 +13,15 @@ class Relation
|
||||
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to => :to_a
|
||||
delegate :insert, :to => :arel
|
||||
|
||||
attr_reader :table, :klass
|
||||
attr_reader :table, :klass, :loaded
|
||||
attr_accessor :extensions
|
||||
alias :loaded? :loaded
|
||||
|
||||
def initialize(klass, table)
|
||||
@klass, @table = klass, table
|
||||
|
||||
@implicit_readonly = nil
|
||||
@loaded = nil
|
||||
@loaded = false
|
||||
|
||||
SINGLE_VALUE_METHODS.each {|v| instance_variable_set(:"@#{v}_value", nil)}
|
||||
(ASSOCIATION_METHODS + MULTI_VALUE_METHODS).each {|v| instance_variable_set(:"@#{v}_values", [])}
|
||||
@ -292,10 +293,6 @@ def delete(id_or_array)
|
||||
where(@klass.primary_key => id_or_array).delete_all
|
||||
end
|
||||
|
||||
def loaded?
|
||||
@loaded
|
||||
end
|
||||
|
||||
def reload
|
||||
reset
|
||||
to_a # force reload
|
||||
|
@ -294,7 +294,6 @@ def destroy
|
||||
private
|
||||
def get_session(env, sid)
|
||||
Base.silence do
|
||||
sid ||= generate_sid
|
||||
session = find_session(sid)
|
||||
env[SESSION_RECORD_KEY] = session
|
||||
[sid, session.data]
|
||||
|
@ -39,8 +39,9 @@ def create #:nodoc:
|
||||
if record_timestamps
|
||||
current_time = current_time_from_proper_timezone
|
||||
|
||||
write_attribute('created_at', current_time) if respond_to?(:created_at) && created_at.nil?
|
||||
write_attribute('created_on', current_time) if respond_to?(:created_on) && created_on.nil?
|
||||
timestamp_attributes_for_create.each do |column|
|
||||
write_attribute(column.to_s, current_time) if respond_to?(column) && self.send(column).nil?
|
||||
end
|
||||
|
||||
timestamp_attributes_for_update_in_model.each do |column|
|
||||
write_attribute(column.to_s, current_time) if self.send(column).nil?
|
||||
@ -65,7 +66,19 @@ def record_update_timestamps #:nodoc:
|
||||
end
|
||||
|
||||
def timestamp_attributes_for_update_in_model #:nodoc:
|
||||
[:updated_at, :updated_on].select { |elem| respond_to?(elem) }
|
||||
timestamp_attributes_for_update.select { |elem| respond_to?(elem) }
|
||||
end
|
||||
|
||||
def timestamp_attributes_for_update #:nodoc:
|
||||
[:updated_at, :updated_on]
|
||||
end
|
||||
|
||||
def timestamp_attributes_for_create #:nodoc:
|
||||
[:created_at, :created_on]
|
||||
end
|
||||
|
||||
def all_timestamp_attributes #:nodoc:
|
||||
timestamp_attributes_for_update + timestamp_attributes_for_create
|
||||
end
|
||||
|
||||
def current_time_from_proper_timezone #:nodoc:
|
||||
|
@ -101,6 +101,7 @@ def with_real_execute
|
||||
#we need to actually modify some data, so we make execute point to the original method
|
||||
ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
|
||||
alias_method :execute_with_stub, :execute
|
||||
remove_method :execute
|
||||
alias_method :execute, :execute_without_stub
|
||||
end
|
||||
yield
|
||||
|
@ -125,7 +125,7 @@ class OverridingAggregationsTest < ActiveRecord::TestCase
|
||||
class Name; end
|
||||
class DifferentName; end
|
||||
|
||||
class Person < ActiveRecord::Base
|
||||
class Person < ActiveRecord::Base
|
||||
composed_of :composed_of, :mapping => %w(person_first_name first_name)
|
||||
end
|
||||
|
||||
|
@ -28,7 +28,7 @@ def test_schema_define
|
||||
assert_equal 7, ActiveRecord::Migrator::current_version
|
||||
end
|
||||
|
||||
def test_schema_raises_an_error_for_invalid_column_ntype
|
||||
def test_schema_raises_an_error_for_invalid_column_type
|
||||
assert_raise NoMethodError do
|
||||
ActiveRecord::Schema.define(:version => 8) do
|
||||
create_table :vegetables do |t|
|
||||
|
@ -5,8 +5,6 @@
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
require 'models/computer'
|
||||
require 'models/customer'
|
||||
require 'models/order'
|
||||
require 'models/post'
|
||||
require 'models/author'
|
||||
require 'models/tag'
|
||||
|
@ -1,8 +1,6 @@
|
||||
require "cases/helper"
|
||||
require 'models/post'
|
||||
require 'models/comment'
|
||||
require 'models/author'
|
||||
require 'models/category'
|
||||
require 'models/project'
|
||||
require 'models/developer'
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
require 'models/post'
|
||||
require 'models/comment'
|
||||
require 'models/author'
|
||||
require 'models/category'
|
||||
require 'models/categorization'
|
||||
require 'models/company'
|
||||
require 'models/topic'
|
||||
|
@ -2,20 +2,14 @@
|
||||
require 'models/developer'
|
||||
require 'models/project'
|
||||
require 'models/company'
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
require 'models/computer'
|
||||
require 'models/customer'
|
||||
require 'models/order'
|
||||
require 'models/categorization'
|
||||
require 'models/category'
|
||||
require 'models/post'
|
||||
require 'models/author'
|
||||
require 'models/comment'
|
||||
require 'models/tag'
|
||||
require 'models/tagging'
|
||||
require 'models/person'
|
||||
require 'models/reader'
|
||||
require 'models/parrot'
|
||||
require 'models/pirate'
|
||||
require 'models/treasure'
|
||||
@ -24,6 +18,8 @@
|
||||
require 'models/member'
|
||||
require 'models/membership'
|
||||
require 'models/sponsor'
|
||||
require 'models/country'
|
||||
require 'models/treaty'
|
||||
require 'active_support/core_ext/string/conversions'
|
||||
|
||||
class ProjectWithAfterCreateHook < ActiveRecord::Base
|
||||
@ -83,6 +79,55 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
||||
fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
|
||||
:parrots, :pirates, :treasures, :price_estimates, :tags, :taggings
|
||||
|
||||
def setup_data_for_habtm_case
|
||||
ActiveRecord::Base.connection.execute('delete from countries_treaties')
|
||||
|
||||
country = Country.new(:name => 'India')
|
||||
country.country_id = 'c1'
|
||||
country.save!
|
||||
|
||||
treaty = Treaty.new(:name => 'peace')
|
||||
treaty.treaty_id = 't1'
|
||||
country.treaties << treaty
|
||||
end
|
||||
|
||||
def test_should_property_quote_string_primary_keys
|
||||
setup_data_for_habtm_case
|
||||
|
||||
con = ActiveRecord::Base.connection
|
||||
sql = 'select * from countries_treaties'
|
||||
record = con.select_rows(sql).last
|
||||
assert_equal 'c1', record[0]
|
||||
assert_equal 't1', record[1]
|
||||
end
|
||||
|
||||
def test_should_record_timestamp_for_join_table
|
||||
setup_data_for_habtm_case
|
||||
|
||||
con = ActiveRecord::Base.connection
|
||||
sql = 'select * from countries_treaties'
|
||||
record = con.select_rows(sql).last
|
||||
assert_not_nil record[2]
|
||||
assert_not_nil record[3]
|
||||
assert_match %r{\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}}, record[2]
|
||||
assert_match %r{\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}}, record[3]
|
||||
end
|
||||
|
||||
def test_should_record_timestamp_for_join_table_only_if_timestamp_should_be_recorded
|
||||
begin
|
||||
Treaty.record_timestamps = false
|
||||
setup_data_for_habtm_case
|
||||
|
||||
con = ActiveRecord::Base.connection
|
||||
sql = 'select * from countries_treaties'
|
||||
record = con.select_rows(sql).last
|
||||
assert_nil record[2]
|
||||
assert_nil record[3]
|
||||
ensure
|
||||
Treaty.record_timestamps = true
|
||||
end
|
||||
end
|
||||
|
||||
def test_has_and_belongs_to_many
|
||||
david = Developer.find(1)
|
||||
|
||||
|
@ -412,7 +412,7 @@ def test_should_not_try_to_set_inverse_instances_when_the_inverse_is_a_has_many
|
||||
i = interests(:trainspotting)
|
||||
m = i.man
|
||||
assert_not_nil m.interests
|
||||
iz = m.interests.detect {|iz| iz.id == i.id}
|
||||
iz = m.interests.detect { |_iz| _iz.id == i.id}
|
||||
assert_not_nil iz
|
||||
assert_equal i.topic, iz.topic, "Interest topics should be the same before changes to child"
|
||||
i.topic = 'Eating cheese with a spoon'
|
||||
@ -516,7 +516,7 @@ def test_should_not_try_to_set_inverse_instances_when_the_inverse_is_a_has_many
|
||||
i = interests(:llama_wrangling)
|
||||
m = i.polymorphic_man
|
||||
assert_not_nil m.polymorphic_interests
|
||||
iz = m.polymorphic_interests.detect {|iz| iz.id == i.id}
|
||||
iz = m.polymorphic_interests.detect { |_iz| _iz.id == i.id}
|
||||
assert_not_nil iz
|
||||
assert_equal i.topic, iz.topic, "Interest topics should be the same before changes to child"
|
||||
i.topic = 'Eating cheese with a spoon'
|
||||
|
@ -2,11 +2,6 @@
|
||||
require 'models/developer'
|
||||
require 'models/project'
|
||||
require 'models/company'
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
require 'models/computer'
|
||||
require 'models/customer'
|
||||
require 'models/order'
|
||||
require 'models/categorization'
|
||||
require 'models/category'
|
||||
require 'models/post'
|
||||
@ -17,18 +12,31 @@
|
||||
require 'models/person'
|
||||
require 'models/reader'
|
||||
require 'models/parrot'
|
||||
require 'models/pirate'
|
||||
require 'models/treasure'
|
||||
require 'models/price_estimate'
|
||||
require 'models/club'
|
||||
require 'models/member'
|
||||
require 'models/membership'
|
||||
require 'models/sponsor'
|
||||
require 'models/ship_part'
|
||||
require 'models/ship'
|
||||
|
||||
class AssociationsTest < ActiveRecord::TestCase
|
||||
fixtures :accounts, :companies, :developers, :projects, :developers_projects,
|
||||
:computers, :people, :readers
|
||||
|
||||
def test_loading_the_association_target_should_keep_child_records_marked_for_destruction
|
||||
ship = Ship.create!(:name => "The good ship Dollypop")
|
||||
part = ship.parts.create!(:name => "Mast")
|
||||
part.mark_for_destruction
|
||||
ship.parts.send(:load_target)
|
||||
assert ship.parts[0].marked_for_destruction?
|
||||
end
|
||||
|
||||
def test_loading_the_association_target_should_load_most_recent_attributes_for_child_records_marked_for_destruction
|
||||
ship = Ship.create!(:name => "The good ship Dollypop")
|
||||
part = ship.parts.create!(:name => "Mast")
|
||||
part.mark_for_destruction
|
||||
ShipPart.find(part.id).update_attribute(:name, 'Deck')
|
||||
ship.parts.send(:load_target)
|
||||
assert_equal 'Deck', ship.parts[0].name
|
||||
end
|
||||
|
||||
|
||||
def test_include_with_order_works
|
||||
assert_nothing_raised {Account.find(:first, :order => 'id', :include => :firm)}
|
||||
assert_nothing_raised {Account.find(:first, :order => :id, :include => :firm)}
|
||||
|
@ -123,6 +123,14 @@ def test_read_attributes_before_type_cast_on_datetime
|
||||
assert_equal developer.created_at.to_s(:db) , developer.attributes_before_type_cast["created_at"]
|
||||
else
|
||||
assert_equal developer.created_at.to_s(:db) , developer.attributes_before_type_cast["created_at"].to_s(:db)
|
||||
|
||||
developer.created_at = "345643456"
|
||||
assert_equal developer.created_at_before_type_cast, "345643456"
|
||||
assert_equal developer.created_at, nil
|
||||
|
||||
developer.created_at = "2010-03-21T21:23:32+01:00"
|
||||
assert_equal developer.created_at_before_type_cast, "2010-03-21T21:23:32+01:00"
|
||||
assert_equal developer.created_at, Time.parse("2010-03-21T21:23:32+01:00")
|
||||
end
|
||||
end
|
||||
|
||||
@ -1816,8 +1824,8 @@ def test_to_xml_including_methods
|
||||
|
||||
def test_to_xml_with_block
|
||||
value = "Rockin' the block"
|
||||
xml = Company.new.to_xml(:skip_instruct => true) do |xml|
|
||||
xml.tag! "arbitrary-element", value
|
||||
xml = Company.new.to_xml(:skip_instruct => true) do |_xml|
|
||||
_xml.tag! "arbitrary-element", value
|
||||
end
|
||||
assert_equal "<company>", xml.first(9)
|
||||
assert xml.include?(%(<arbitrary-element>#{value}</arbitrary-element>))
|
||||
|
@ -10,7 +10,6 @@
|
||||
require 'models/project'
|
||||
require 'models/developer'
|
||||
require 'models/customer'
|
||||
require 'models/job'
|
||||
|
||||
class DynamicFinderMatchTest < ActiveRecord::TestCase
|
||||
def test_find_no_match
|
||||
|
@ -36,7 +36,7 @@ def test_clean_fixtures
|
||||
fixtures = nil
|
||||
assert_nothing_raised { fixtures = create_fixtures(name) }
|
||||
assert_kind_of(Fixtures, fixtures)
|
||||
fixtures.each { |name, fixture|
|
||||
fixtures.each { |_name, fixture|
|
||||
fixture.each { |key, value|
|
||||
assert_match(MATCH_ATTRIBUTE_NAME, key)
|
||||
}
|
||||
@ -229,9 +229,9 @@ def test_resets_to_min_pk_with_default_pk_and_sequence
|
||||
|
||||
def test_create_fixtures_resets_sequences_when_not_cached
|
||||
@instances.each do |instance|
|
||||
max_id = create_fixtures(instance.class.table_name).inject(0) do |max_id, (name, fixture)|
|
||||
max_id = create_fixtures(instance.class.table_name).inject(0) do |_max_id, (name, fixture)|
|
||||
fixture_id = fixture['id'].to_i
|
||||
fixture_id > max_id ? fixture_id : max_id
|
||||
fixture_id > _max_id ? fixture_id : _max_id
|
||||
end
|
||||
|
||||
# Clone the last fixture to check that it gets the next greatest id.
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
class LogSubscriberTest < ActiveRecord::TestCase
|
||||
include ActiveSupport::LogSubscriber::TestHelper
|
||||
include ActiveSupport::BufferedLogger::Severity
|
||||
|
||||
def setup
|
||||
@old_logger = ActiveRecord::Base.logger
|
||||
@ -39,4 +40,21 @@ def test_cached_queries
|
||||
assert_match(/CACHE/, @logger.logged(:debug).last)
|
||||
assert_match(/SELECT .*?FROM .?developers.?/i, @logger.logged(:debug).last)
|
||||
end
|
||||
|
||||
def test_basic_query_doesnt_log_when_level_is_not_debug
|
||||
@logger.level = INFO
|
||||
Developer.all
|
||||
wait
|
||||
assert_equal 0, @logger.logged(:debug).size
|
||||
end
|
||||
|
||||
def test_cached_queries_doesnt_log_when_level_is_not_debug
|
||||
@logger.level = INFO
|
||||
ActiveRecord::Base.cache do
|
||||
Developer.all
|
||||
Developer.all
|
||||
end
|
||||
wait
|
||||
assert_equal 0, @logger.logged(:debug).size
|
||||
end
|
||||
end
|
||||
|
@ -8,7 +8,6 @@
|
||||
require 'models/developer'
|
||||
require 'models/project'
|
||||
require 'models/comment'
|
||||
require 'models/category'
|
||||
|
||||
class MethodScopingTest < ActiveRecord::TestCase
|
||||
fixtures :authors, :developers, :projects, :comments, :posts, :developers_projects
|
||||
@ -543,4 +542,4 @@ def test_nested_scoped_find_merges_new_and_old_style_joins
|
||||
assert_equal 1, scoped_authors.size
|
||||
assert_equal authors(:david).attributes, scoped_authors.first.attributes
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -270,27 +270,27 @@ def test_many_should_return_true_if_more_than_one
|
||||
assert Topic.base.many?
|
||||
end
|
||||
|
||||
def test_should_build_with_proxy_options
|
||||
def test_should_build_on_top_of_named_scope
|
||||
topic = Topic.approved.build({})
|
||||
assert topic.approved
|
||||
end
|
||||
|
||||
def test_should_build_new_with_proxy_options
|
||||
def test_should_build_new_on_top_of_named_scope
|
||||
topic = Topic.approved.new
|
||||
assert topic.approved
|
||||
end
|
||||
|
||||
def test_should_create_with_proxy_options
|
||||
def test_should_create_on_top_of_named_scope
|
||||
topic = Topic.approved.create({})
|
||||
assert topic.approved
|
||||
end
|
||||
|
||||
def test_should_create_with_bang_with_proxy_options
|
||||
def test_should_create_with_bang_on_top_of_named_scope
|
||||
topic = Topic.approved.create!({})
|
||||
assert topic.approved
|
||||
end
|
||||
|
||||
def test_should_build_with_proxy_options_chained
|
||||
def test_should_build_on_top_of_chained_named_scopes
|
||||
topic = Topic.approved.by_lifo.build({})
|
||||
assert topic.approved
|
||||
assert_equal 'lifo', topic.author_name
|
||||
|
@ -59,6 +59,7 @@ def test_should_build_a_new_record_if_reject_all_blank_does_not_return_false
|
||||
pirate.save!
|
||||
|
||||
assert_equal 1, pirate.birds_with_reject_all_blank.count
|
||||
assert_equal 'Tweetie', pirate.birds_with_reject_all_blank.first.name
|
||||
end
|
||||
|
||||
def test_should_raise_an_ArgumentError_for_non_existing_associations
|
||||
@ -74,7 +75,7 @@ def test_should_disable_allow_destroy_by_default
|
||||
ship = pirate.create_ship(:name => 'Nights Dirty Lightning')
|
||||
|
||||
assert_no_difference('Ship.count') do
|
||||
pirate.update_attributes(:ship_attributes => { '_destroy' => true })
|
||||
pirate.update_attributes(:ship_attributes => { '_destroy' => true, :id => ship.id })
|
||||
end
|
||||
end
|
||||
|
||||
@ -100,7 +101,8 @@ def test_reject_if_method_with_arguments
|
||||
pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true }
|
||||
assert_no_difference('Ship.count') { pirate.save! }
|
||||
|
||||
# pirate.reject_empty_ships_on_create returns false for saved records
|
||||
# pirate.reject_empty_ships_on_create returns false for saved pirate records
|
||||
# in the previous step note that pirate gets saved but ship fails
|
||||
pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true }
|
||||
assert_difference('Ship.count') { pirate.save! }
|
||||
end
|
||||
@ -266,6 +268,28 @@ def test_should_update_existing_when_update_only_is_true_and_no_id_is_given
|
||||
end
|
||||
assert_equal 'Mayflower', @ship.reload.name
|
||||
end
|
||||
|
||||
def test_should_update_existing_when_update_only_is_true_and_id_is_given
|
||||
@ship.delete
|
||||
@ship = @pirate.create_update_only_ship(:name => 'Nights Dirty Lightning')
|
||||
|
||||
assert_no_difference('Ship.count') do
|
||||
@pirate.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower', :id => @ship.id })
|
||||
end
|
||||
assert_equal 'Mayflower', @ship.reload.name
|
||||
end
|
||||
|
||||
def test_should_destroy_existing_when_update_only_is_true_and_id_is_given_and_is_marked_for_destruction
|
||||
Pirate.accepts_nested_attributes_for :update_only_ship, :update_only => true, :allow_destroy => true
|
||||
@ship.delete
|
||||
@ship = @pirate.create_update_only_ship(:name => 'Nights Dirty Lightning')
|
||||
|
||||
assert_difference('Ship.count', -1) do
|
||||
@pirate.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower', :id => @ship.id, :_destroy => true })
|
||||
end
|
||||
Pirate.accepts_nested_attributes_for :update_only_ship, :update_only => true, :allow_destroy => false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
|
||||
@ -411,6 +435,27 @@ def test_should_update_existing_when_update_only_is_true_and_no_id_is_given
|
||||
end
|
||||
assert_equal 'Arr', @pirate.reload.catchphrase
|
||||
end
|
||||
|
||||
def test_should_update_existing_when_update_only_is_true_and_id_is_given
|
||||
@pirate.delete
|
||||
@pirate = @ship.create_update_only_pirate(:catchphrase => 'Aye')
|
||||
|
||||
assert_no_difference('Pirate.count') do
|
||||
@ship.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr', :id => @pirate.id })
|
||||
end
|
||||
assert_equal 'Arr', @pirate.reload.catchphrase
|
||||
end
|
||||
|
||||
def test_should_destroy_existing_when_update_only_is_true_and_id_is_given_and_is_marked_for_destruction
|
||||
Ship.accepts_nested_attributes_for :update_only_pirate, :update_only => true, :allow_destroy => true
|
||||
@pirate.delete
|
||||
@pirate = @ship.create_update_only_pirate(:catchphrase => 'Aye')
|
||||
|
||||
assert_difference('Pirate.count', -1) do
|
||||
@ship.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr', :id => @pirate.id, :_destroy => true })
|
||||
end
|
||||
Ship.accepts_nested_attributes_for :update_only_pirate, :update_only => true, :allow_destroy => false
|
||||
end
|
||||
end
|
||||
|
||||
module NestedAttributesOnACollectionAssociationTests
|
||||
@ -811,7 +856,25 @@ def setup
|
||||
@part = @ship.parts.create!(:name => "Mast")
|
||||
@trinket = @part.trinkets.create!(:name => "Necklace")
|
||||
end
|
||||
|
||||
|
||||
test "if association is not loaded and association record is saved and then in memory record attributes should be saved" do
|
||||
@ship.parts_attributes=[{:id => @part.id,:name =>'Deck'}]
|
||||
assert_equal 1, @ship.parts.proxy_target.size
|
||||
assert_equal 'Deck', @ship.parts[0].name
|
||||
end
|
||||
|
||||
test "if association is not loaded and child doesn't change and I am saving a grandchild then in memory record should be used" do
|
||||
@ship.parts_attributes=[{:id => @part.id,:trinkets_attributes =>[{:id => @trinket.id, :name => 'Ruby'}]}]
|
||||
assert_equal 1, @ship.parts.proxy_target.size
|
||||
assert_equal 'Mast', @ship.parts[0].name
|
||||
assert_no_difference("@ship.parts[0].trinkets.proxy_target.size") do
|
||||
@ship.parts[0].trinkets.proxy_target.size
|
||||
end
|
||||
assert_equal 'Ruby', @ship.parts[0].trinkets[0].name
|
||||
@ship.save
|
||||
assert_equal 'Ruby', @ship.parts[0].trinkets[0].name
|
||||
end
|
||||
|
||||
test "when grandchild changed in memory, saving parent should save grandchild" do
|
||||
@trinket.name = "changed"
|
||||
@ship.save
|
||||
|
@ -5,25 +5,19 @@
|
||||
require 'models/reply'
|
||||
require 'models/category'
|
||||
require 'models/company'
|
||||
require 'models/customer'
|
||||
require 'models/developer'
|
||||
require 'models/project'
|
||||
require 'models/default'
|
||||
require 'models/auto_id'
|
||||
require 'models/column_name'
|
||||
require 'models/subscriber'
|
||||
require 'models/keyboard'
|
||||
require 'models/comment'
|
||||
require 'models/minimalistic'
|
||||
require 'models/warehouse_thing'
|
||||
require 'models/parrot'
|
||||
require 'models/minivan'
|
||||
require 'models/loose_person'
|
||||
require 'rexml/document'
|
||||
require 'active_support/core_ext/exception'
|
||||
|
||||
class PersistencesTest < ActiveRecord::TestCase
|
||||
|
||||
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts
|
||||
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts, :minivans
|
||||
|
||||
def test_create
|
||||
topic = Topic.new
|
||||
@ -220,6 +214,11 @@ def test_update_attribute
|
||||
assert !Topic.find(1).approved?
|
||||
end
|
||||
|
||||
def test_update_attribute_for_readonly_attribute
|
||||
minivan = Minivan.find('m1')
|
||||
assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, 'black') }
|
||||
end
|
||||
|
||||
def test_update_attribute_with_one_changed_and_one_updated
|
||||
t = Topic.order('id').limit(1).first
|
||||
title, author_name = t.title, t.author_name
|
||||
|
@ -13,7 +13,7 @@ def test_to_key_with_default_primary_key
|
||||
topic = Topic.new
|
||||
assert topic.to_key.nil?
|
||||
topic = Topic.find(1)
|
||||
assert_equal topic.to_key, [1]
|
||||
assert_equal [1], topic.to_key
|
||||
end
|
||||
|
||||
def test_to_key_with_customized_primary_key
|
||||
@ -26,7 +26,7 @@ def test_to_key_with_customized_primary_key
|
||||
def test_to_key_with_primary_key_after_destroy
|
||||
topic = Topic.find(1)
|
||||
topic.destroy
|
||||
assert_equal topic.to_key, [1]
|
||||
assert_equal [1], topic.to_key
|
||||
end
|
||||
|
||||
def test_integer_key
|
@ -1,8 +1,6 @@
|
||||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
require 'models/task'
|
||||
require 'models/course'
|
||||
require 'models/category'
|
||||
require 'models/post'
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
require 'models/project'
|
||||
require 'models/comment'
|
||||
require 'models/category'
|
||||
require 'models/person'
|
||||
require 'models/reference'
|
||||
|
||||
class RelationScopingTest < ActiveRecord::TestCase
|
||||
fixtures :authors, :developers, :projects, :comments, :posts, :developers_projects
|
||||
@ -218,7 +220,7 @@ def test_nested_exclusive_scope_for_create
|
||||
end
|
||||
|
||||
class HasManyScopingTest< ActiveRecord::TestCase
|
||||
fixtures :comments, :posts
|
||||
fixtures :comments, :posts, :people, :references
|
||||
|
||||
def setup
|
||||
@welcome = Post.find(1)
|
||||
@ -250,6 +252,23 @@ def test_nested_scope_finder
|
||||
assert_equal 'a comment...', @welcome.comments.what_are_you
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_maintain_default_scope_on_associations
|
||||
person = people(:michael)
|
||||
magician = BadReference.find(1)
|
||||
assert_equal [magician], people(:michael).bad_references
|
||||
end
|
||||
|
||||
def test_should_default_scope_on_associations_is_overriden_by_association_conditions
|
||||
person = people(:michael)
|
||||
assert_equal [], people(:michael).fixed_bad_references
|
||||
end
|
||||
|
||||
def test_should_maintain_default_scope_on_eager_loaded_associations
|
||||
michael = Person.where(:id => people(:michael).id).includes(:bad_references).first
|
||||
magician = BadReference.find(1)
|
||||
assert_equal [magician], michael.bad_references
|
||||
end
|
||||
end
|
||||
|
||||
class HasAndBelongsToManyScopingTest< ActiveRecord::TestCase
|
||||
@ -399,4 +418,4 @@ def test_create_attribute_overwrites_default_values
|
||||
assert_equal nil, PoorDeveloperCalledJamis.create!(:salary => nil).salary
|
||||
assert_equal 50000, PoorDeveloperCalledJamis.create!(:name => 'David').salary
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,4 @@
|
||||
require "cases/helper"
|
||||
require 'models/tag'
|
||||
require 'models/tagging'
|
||||
require 'models/post'
|
||||
require 'models/topic'
|
||||
|
@ -1,6 +1,5 @@
|
||||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
|
||||
class TransactionCallbacksTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
|
@ -1,6 +1,5 @@
|
||||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
|
||||
class I18nGenerateMessageValidationTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user