diff --git a/app/metal/itex.rb b/app/metal/itex.rb
index b9091c9f..867ab590 100644
--- a/app/metal/itex.rb
+++ b/app/metal/itex.rb
@@ -18,7 +18,7 @@ class Itex
begin
require 'nokogiri'
def self.xmlparse(text)
- Nokogiri::XML(text) { |config| config.options = Nokogiri::XML::ParseOptions::STRICT }
+ Nokogiri::XML(text) { |config| config.strict }
end
rescue LoadError
require 'rexml/document'
diff --git a/app/views/layouts/default.rhtml b/app/views/layouts/default.rhtml
index 338e11d0..9c6b1c3d 100644
--- a/app/views/layouts/default.rhtml
+++ b/app/views/layouts/default.rhtml
@@ -33,6 +33,7 @@
<%= @web && @web.additional_style ? @web.additional_style.html_safe : '' %>
/*]]>*/-->
<%= javascript_include_tag :defaults %>
+ <%= csrf_meta_tag %>
<%- if @web -%>
<%- if @web.markup == :markdownMML -%>
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
index 47df15e9..a75bd522 100644
--- a/public/javascripts/application.js
+++ b/public/javascripts/application.js
@@ -5,3 +5,25 @@ function toggleView(id)
(document.getElementById(id).style.display == 'block') ? document.getElementById(id).style.display='none' : document.getElementById(id).style.display='block';
}
+/*
+ * Registers a callback which copies the csrf token into the
+ * X-CSRF-Token header with each ajax request. Necessary to
+ * work with rails applications which have fixed
+ * CVE-2011-0447
+*/
+
+Ajax.Responders.register({
+ onCreate: function(request) {
+ var csrf_meta_tag = $$('meta[name=csrf-token]')[0];
+
+ if (csrf_meta_tag) {
+ var header = 'X-CSRF-Token',
+ token = csrf_meta_tag.readAttribute('content');
+
+ if (!request.options.requestHeaders) {
+ request.options.requestHeaders = {};
+ }
+ request.options.requestHeaders[header] = token;
+ }
+ }
+});
diff --git a/vendor/rails/actionmailer/CHANGELOG b/vendor/rails/actionmailer/CHANGELOG
index 2b3e4ed7..59f5b187 100644
--- a/vendor/rails/actionmailer/CHANGELOG
+++ b/vendor/rails/actionmailer/CHANGELOG
@@ -1,3 +1,4 @@
+*2.3.11 (February 9, 2011)*
*2.3.10 (October 15, 2010)*
*2.3.9 (September 4, 2010)*
*2.3.8 (May 24, 2010)*
diff --git a/vendor/rails/actionmailer/Rakefile b/vendor/rails/actionmailer/Rakefile
index fa671826..e7ef2b23 100644
--- a/vendor/rails/actionmailer/Rakefile
+++ b/vendor/rails/actionmailer/Rakefile
@@ -54,7 +54,7 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "actionmailer"
s.homepage = "http://www.rubyonrails.org"
- s.add_dependency('actionpack', '= 2.3.10' + PKG_BUILD)
+ s.add_dependency('actionpack', '= 2.3.11' + PKG_BUILD)
s.has_rdoc = true
s.requirements << 'none'
diff --git a/vendor/rails/actionmailer/lib/action_mailer/base.rb b/vendor/rails/actionmailer/lib/action_mailer/base.rb
index f8a0a2bc..3e4e7d1f 100644
--- a/vendor/rails/actionmailer/lib/action_mailer/base.rb
+++ b/vendor/rails/actionmailer/lib/action_mailer/base.rb
@@ -195,6 +195,39 @@ module ActionMailer #:nodoc:
# end
# end
#
+ # = Multipart Emails with Attachments
+ #
+ # Multipart emails that also have attachments can be created by nesting a "multipart/alternative" part
+ # within an email that has its content type set to "multipart/mixed". This would also need two templates
+ # in place within +app/views/mailer+ called "welcome_email.text.html.erb" and "welcome_email.text.plain.erb"
+ #
+ # class ApplicationMailer < ActionMailer::Base
+ # def signup_notification(recipient)
+ # recipients recipient.email_address_with_name
+ # subject "New account information"
+ # from "system@example.com"
+ # content_type "multipart/mixed"
+ #
+ # part "multipart/alternative" do |alternative|
+ #
+ # alternative.part "text/html" do |html|
+ # html.body = render_message("welcome_email.text.html", :message => "
HTML content
")
+ # end
+ #
+ # alternative.part "text/plain" do |plain|
+ # plain.body = render_message("welcome_email.text.plain", :message => "text content")
+ # end
+ #
+ # end
+ #
+ # attachment :content_type => "image/png",
+ # :body => File.read(File.join(RAILS_ROOT, 'public/images/rails.png'))
+ #
+ # attachment "application/pdf" do |a|
+ # a.body = File.read('/Users/mikel/Code/mail/spec/fixtures/attachments/test.pdf')
+ # end
+ # end
+ # end
#
# = Configuration options
#
diff --git a/vendor/rails/actionmailer/lib/action_mailer/version.rb b/vendor/rails/actionmailer/lib/action_mailer/version.rb
index 8167d903..da9b986a 100644
--- a/vendor/rails/actionmailer/lib/action_mailer/version.rb
+++ b/vendor/rails/actionmailer/lib/action_mailer/version.rb
@@ -2,7 +2,7 @@ module ActionMailer
module VERSION #:nodoc:
MAJOR = 2
MINOR = 3
- TINY = 10
+ TINY = 11
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/vendor/rails/actionpack/CHANGELOG b/vendor/rails/actionpack/CHANGELOG
index 87e86308..af6b0be2 100644
--- a/vendor/rails/actionpack/CHANGELOG
+++ b/vendor/rails/actionpack/CHANGELOG
@@ -1,3 +1,7 @@
+*2.3.11 (February 9, 2011)*
+
+* Two security fixes. CVE-2011-0446, CVE-2011-0447
+
*2.3.10 (October 15, 2010)*
*2.3.9 (September 4, 2010)*
diff --git a/vendor/rails/actionpack/Rakefile b/vendor/rails/actionpack/Rakefile
index b97eae09..4c7c4b7b 100644
--- a/vendor/rails/actionpack/Rakefile
+++ b/vendor/rails/actionpack/Rakefile
@@ -79,7 +79,7 @@ spec = Gem::Specification.new do |s|
s.has_rdoc = true
s.requirements << 'none'
- s.add_dependency('activesupport', '= 2.3.10' + PKG_BUILD)
+ s.add_dependency('activesupport', '= 2.3.11' + PKG_BUILD)
s.add_dependency('rack', '~> 1.1.0')
s.require_path = 'lib'
diff --git a/vendor/rails/actionpack/lib/action_controller/cookies.rb b/vendor/rails/actionpack/lib/action_controller/cookies.rb
index 4857de7a..9eab87b7 100644
--- a/vendor/rails/actionpack/lib/action_controller/cookies.rb
+++ b/vendor/rails/actionpack/lib/action_controller/cookies.rb
@@ -60,7 +60,7 @@ module ActionController #:nodoc:
attr_reader :controller
def initialize(controller)
- @controller, @cookies = controller, controller.request.cookies
+ @controller, @cookies, @secure = controller, controller.request.cookies, controller.request.ssl?
super()
update(@cookies)
end
@@ -81,7 +81,7 @@ module ActionController #:nodoc:
options[:path] = "/" unless options.has_key?(:path)
super(key.to_s, options[:value])
- @controller.response.set_cookie(key, options)
+ @controller.response.set_cookie(key, options) if write_cookie?(options)
end
# Removes the cookie on the client machine by setting the value to an empty string
@@ -126,6 +126,12 @@ module ActionController #:nodoc:
def signed
@signed ||= SignedCookieJar.new(self)
end
+
+ private
+
+ def write_cookie?(cookie)
+ @secure || !cookie[:secure] || defined?(Rails.env) && Rails.env.development?
+ end
end
class PermanentCookieJar < CookieJar #:nodoc:
diff --git a/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb b/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb
index 24821fff..00308579 100644
--- a/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb
+++ b/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb
@@ -76,7 +76,11 @@ module ActionController #:nodoc:
protected
# The actual before_filter that is used. Modify this to change how you handle unverified requests.
def verify_authenticity_token
- verified_request? || raise(ActionController::InvalidAuthenticityToken)
+ verified_request? || handle_unverified_request
+ end
+
+ def handle_unverified_request
+ reset_session
end
# Returns true or false if a request is verified. Checks:
@@ -85,11 +89,10 @@ module ActionController #:nodoc:
# * is it a GET request? Gets should be safe and idempotent
# * Does the form_authenticity_token match the given token value from the params?
def verified_request?
- !protect_against_forgery? ||
- request.method == :get ||
- request.xhr? ||
- !verifiable_request_format? ||
- form_authenticity_token == form_authenticity_param
+ !protect_against_forgery? ||
+ request.get? ||
+ form_authenticity_token == form_authenticity_param ||
+ form_authenticity_token == request.headers['X-CSRF-Token']
end
def form_authenticity_param
diff --git a/vendor/rails/actionpack/lib/action_controller/session/abstract_store.rb b/vendor/rails/actionpack/lib/action_controller/session/abstract_store.rb
index 51acab24..de0163d2 100644
--- a/vendor/rails/actionpack/lib/action_controller/session/abstract_store.rb
+++ b/vendor/rails/actionpack/lib/action_controller/session/abstract_store.rb
@@ -195,22 +195,8 @@ module ActionController
request_cookies = env["rack.request.cookie_hash"]
if (request_cookies.nil? || request_cookies[@key] != sid) || options[:expire_after]
- cookie = Rack::Utils.escape(@key) + '=' + Rack::Utils.escape(sid)
- cookie << "; domain=#{options[:domain]}" if options[:domain]
- cookie << "; path=#{options[:path]}" if options[:path]
- if options[:expire_after]
- expiry = Time.now + options[:expire_after]
- cookie << "; expires=#{expiry.httpdate}"
- end
- cookie << "; secure" if options[:secure]
- cookie << "; HttpOnly" if options[:httponly]
-
- headers = response[1]
- unless headers[SET_COOKIE].blank?
- headers[SET_COOKIE] << "\n#{cookie}"
- else
- headers[SET_COOKIE] = cookie
- end
+ cookie = {:value => sid}
+ Rack::Utils.set_cookie_header!(response[1], @key, cookie.merge(options))
end
end
diff --git a/vendor/rails/actionpack/lib/action_controller/session/cookie_store.rb b/vendor/rails/actionpack/lib/action_controller/session/cookie_store.rb
index 31b63663..2053aabc 100644
--- a/vendor/rails/actionpack/lib/action_controller/session/cookie_store.rb
+++ b/vendor/rails/actionpack/lib/action_controller/session/cookie_store.rb
@@ -52,7 +52,6 @@ module ActionController
ENV_SESSION_KEY = "rack.session".freeze
ENV_SESSION_OPTIONS_KEY = "rack.session.options".freeze
- HTTP_SET_COOKIE = "Set-Cookie".freeze
# Raised when storing more than 4K of session data.
class CookieOverflow < StandardError; end
@@ -116,9 +115,7 @@ module ActionController
cookie[:expires] = Time.now + options[:expire_after]
end
- cookie = build_cookie(@key, cookie.merge(options))
- headers[HTTP_SET_COOKIE] = [] if headers[HTTP_SET_COOKIE].blank?
- headers[HTTP_SET_COOKIE] << cookie
+ Rack::Utils.set_cookie_header!(headers, @key, cookie.merge(options))
end
[status, headers, body]
@@ -130,26 +127,6 @@ module ActionController
env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
env[ENV_SESSION_OPTIONS_KEY] = AbstractStore::OptionsHash.new(self, env, @default_options)
end
-
- # Should be in Rack::Utils soon
- def build_cookie(key, value)
- case value
- when Hash
- domain = "; domain=" + value[:domain] if value[:domain]
- path = "; path=" + value[:path] if value[:path]
- # According to RFC 2109, we need dashes here.
- # N.B.: cgi.rb uses spaces...
- expires = "; expires=" + value[:expires].clone.gmtime.
- strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires]
- secure = "; secure" if value[:secure]
- httponly = "; HttpOnly" if value[:httponly]
- value = value[:value]
- end
- value = [value] unless Array === value
- cookie = Rack::Utils.escape(key) + "=" +
- value.map { |v| Rack::Utils.escape(v) }.join("&") +
- "#{domain}#{path}#{expires}#{secure}#{httponly}"
- end
def load_session(env)
data = unpacked_cookie_data(env)
diff --git a/vendor/rails/actionpack/lib/action_controller/session/mem_cache_store.rb b/vendor/rails/actionpack/lib/action_controller/session/mem_cache_store.rb
index 402681cd..2bb1b133 100644
--- a/vendor/rails/actionpack/lib/action_controller/session/mem_cache_store.rb
+++ b/vendor/rails/actionpack/lib/action_controller/session/mem_cache_store.rb
@@ -1,6 +1,6 @@
begin
require_library_or_gem 'memcache'
-
+ require 'thread'
module ActionController
module Session
class MemCacheStore < AbstractStore
diff --git a/vendor/rails/actionpack/lib/action_pack/version.rb b/vendor/rails/actionpack/lib/action_pack/version.rb
index 3880c00a..227ef601 100644
--- a/vendor/rails/actionpack/lib/action_pack/version.rb
+++ b/vendor/rails/actionpack/lib/action_pack/version.rb
@@ -2,7 +2,7 @@ module ActionPack #:nodoc:
module VERSION #:nodoc:
MAJOR = 2
MINOR = 3
- TINY = 10
+ TINY = 11
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/vendor/rails/actionpack/lib/action_view/helpers.rb b/vendor/rails/actionpack/lib/action_view/helpers.rb
index cea894dd..debd2e75 100644
--- a/vendor/rails/actionpack/lib/action_view/helpers.rb
+++ b/vendor/rails/actionpack/lib/action_view/helpers.rb
@@ -6,6 +6,7 @@ module ActionView #:nodoc:
autoload :BenchmarkHelper, 'action_view/helpers/benchmark_helper'
autoload :CacheHelper, 'action_view/helpers/cache_helper'
autoload :CaptureHelper, 'action_view/helpers/capture_helper'
+ autoload :CsrfHelper, 'action_view/helpers/csrf_helper'
autoload :DateHelper, 'action_view/helpers/date_helper'
autoload :DebugHelper, 'action_view/helpers/debug_helper'
autoload :FormHelper, 'action_view/helpers/form_helper'
@@ -38,6 +39,7 @@ module ActionView #:nodoc:
include BenchmarkHelper
include CacheHelper
include CaptureHelper
+ include CsrfHelper
include DateHelper
include DebugHelper
include FormHelper
diff --git a/vendor/rails/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 38292681..1a8af3d3 100644
--- a/vendor/rails/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/vendor/rails/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -1,6 +1,7 @@
require 'cgi'
require 'action_view/helpers/url_helper'
require 'action_view/helpers/tag_helper'
+require 'thread'
module ActionView
module Helpers #:nodoc:
diff --git a/vendor/rails/actionpack/lib/action_view/helpers/csrf_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/csrf_helper.rb
new file mode 100644
index 00000000..e0e6c9a6
--- /dev/null
+++ b/vendor/rails/actionpack/lib/action_view/helpers/csrf_helper.rb
@@ -0,0 +1,14 @@
+module ActionView
+ # = Action View CSRF Helper
+ module Helpers
+ module CsrfHelper
+ # Returns a meta tag with the cross-site request forgery protection token
+ # for forms to use. Place this in your head.
+ def csrf_meta_tag
+ if protect_against_forgery?
+ %(\n).html_safe
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails/actionpack/lib/action_view/helpers/form_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/form_helper.rb
index 38c44a2d..389212df 100644
--- a/vendor/rails/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/vendor/rails/actionpack/lib/action_view/helpers/form_helper.rb
@@ -665,7 +665,7 @@ module ActionView
#
# The HTML specification says unchecked check boxes are not successful, and
# thus web browsers do not send them. Unfortunately this introduces a gotcha:
- # if an Invoice model has a +paid+ flag, and in the form that edits a paid
+ # if an +Invoice+ model has a +paid+ flag, and in the form that edits a paid
# invoice the user unchecks its check box, no +paid+ parameter is sent. So,
# any mass-assignment idiom like
#
@@ -673,12 +673,15 @@ module ActionView
#
# wouldn't update the flag.
#
- # To prevent this the helper generates a hidden field with the same name as
- # the checkbox after the very check box. So, the client either sends only the
- # hidden field (representing the check box is unchecked), or both fields.
- # Since the HTML specification says key/value pairs have to be sent in the
- # same order they appear in the form and Rails parameters extraction always
- # gets the first occurrence of any given key, that works in ordinary forms.
+ # To prevent this the helper generates an auxiliary hidden field before
+ # the very check box. The hidden field has the same name and its
+ # attributes mimick an unchecked check box.
+ #
+ # This way, the client either sends only the hidden field (representing
+ # the check box is unchecked), or both fields. Since the HTML specification
+ # says key/value pairs have to be sent in the same order they appear in the
+ # form, and parameters extraction gets the last occurrence of any repeated
+ # key in the query string, that works for ordinary forms.
#
# Unfortunately that workaround does not work when the check box goes
# within an array-like parameter, as in
@@ -689,22 +692,26 @@ module ActionView
# <% end %>
#
# because parameter name repetition is precisely what Rails seeks to distinguish
- # the elements of the array.
+ # the elements of the array. For each item with a checked check box you
+ # get an extra ghost item with only that attribute, assigned to "0".
+ #
+ # In that case it is preferable to either use +check_box_tag+ or to use
+ # hashes instead of arrays.
#
# ==== Examples
# # Let's say that @post.validated? is 1:
# check_box("post", "validated")
- # # =>
- # #
+ # # =>
+ # #
#
# # Let's say that @puppy.gooddog is "no":
# check_box("puppy", "gooddog", {}, "yes", "no")
- # # =>
- # #
+ # # =>
+ # #
#
# check_box("eula", "accepted", { :class => 'eula_check' }, "yes", "no")
- # # =>
- # #
+ # # =>
+ # #
#
def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
InstanceTag.new(object_name, method, self, options.delete(:object)).to_check_box_tag(options, checked_value, unchecked_value)
diff --git a/vendor/rails/actionpack/lib/action_view/helpers/url_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/url_helper.rb
index 74cb4486..8654adb3 100644
--- a/vendor/rails/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/vendor/rails/actionpack/lib/action_view/helpers/url_helper.rb
@@ -471,7 +471,8 @@ module ActionView
email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.has_key?("replace_dot")
if encode == "javascript"
- "document.write('#{content_tag("a", name || email_address_obfuscated.html_safe, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');".each_byte do |c|
+ html = content_tag("a", name || email_address_obfuscated.html_safe, html_options.merge({ "href" => "mailto:"+html_escape(email_address)+extras }))
+ "document.write('#{escape_javascript(html)}');".each_byte do |c|
string << sprintf("%%%x", c)
end
""
diff --git a/vendor/rails/actionpack/lib/action_view/renderable_partial.rb b/vendor/rails/actionpack/lib/action_view/renderable_partial.rb
index 3ea836fa..fb446145 100644
--- a/vendor/rails/actionpack/lib/action_view/renderable_partial.rb
+++ b/vendor/rails/actionpack/lib/action_view/renderable_partial.rb
@@ -27,7 +27,7 @@ module ActionView
def render_partial(view, object = nil, local_assigns = {}, as = nil)
object ||= local_assigns[:object] || local_assigns[variable_name]
- if object.nil? && view.respond_to?(:controller)
+ if object.nil? && !local_assigns_key?(local_assigns) && view.respond_to?(:controller)
ivar = :"@#{variable_name}"
object =
if view.controller.instance_variable_defined?(ivar)
@@ -43,5 +43,11 @@ module ActionView
render_template(view, local_assigns)
end
+
+ private
+
+ def local_assigns_key?(local_assigns)
+ local_assigns.key?(:object) || local_assigns.key?(variable_name)
+ end
end
end
diff --git a/vendor/rails/actionpack/test/controller/cookie_test.rb b/vendor/rails/actionpack/test/controller/cookie_test.rb
index a312f7f6..f517fdfe 100644
--- a/vendor/rails/actionpack/test/controller/cookie_test.rb
+++ b/vendor/rails/actionpack/test/controller/cookie_test.rb
@@ -100,11 +100,26 @@ class CookieTest < ActionController::TestCase
end
def test_setting_cookie_with_secure
+ @request.env["HTTPS"] = "on"
get :authenticate_with_secure
assert_equal ["user_name=david; path=/; secure"], @response.headers["Set-Cookie"]
assert_equal({"user_name" => "david"}, @response.cookies)
end
+ def test_setting_cookie_with_secure_in_development
+ with_environment(:development) do
+ get :authenticate_with_secure
+ assert_equal ["user_name=david; path=/; secure"], @response.headers["Set-Cookie"]
+ assert_equal({"user_name" => "david"}, @response.cookies)
+ end
+ end
+
+ def test_not_setting_cookie_with_secure
+ get :authenticate_with_secure
+ assert_not_equal ["user_name=david; path=/; secure"], @response.headers["Set-Cookie"]
+ assert_not_equal({"user_name" => "david"}, @response.cookies)
+ end
+
def test_multiple_cookies
get :set_multiple_cookies
assert_equal 2, @response.cookies.size
@@ -177,4 +192,17 @@ class CookieTest < ActionController::TestCase
assert_match %r(#{20.years.from_now.year}), @response.headers["Set-Cookie"].first
assert_equal 100, @controller.send(:cookies).signed[:remember_me]
end
+
+ private
+ def with_environment(enviroment)
+ old_rails = Object.const_get(:Rails) rescue nil
+ mod = Object.const_set(:Rails, Module.new)
+ (class << mod; self; end).instance_eval do
+ define_method(:env) { @_env ||= ActiveSupport::StringInquirer.new(enviroment.to_s) }
+ end
+ yield
+ ensure
+ Object.module_eval { remove_const(:Rails) } if defined?(Rails)
+ Object.const_set(:Rails, old_rails) if old_rails
+ end
end
\ No newline at end of file
diff --git a/vendor/rails/actionpack/test/controller/reloader_test.rb b/vendor/rails/actionpack/test/controller/reloader_test.rb
index e5305493..d78f8111 100644
--- a/vendor/rails/actionpack/test/controller/reloader_test.rb
+++ b/vendor/rails/actionpack/test/controller/reloader_test.rb
@@ -1,4 +1,5 @@
require 'abstract_unit'
+require 'thread'
class ReloaderTests < ActiveSupport::TestCase
Reloader = ActionController::Reloader
diff --git a/vendor/rails/actionpack/test/controller/render_test.rb b/vendor/rails/actionpack/test/controller/render_test.rb
index 42f776c7..288260a2 100644
--- a/vendor/rails/actionpack/test/controller/render_test.rb
+++ b/vendor/rails/actionpack/test/controller/render_test.rb
@@ -716,6 +716,11 @@ class TestController < ActionController::Base
render :partial => "customer"
end
+ def partial_with_implicit_local_assignment_and_nil_local
+ @customer = Customer.new("Marcel")
+ render :partial => "customer", :locals => { :customer => nil }
+ end
+
def render_call_to_partial_with_layout
render :action => "calling_partial_with_layout"
end
@@ -1543,6 +1548,13 @@ class RenderTest < ActionController::TestCase
end
end
+ def test_partial_with_implicit_local_assignment_and_nil_local
+ assert_not_deprecated do
+ get :partial_with_implicit_local_assignment_and_nil_local
+ assert_equal "Hello: Anonymous", @response.body
+ end
+ end
+
def test_render_missing_partial_template
assert_raise(ActionView::MissingTemplate) do
get :missing_partial
diff --git a/vendor/rails/actionpack/test/controller/request_forgery_protection_test.rb b/vendor/rails/actionpack/test/controller/request_forgery_protection_test.rb
index c6ad4b92..75029057 100644
--- a/vendor/rails/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/vendor/rails/actionpack/test/controller/request_forgery_protection_test.rb
@@ -23,6 +23,10 @@ module RequestForgeryProtectionActions
render :text => 'pwn'
end
+ def meta
+ render :inline => "<%= csrf_meta_tag %>"
+ end
+
def rescue_action(e) raise e end
end
@@ -32,6 +36,16 @@ class RequestForgeryProtectionController < ActionController::Base
protect_from_forgery :only => :index
end
+class RequestForgeryProtectionControllerUsingOldBehaviour < ActionController::Base
+ include RequestForgeryProtectionActions
+ protect_from_forgery :only => %w(index meta)
+
+ def handle_unverified_request
+ raise(ActionController::InvalidAuthenticityToken)
+ end
+end
+
+
class FreeCookieController < RequestForgeryProtectionController
self.allow_forgery_protection = false
@@ -54,158 +68,92 @@ end
# common test methods
module RequestForgeryProtectionTests
- def teardown
- ActionController::Base.request_forgery_protection_token = nil
+ def setup
+ @token = "cf50faa3fe97702ca1ae"
+
+ ActiveSupport::SecureRandom.stubs(:base64).returns(@token)
+ ActionController::Base.request_forgery_protection_token = :authenticity_token
end
-
+
def test_should_render_form_with_token_tag
- get :index
- assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
- end
-
- def test_should_render_button_to_with_token_tag
- get :show_button
- assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
- end
-
- def test_should_render_remote_form_with_only_one_token_parameter
- get :remote_form
- assert_equal 1, @response.body.scan(@token).size
- end
-
- def test_should_allow_get
- get :index
- assert_response :success
- end
-
- def test_should_allow_post_without_token_on_unsafe_action
- post :unsafe
- assert_response :success
- end
-
- def test_should_not_allow_html_post_without_token
- @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
- assert_raise(ActionController::InvalidAuthenticityToken) { post :index, :format => :html }
- end
-
- def test_should_not_allow_html_put_without_token
- @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
- assert_raise(ActionController::InvalidAuthenticityToken) { put :index, :format => :html }
- end
-
- def test_should_not_allow_html_delete_without_token
- @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
- assert_raise(ActionController::InvalidAuthenticityToken) { delete :index, :format => :html }
- end
-
- def test_should_allow_api_formatted_post_without_token
- assert_nothing_raised do
- post :index, :format => 'xml'
+ assert_not_blocked do
+ get :index
end
+ assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
end
- def test_should_not_allow_api_formatted_put_without_token
- assert_nothing_raised do
- put :index, :format => 'xml'
+ def test_should_render_button_to_with_token_tag
+ assert_not_blocked do
+ get :show_button
end
+ assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
end
- def test_should_allow_api_formatted_delete_without_token
- assert_nothing_raised do
- delete :index, :format => 'xml'
- end
+ def test_should_allow_get
+ assert_not_blocked { get :index }
end
- def test_should_not_allow_api_formatted_post_sent_as_url_encoded_form_without_token
- assert_raise(ActionController::InvalidAuthenticityToken) do
- @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
- post :index, :format => 'xml'
- end
+ def test_should_allow_post_without_token_on_unsafe_action
+ assert_not_blocked { post :unsafe }
end
- def test_should_not_allow_api_formatted_put_sent_as_url_encoded_form_without_token
- assert_raise(ActionController::InvalidAuthenticityToken) do
- @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
- put :index, :format => 'xml'
- end
+ def test_should_not_allow_post_without_token
+ assert_blocked { post :index }
end
- def test_should_not_allow_api_formatted_delete_sent_as_url_encoded_form_without_token
- assert_raise(ActionController::InvalidAuthenticityToken) do
- @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
- delete :index, :format => 'xml'
- end
+ def test_should_not_allow_post_without_token_irrespective_of_format
+ assert_blocked { post :index, :format=>'xml' }
end
- def test_should_not_allow_api_formatted_post_sent_as_multipart_form_without_token
- assert_raise(ActionController::InvalidAuthenticityToken) do
- @request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
- post :index, :format => 'xml'
- end
+ def test_should_not_allow_put_without_token
+ assert_blocked { put :index }
end
- def test_should_not_allow_api_formatted_put_sent_as_multipart_form_without_token
- assert_raise(ActionController::InvalidAuthenticityToken) do
- @request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
- put :index, :format => 'xml'
- end
+ def test_should_not_allow_delete_without_token
+ assert_blocked { delete :index }
end
- def test_should_not_allow_api_formatted_delete_sent_as_multipart_form_without_token
- assert_raise(ActionController::InvalidAuthenticityToken) do
- @request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
- delete :index, :format => 'xml'
- end
+ def test_should_not_allow_xhr_post_without_token
+ assert_blocked { xhr :post, :index }
end
-
- def test_should_allow_xhr_post_without_token
- assert_nothing_raised { xhr :post, :index }
- end
-
- def test_should_allow_xhr_put_without_token
- assert_nothing_raised { xhr :put, :index }
- end
-
- def test_should_allow_xhr_delete_without_token
- assert_nothing_raised { xhr :delete, :index }
- end
-
- def test_should_allow_xhr_post_with_encoded_form_content_type_without_token
- @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
- assert_nothing_raised { xhr :post, :index }
- end
-
+
def test_should_allow_post_with_token
- post :index, :authenticity_token => @token
- assert_response :success
+ assert_not_blocked { post :index, :authenticity_token => @token }
end
def test_should_allow_put_with_token
- put :index, :authenticity_token => @token
- assert_response :success
+ assert_not_blocked { put :index, :authenticity_token => @token }
end
def test_should_allow_delete_with_token
- delete :index, :authenticity_token => @token
+ assert_not_blocked { delete :index, :authenticity_token => @token }
+ end
+
+ def test_should_allow_post_with_token_in_header
+ @request.env['HTTP_X_CSRF_TOKEN'] = @token
+ assert_not_blocked { post :index }
+ end
+
+ def test_should_allow_delete_with_token_in_header
+ @request.env['HTTP_X_CSRF_TOKEN'] = @token
+ assert_not_blocked { delete :index }
+ end
+
+ def test_should_allow_put_with_token_in_header
+ @request.env['HTTP_X_CSRF_TOKEN'] = @token
+ assert_not_blocked { put :index }
+ end
+
+ def assert_blocked
+ session[:something_like_user_id] = 1
+ yield
+ assert_nil session[:something_like_user_id], "session values are still present"
assert_response :success
end
- def test_should_allow_post_with_xml
- @request.env['CONTENT_TYPE'] = Mime::XML.to_s
- post :index, :format => 'xml'
- assert_response :success
- end
-
- def test_should_allow_put_with_xml
- @request.env['CONTENT_TYPE'] = Mime::XML.to_s
- put :index, :format => 'xml'
- assert_response :success
- end
-
- def test_should_allow_delete_with_xml
- @request.env['CONTENT_TYPE'] = Mime::XML.to_s
- delete :index, :format => 'xml'
+ def assert_not_blocked
+ assert_nothing_raised { yield }
assert_response :success
end
end
@@ -214,15 +162,20 @@ end
class RequestForgeryProtectionControllerTest < ActionController::TestCase
include RequestForgeryProtectionTests
- def setup
- @controller = RequestForgeryProtectionController.new
- @request = ActionController::TestRequest.new
- @request.format = :html
- @response = ActionController::TestResponse.new
- @token = "cf50faa3fe97702ca1ae"
- ActiveSupport::SecureRandom.stubs(:base64).returns(@token)
- ActionController::Base.request_forgery_protection_token = :authenticity_token
+ test 'should emit a csrf-token meta tag' do
+ ActiveSupport::SecureRandom.stubs(:base64).returns(@token + '<=?')
+ get :meta
+ assert_equal %(\n), @response.body
+ end
+end
+
+class RequestForgeryProtectionControllerUsingOldBehaviourTest < ActionController::TestCase
+ include RequestForgeryProtectionTests
+ def assert_blocked
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ yield
+ end
end
end
@@ -251,15 +204,30 @@ class FreeCookieControllerTest < ActionController::TestCase
assert_nothing_raised { send(method, :index)}
end
end
+
+ test 'should not emit a csrf-token meta tag' do
+ get :meta
+ assert_blank @response.body
+ end
end
+
+
+
+
class CustomAuthenticityParamControllerTest < ActionController::TestCase
def setup
+ ActionController::Base.request_forgery_protection_token = :custom_token_name
+ super
+ end
+
+ def teardown
ActionController::Base.request_forgery_protection_token = :authenticity_token
+ super
end
def test_should_allow_custom_token
- post :index, :authenticity_token => 'foobar'
+ post :index, :custom_token_name => 'foobar'
assert_response :ok
end
end
diff --git a/vendor/rails/actionpack/test/controller/session/cookie_store_test.rb b/vendor/rails/actionpack/test/controller/session/cookie_store_test.rb
index d467af7e..b7b922c3 100644
--- a/vendor/rails/actionpack/test/controller/session/cookie_store_test.rb
+++ b/vendor/rails/actionpack/test/controller/session/cookie_store_test.rb
@@ -106,7 +106,7 @@ class CookieStoreTest < ActionController::IntegrationTest
with_test_route_set do
get '/set_session_value'
assert_response :success
- assert_equal ["_myapp_session=#{response.body}; path=/; HttpOnly"],
+ assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly",
headers['Set-Cookie']
end
end
@@ -159,7 +159,7 @@ class CookieStoreTest < ActionController::IntegrationTest
with_test_route_set(:secure => true) do
get '/set_session_value', nil, 'HTTPS' => 'on'
assert_response :success
- assert_equal ["_myapp_session=#{response.body}; path=/; secure; HttpOnly"],
+ assert_equal "_myapp_session=#{response.body}; path=/; secure; HttpOnly",
headers['Set-Cookie']
end
end
@@ -195,12 +195,12 @@ class CookieStoreTest < ActionController::IntegrationTest
get '/set_session_value'
assert_response :success
session_payload = response.body
- assert_equal ["_myapp_session=#{response.body}; path=/; HttpOnly"],
+ assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly",
headers['Set-Cookie']
get '/call_reset_session'
assert_response :success
- assert_not_equal [], headers['Set-Cookie']
+ assert_not_equal "", headers['Set-Cookie']
assert_not_equal session_payload, cookies[SessionKey]
get '/get_session_value'
@@ -214,7 +214,7 @@ class CookieStoreTest < ActionController::IntegrationTest
get '/set_session_value'
assert_response :success
session_payload = response.body
- assert_equal ["_myapp_session=#{response.body}; path=/; HttpOnly"],
+ assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly",
headers['Set-Cookie']
get '/call_session_clear'
diff --git a/vendor/rails/actionpack/test/template/url_helper_test.rb b/vendor/rails/actionpack/test/template/url_helper_test.rb
index 9d541fc1..480624f4 100644
--- a/vendor/rails/actionpack/test/template/url_helper_test.rb
+++ b/vendor/rails/actionpack/test/template/url_helper_test.rb
@@ -333,11 +333,11 @@ class UrlHelperTest < ActionView::TestCase
end
def test_mail_to_with_javascript
- assert_dom_equal "", mail_to("me@domain.com", "My email", :encode => "javascript")
+ assert_dom_equal "", mail_to("me@domain.com", "My email", :encode => "javascript")
end
def test_mail_to_with_javascript_unicode
- assert_dom_equal "", mail_to("unicode@example.com", "Ășnicode", :encode => "javascript")
+ assert_dom_equal "", mail_to("unicode@example.com", "Ășnicode", :encode => "javascript")
end
def test_mail_with_options
@@ -361,8 +361,8 @@ class UrlHelperTest < ActionView::TestCase
assert_dom_equal "me(at)domain.com", mail_to("me@domain.com", nil, :encode => "hex", :replace_at => "(at)")
assert_dom_equal "My email", mail_to("me@domain.com", "My email", :encode => "hex", :replace_at => "(at)")
assert_dom_equal "me(at)domain(dot)com", mail_to("me@domain.com", nil, :encode => "hex", :replace_at => "(at)", :replace_dot => "(dot)")
- assert_dom_equal "", mail_to("me@domain.com", "My email", :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
- assert_dom_equal "", mail_to("me@domain.com", nil, :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
+ assert_dom_equal "", mail_to("me@domain.com", "My email", :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
+ assert_dom_equal "", mail_to("me@domain.com", nil, :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)")
end
def protect_against_forgery?
diff --git a/vendor/rails/activerecord/CHANGELOG b/vendor/rails/activerecord/CHANGELOG
index 9383f962..a8fb4dbb 100644
--- a/vendor/rails/activerecord/CHANGELOG
+++ b/vendor/rails/activerecord/CHANGELOG
@@ -1,3 +1,5 @@
+*2.3.11 (February 9, 2011)*
+
*2.3.10 (October 15, 2010)*
* Security Release to fix CVE-2010-3933
diff --git a/vendor/rails/activerecord/Rakefile b/vendor/rails/activerecord/Rakefile
index e0684466..613bda69 100644
--- a/vendor/rails/activerecord/Rakefile
+++ b/vendor/rails/activerecord/Rakefile
@@ -192,7 +192,7 @@ spec = Gem::Specification.new do |s|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
end
- s.add_dependency('activesupport', '= 2.3.10' + PKG_BUILD)
+ s.add_dependency('activesupport', '= 2.3.11' + PKG_BUILD)
s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite"
s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite"
diff --git a/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb b/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb
index fbff07a2..3a602e49 100644
--- a/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb
+++ b/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb
@@ -353,15 +353,14 @@ module ActiveRecord
if @target.is_a?(Array) && @target.any?
@target = find_target.map do |f|
i = @target.index(f)
- 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
+ t = @target.delete_at(i) if i
+ if t && t.changed?
+ t
else
+ f.mark_for_destruction if t && t.marked_for_destruction?
f
end
- end + @target
+ end + @target.find_all {|t| t.new_record?}
else
@target = find_target
end
@@ -375,16 +374,17 @@ module ActiveRecord
target
end
- def method_missing(method, *args)
+ def method_missing(method, *args, &block)
case method.to_s
when 'find_or_create'
return find(:first, :conditions => args.first) || create(args.first)
when /^find_or_create_by_(.*)$/
rest = $1
- return send("find_by_#{rest}", *args) ||
- method_missing("create_by_#{rest}", *args)
+ find_args = pull_finder_args_from(DynamicFinderMatch.match(method).attribute_names, *args)
+ return send("find_by_#{rest}", find_args) ||
+ method_missing("create_by_#{rest}", *args, &block)
when /^create_by_(.*)$/
- return create($1.split('_and_').zip(args).inject({}) { |h,kv| k,v=kv ; h[k] = v ; h })
+ return create($1.split('_and_').zip(args).inject({}) { |h,kv| k,v=kv ; h[k] = v ; h }, &block)
end
if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
@@ -434,20 +434,32 @@ module ActiveRecord
callback(:before_add, record)
yield(record) if block_given?
@target ||= [] unless loaded?
- index = @target.index(record)
- unless @reflection.options[:uniq] && index
- if index
- @target[index] = record
- else
- @target << record
- end
- end
+ @target << record unless @reflection.options[:uniq] && @target.include?(record)
callback(:after_add, record)
set_inverse_instance(record, @owner)
record
end
private
+ # Separate the "finder" args from the "create" args given to a
+ # find_or_create_by_ call. Returns an array with the
+ # parameter values in the same order as the keys in the
+ # "names" array. This code was based on code in base.rb's
+ # method_missing method.
+ def pull_finder_args_from(names, *args)
+ attributes = names.collect { |name| name.intern }
+ attribute_hash = {}
+ args.each_with_index do |arg, i|
+ if arg.is_a?(Hash)
+ attribute_hash.merge! arg
+ else
+ attribute_hash[attributes[i]] = arg
+ end
+ end
+ attribute_hash = attribute_hash.with_indifferent_access
+ attributes.collect { |attr| attribute_hash[attr] }
+ end
+
def create_record(attrs)
attrs.update(@reflection.options[:conditions]) if @reflection.options[:conditions].is_a?(Hash)
ensure_owner_is_not_new
diff --git a/vendor/rails/activerecord/lib/active_record/calculations.rb b/vendor/rails/activerecord/lib/active_record/calculations.rb
index 0df2b6bd..f6249e52 100644
--- a/vendor/rails/activerecord/lib/active_record/calculations.rb
+++ b/vendor/rails/activerecord/lib/active_record/calculations.rb
@@ -187,7 +187,7 @@ module ActiveRecord
# A (slower) workaround if we're using a backend, like sqlite, that doesn't support COUNT DISTINCT.
sql = "SELECT COUNT(*) AS #{aggregate_alias}" if use_workaround
- sql << ", #{options[:group_field]} AS #{options[:group_alias]}" if options[:group]
+ options[:group_fields].each_index{|i| sql << ", #{options[:group_fields][i]} AS #{options[:group_aliases][i]}" } if options[:group]
if options[:from]
sql << " FROM #{options[:from]} "
elsif scope && scope[:from] && !use_workaround
@@ -211,8 +211,8 @@ module ActiveRecord
add_limited_ids_condition!(sql, options, join_dependency) if join_dependency && !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
if options[:group]
- group_key = connection.adapter_name == 'FrontBase' ? :group_alias : :group_field
- sql << " GROUP BY #{options[group_key]} "
+ group_key = connection.adapter_name == 'FrontBase' ? :group_aliases : :group_fields
+ sql << " GROUP BY #{options[group_key].join(',')} "
end
if options[:group] && options[:having]
@@ -239,24 +239,31 @@ module ActiveRecord
end
def execute_grouped_calculation(operation, column_name, column, options) #:nodoc:
- group_attr = options[:group].to_s
- association = reflect_on_association(group_attr.to_sym)
- associated = association && association.macro == :belongs_to # only count belongs_to associations
- group_field = associated ? association.primary_key_name : group_attr
- group_alias = column_alias_for(group_field)
- group_column = column_for group_field
- sql = construct_calculation_sql(operation, column_name, options.merge(:group_field => group_field, :group_alias => group_alias))
+ group_attr = options[:group]
+ association = reflect_on_association(group_attr.to_s.to_sym)
+ associated = association && association.macro == :belongs_to # only count belongs_to associations
+ group_fields = Array(associated ? association.primary_key_name : group_attr)
+ group_aliases = []
+ group_columns = {}
+
+ group_fields.each do |field|
+ group_aliases << column_alias_for(field)
+ group_columns[column_alias_for(field)] = column_for(field)
+ end
+
+ sql = construct_calculation_sql(operation, column_name, options.merge(:group_fields => group_fields, :group_aliases => group_aliases))
calculated_data = connection.select_all(sql)
aggregate_alias = column_alias_for(operation, column_name)
if association
- key_ids = calculated_data.collect { |row| row[group_alias] }
+ key_ids = calculated_data.collect { |row| row[group_aliases.first] }
key_records = association.klass.base_class.find(key_ids)
key_records = key_records.inject({}) { |hsh, r| hsh.merge(r.id => r) }
end
calculated_data.inject(ActiveSupport::OrderedHash.new) do |all, row|
- key = type_cast_calculated_value(row[group_alias], group_column)
+ key = group_aliases.map{|group_alias| type_cast_calculated_value(row[group_alias], group_columns[group_alias])}
+ key = key.first if key.size == 1
key = key_records[key] if associated
value = row[aggregate_alias]
all[key] = type_cast_calculated_value(value, column, operation)
diff --git a/vendor/rails/activerecord/lib/active_record/version.rb b/vendor/rails/activerecord/lib/active_record/version.rb
index 06680c37..f106e409 100644
--- a/vendor/rails/activerecord/lib/active_record/version.rb
+++ b/vendor/rails/activerecord/lib/active_record/version.rb
@@ -2,7 +2,7 @@ module ActiveRecord
module VERSION #:nodoc:
MAJOR = 2
MINOR = 3
- TINY = 10
+ TINY = 11
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/vendor/rails/activerecord/test/cases/associations/has_many_associations_test.rb b/vendor/rails/activerecord/test/cases/associations/has_many_associations_test.rb
index c626d457..3996b847 100644
--- a/vendor/rails/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/vendor/rails/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -65,6 +65,29 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal person, person.readers.first.person
end
+ def test_find_or_create_by_with_additional_parameters
+ post = Post.create! :title => 'test_find_or_create_by_with_additional_parameters', :body => 'this is the body'
+ comment = post.comments.create! :body => 'test comment body', :type => 'test'
+
+ assert_equal comment, post.comments.find_or_create_by_body('test comment body')
+
+ post.comments.find_or_create_by_body(:body => 'other test comment body', :type => 'test')
+ assert_equal 2, post.comments.count
+ assert_equal 2, post.comments.length
+ post.comments.find_or_create_by_body('other other test comment body', :type => 'test')
+ assert_equal 3, post.comments.count
+ assert_equal 3, post.comments.length
+ post.comments.find_or_create_by_body_and_type('3rd test comment body', 'test')
+ assert_equal 4, post.comments.count
+ assert_equal 4, post.comments.length
+ end
+
+ def test_find_or_create_by_with_block
+ post = Post.create! :title => 'test_find_or_create_by_with_additional_parameters', :body => 'this is the body'
+ comment = post.comments.find_or_create_by_body('other test comment body') { |comment| comment.type = 'test' }
+ assert_equal 'test', comment.type
+ end
+
def test_find_or_create
person = Person.create! :first_name => 'tenderlove'
post = Post.find :first
@@ -843,6 +866,17 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert companies(:first_firm).clients_of_firm(true).empty?, "37signals has no clients after destroy all and refresh"
end
+ def test_destroy_all_with_creates_and_scope_that_doesnt_match_created_records
+ company = companies(:first_firm)
+ unloaded_client_matching_scope = companies(:second_client)
+ created_client_matching_scope = company.clients_of_firm.create!(:name => "Somesoft")
+ created_client_not_matching_scope = company.clients_of_firm.create!(:name => "OtherCo")
+ destroyed = company.clients_of_firm.with_oft_in_name.destroy_all
+ assert destroyed.include?(unloaded_client_matching_scope), "unloaded clients matching the scope destroy_all on should have been destroyed"
+ assert destroyed.include?(created_client_matching_scope), "loaded clients matching the scope destroy_all on should have been destroyed"
+ assert !destroyed.include?(created_client_not_matching_scope), "loaded clients not matching the scope destroy_all on should not have been destroyed"
+ end
+
def test_dependence
firm = companies(:first_firm)
assert_equal 2, firm.clients.size
diff --git a/vendor/rails/activerecord/test/cases/associations_test.rb b/vendor/rails/activerecord/test/cases/associations_test.rb
index 47cb0d10..048d042b 100644
--- a/vendor/rails/activerecord/test/cases/associations_test.rb
+++ b/vendor/rails/activerecord/test/cases/associations_test.rb
@@ -18,8 +18,6 @@ require 'models/person'
require 'models/reader'
require 'models/parrot'
require 'models/pirate'
-require 'models/ship'
-require 'models/ship_part'
require 'models/treasure'
require 'models/price_estimate'
require 'models/club'
@@ -31,23 +29,6 @@ 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)}
diff --git a/vendor/rails/activerecord/test/cases/calculations_test.rb b/vendor/rails/activerecord/test/cases/calculations_test.rb
index 503b70aa..d5bb3589 100644
--- a/vendor/rails/activerecord/test/cases/calculations_test.rb
+++ b/vendor/rails/activerecord/test/cases/calculations_test.rb
@@ -58,6 +58,19 @@ class CalculationsTest < ActiveRecord::TestCase
[1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
end
+ def test_should_group_by_multiple_fields
+ c = Account.count(:all, :group => ['firm_id', :credit_limit])
+ [ [nil, 50], [1, 50], [6, 50], [6, 55], [9, 53], [2, 60] ].each { |firm_and_limit| assert c.keys.include?(firm_and_limit) }
+ end
+
+ def test_should_group_by_multiple_fields_having_functions
+ c = Topic.count(:all, :group => [:author_name, 'COALESCE(type, title)'])
+ assert_equal 1, c[["Nick", "The Third Topic of the day"]]
+ assert_equal 1, c[["Mary", "Reply"]]
+ assert_equal 1, c[["David", "The First Topic"]]
+ assert_equal 1, c[["Carl", "Reply"]]
+ end
+
def test_should_group_by_summed_field
c = Account.sum(:credit_limit, :group => :firm_id)
assert_equal 50, c[1]
diff --git a/vendor/rails/activerecord/test/cases/nested_attributes_test.rb b/vendor/rails/activerecord/test/cases/nested_attributes_test.rb
index 3adcc88d..6b144a14 100644
--- a/vendor/rails/activerecord/test/cases/nested_attributes_test.rb
+++ b/vendor/rails/activerecord/test/cases/nested_attributes_test.rb
@@ -808,13 +808,7 @@ class TestHasManyAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveR
@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 "when grandchild changed in memory, saving parent should save grandchild" do
@trinket.name = "changed"
@ship.save
diff --git a/vendor/rails/activerecord/test/models/company.rb b/vendor/rails/activerecord/test/models/company.rb
index de1a1cc5..ced2faab 100644
--- a/vendor/rails/activerecord/test/models/company.rb
+++ b/vendor/rails/activerecord/test/models/company.rb
@@ -12,6 +12,8 @@ class Company < AbstractCompany
has_many :contracts
has_many :developers, :through => :contracts
+ named_scope :with_oft_in_name, :conditions => "name LIKE '%oft%'"
+
def arbitrary_method
"I am Jack's profound disappointment"
end
diff --git a/vendor/rails/activeresource/CHANGELOG b/vendor/rails/activeresource/CHANGELOG
index f779b6f9..bbd33e6c 100644
--- a/vendor/rails/activeresource/CHANGELOG
+++ b/vendor/rails/activeresource/CHANGELOG
@@ -1,3 +1,4 @@
+*2.3.11 (February 9, 2011)*
*2.3.10 (October 15, 2010)*
*2.3.9 (September 4, 2010)*
*2.3.8 (May 24, 2010)*
diff --git a/vendor/rails/activeresource/Rakefile b/vendor/rails/activeresource/Rakefile
index ed214f74..3aa276b1 100644
--- a/vendor/rails/activeresource/Rakefile
+++ b/vendor/rails/activeresource/Rakefile
@@ -66,7 +66,7 @@ spec = Gem::Specification.new do |s|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
end
- s.add_dependency('activesupport', '= 2.3.10' + PKG_BUILD)
+ s.add_dependency('activesupport', '= 2.3.11' + PKG_BUILD)
s.require_path = 'lib'
s.autorequire = 'active_resource'
diff --git a/vendor/rails/activeresource/lib/active_resource/version.rb b/vendor/rails/activeresource/lib/active_resource/version.rb
index cc4540ac..0e36311c 100644
--- a/vendor/rails/activeresource/lib/active_resource/version.rb
+++ b/vendor/rails/activeresource/lib/active_resource/version.rb
@@ -2,7 +2,7 @@ module ActiveResource
module VERSION #:nodoc:
MAJOR = 2
MINOR = 3
- TINY = 10
+ TINY = 11
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/vendor/rails/activesupport/CHANGELOG b/vendor/rails/activesupport/CHANGELOG
index e6edc33a..600b5703 100644
--- a/vendor/rails/activesupport/CHANGELOG
+++ b/vendor/rails/activesupport/CHANGELOG
@@ -1,3 +1,5 @@
+*2.3.11 (February 9, 2011)*
+
*2.3.10 (October 15, 2010)*
diff --git a/vendor/rails/activesupport/lib/active_support/basic_object.rb b/vendor/rails/activesupport/lib/active_support/basic_object.rb
index 1f77209e..3b5277c2 100644
--- a/vendor/rails/activesupport/lib/active_support/basic_object.rb
+++ b/vendor/rails/activesupport/lib/active_support/basic_object.rb
@@ -1,13 +1,7 @@
-# A base class with no predefined methods that tries to behave like Builder's
-# BlankSlate in Ruby 1.9. In Ruby pre-1.9, this is actually the
-# Builder::BlankSlate class.
-#
-# Ruby 1.9 introduces BasicObject which differs slightly from Builder's
-# BlankSlate that has been used so far. ActiveSupport::BasicObject provides a
-# barebones base class that emulates Builder::BlankSlate while still relying on
-# Ruby 1.9's BasicObject in Ruby 1.9.
module ActiveSupport
if defined? ::BasicObject
+ # A class with no predefined methods that behaves similarly to Builder's
+ # BlankSlate. Used for proxy classes.
class BasicObject < ::BasicObject
undef_method :==
undef_method :equal?
@@ -18,7 +12,10 @@ module ActiveSupport
end
end
else
- require 'blankslate'
- BasicObject = BlankSlate
+ class BasicObject #:nodoc:
+ instance_methods.each do |m|
+ undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$)/
+ end
+ end
end
end
diff --git a/vendor/rails/activesupport/lib/active_support/buffered_logger.rb b/vendor/rails/activesupport/lib/active_support/buffered_logger.rb
index 6c35b190..63c61543 100644
--- a/vendor/rails/activesupport/lib/active_support/buffered_logger.rb
+++ b/vendor/rails/activesupport/lib/active_support/buffered_logger.rb
@@ -1,3 +1,5 @@
+require 'thread'
+
module ActiveSupport
# Inspired by the buffered logger idea by Ezra
class BufferedLogger
diff --git a/vendor/rails/activesupport/lib/active_support/locale/en.yml b/vendor/rails/activesupport/lib/active_support/locale/en.yml
index e604c9ee..49ad192b 100644
--- a/vendor/rails/activesupport/lib/active_support/locale/en.yml
+++ b/vendor/rails/activesupport/lib/active_support/locale/en.yml
@@ -15,7 +15,10 @@ en:
month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December]
abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
# Used in date_select and datime_select.
- order: [ :year, :month, :day ]
+ order:
+ - :year
+ - :month
+ - :day
time:
formats:
diff --git a/vendor/rails/activesupport/lib/active_support/version.rb b/vendor/rails/activesupport/lib/active_support/version.rb
index 835a507d..922d12ff 100644
--- a/vendor/rails/activesupport/lib/active_support/version.rb
+++ b/vendor/rails/activesupport/lib/active_support/version.rb
@@ -2,7 +2,7 @@ module ActiveSupport
module VERSION #:nodoc:
MAJOR = 2
MINOR = 3
- TINY = 10
+ TINY = 11
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/vendor/rails/activesupport/test/core_ext/module/synchronization_test.rb b/vendor/rails/activesupport/test/core_ext/module/synchronization_test.rb
index c28bc9b0..73430223 100644
--- a/vendor/rails/activesupport/test/core_ext/module/synchronization_test.rb
+++ b/vendor/rails/activesupport/test/core_ext/module/synchronization_test.rb
@@ -1,4 +1,5 @@
require 'abstract_unit'
+require 'thread'
class SynchronizationTest < Test::Unit::TestCase
def setup
diff --git a/vendor/rails/railties/CHANGELOG b/vendor/rails/railties/CHANGELOG
index bdbec15b..2e292142 100644
--- a/vendor/rails/railties/CHANGELOG
+++ b/vendor/rails/railties/CHANGELOG
@@ -1,3 +1,5 @@
+*2.3.11 (February 9, 2011)*
+
*2.3.10 (October 15, 2010)*
*2.3.9 (September 4, 2010)*
diff --git a/vendor/rails/railties/Rakefile b/vendor/rails/railties/Rakefile
index 20865bd4..ebf7c68e 100644
--- a/vendor/rails/railties/Rakefile
+++ b/vendor/rails/railties/Rakefile
@@ -313,11 +313,11 @@ spec = Gem::Specification.new do |s|
EOF
s.add_dependency('rake', '>= 0.8.3')
- s.add_dependency('activesupport', '= 2.3.10' + PKG_BUILD)
- s.add_dependency('activerecord', '= 2.3.10' + PKG_BUILD)
- s.add_dependency('actionpack', '= 2.3.10' + PKG_BUILD)
- s.add_dependency('actionmailer', '= 2.3.10' + PKG_BUILD)
- s.add_dependency('activeresource', '= 2.3.10' + PKG_BUILD)
+ s.add_dependency('activesupport', '= 2.3.11' + PKG_BUILD)
+ s.add_dependency('activerecord', '= 2.3.11' + PKG_BUILD)
+ s.add_dependency('actionpack', '= 2.3.11' + PKG_BUILD)
+ s.add_dependency('actionmailer', '= 2.3.11' + PKG_BUILD)
+ s.add_dependency('activeresource', '= 2.3.11' + PKG_BUILD)
s.rdoc_options << '--exclude' << '.'
s.has_rdoc = false
diff --git a/vendor/rails/railties/guides/source/action_mailer_basics.textile b/vendor/rails/railties/guides/source/action_mailer_basics.textile
index 9476635a..ed42f518 100644
--- a/vendor/rails/railties/guides/source/action_mailer_basics.textile
+++ b/vendor/rails/railties/guides/source/action_mailer_basics.textile
@@ -218,7 +218,9 @@ If you set a default +:host+ for your mailers you need to pass +:only_path => fa
h4. Sending Multipart Emails
-Action Mailer will automatically send multipart emails if you have different templates for the same action. So, for our UserMailer example, if you have +welcome_email.text.plain.erb+ and +welcome_email.text.html.erb+ in +app/views/user_mailer+, Action Mailer will automatically send a multipart email with the HTML and text versions setup as different parts.
+Action Mailer will automatically send multipart emails if you have different templates for the same action. So, for our UserMailer example, if you have +welcome_email.text.plain.erb+ and +welcome_email.text.html.erb+ in +app/views/user_mailer+, Action Mailer will automatically send a "multipart/alternative" email with the HTML and text versions setup as different parts.
+
+A "multipart/alternative" content type tells your email client that there are several representations of the same content available and that the email client is free to choose any one to display to the user. In this case we are giving a plain text and HTML version of the same message. But this could also be a text version, and a recording of someone speaking the the same message. It is important to use "multipart/alternative" only when each part has the same content.
To explicitly specify multipart messages, you can do something like:
@@ -242,7 +244,11 @@ end
h4. Sending Emails with Attachments
-Attachments can be added by using the +attachment+ method:
+Attachments can be added by using the +attachment+ method. The +attachment+ method has two variations, you can either pass the body in as an option, or create it within a block.
+
+Usually you will use the variation shown below for the "image/jpeg" attachment, here you just pass in the content type and body as a options hash to the attachment method. However, if you need to do some processing to create the attachment, such as with the PDF below, then the block variation can be used.
+
+This email uses the "multipart/mixed" content type because each part is a different block of content. This indicates to the email client that it must show all the parts that it can display to the end user.
class UserMailer < ActionMailer::Base
@@ -250,13 +256,14 @@ class UserMailer < ActionMailer::Base
recipients user.email_address
subject "New account information"
from "system@example.com"
- content_type "multipart/alternative"
+ content_type "multipart/mixed"
attachment :content_type => "image/jpeg",
:body => File.read("an-image.jpg")
attachment "application/pdf" do |a|
- a.body = generate_your_pdf_here()
+ pdf = generate_your_pdf_here(:name => user)
+ a.body = pdf
end
end
end
@@ -266,7 +273,11 @@ h4. Sending Multipart Emails with Attachments
Once you use the +attachment+ method, ActionMailer will no longer automagically use the correct template based on the filename. You must declare which template you are using for each content type via the +part+ method.
-In the following example, there would be two template files, +welcome_email_html.erb+ and +welcome_email_plain.erb+ in the +app/views/user_mailer+ folder.
+Here we are making the email "multipart/mixed" with three top level parts, a "multipart/alternative", an "image/jpeg" and an "application/pdf". Within the "multipart/alternative" we are nesting a "text/html" and "text/plain" version of the same message.
+
+This tells the email client that each of the top level parts should be shown to the end user, however, the first part has the content type "multipart/alternative" and provides two versions of the same message, a plain text and HTML version.
+
+In the following example, there would be two template files, +welcome_email.text.html.erb+ and +welcome_email.text.plain.erb+ in the +app/views/user_mailer+ folder.
class UserMailer < ActionMailer::Base
@@ -274,22 +285,28 @@ class UserMailer < ActionMailer::Base
recipients user.email_address
subject "New account information"
from "system@example.com"
- content_type "multipart/alternative"
+ content_type "multipart/mixed"
- part "text/html" do |p|
- p.body = render_message("welcome_email_html", :message => "
HTML content
")
- end
+ part "multipart/alternative" do |alternative|
+
+ alternative.part "text/html" do |html|
+ html.body = render_message("welcome_email.text.html", :message => "
HTML content
")
+ end
+
+ alternative.part "text/plain" do |plain|
+ plain.body = render_message("welcome_email.text.plain", :message => "text content")
+ end
- part "text/plain" do |p|
- p.body = render_message("welcome_email_plain", :message => "text content")
end
attachment :content_type => "image/jpeg",
:body => File.read("an-image.jpg")
attachment "application/pdf" do |a|
- a.body = generate_your_pdf_here()
+ pdf = generate_your_pdf_here(:name => user)
+ a.body = pdf
end
+
end
end
diff --git a/vendor/rails/railties/lib/rails/version.rb b/vendor/rails/railties/lib/rails/version.rb
index 28ff027a..2f557201 100644
--- a/vendor/rails/railties/lib/rails/version.rb
+++ b/vendor/rails/railties/lib/rails/version.rb
@@ -2,7 +2,7 @@ module Rails
module VERSION #:nodoc:
MAJOR = 2
MINOR = 3
- TINY = 10
+ TINY = 11
STRING = [MAJOR, MINOR, TINY].join('.')
end