aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md32
-rw-r--r--actionpack/README.rdoc285
-rw-r--r--actionpack/examples/performance.rb185
-rw-r--r--actionpack/examples/views/_collection.erb3
-rw-r--r--actionpack/examples/views/_hello.erb1
-rw-r--r--actionpack/examples/views/_hundred_partials.erb3
-rw-r--r--actionpack/examples/views/_partial.erb10
-rw-r--r--actionpack/examples/views/_ten_partials.erb10
-rw-r--r--actionpack/examples/views/hashes/_hash.erb3
-rw-r--r--actionpack/examples/views/my_hashes/_my_hash.erb3
-rw-r--r--actionpack/examples/views/template.html.erb1
-rw-r--r--actionpack/lib/action_controller/caching/fragments.rb44
-rw-r--r--actionpack/lib/action_controller/metal/live.rb20
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb5
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb11
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb5
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb6
-rw-r--r--actionpack/lib/action_dispatch/railtie.rb1
-rw-r--r--actionpack/lib/action_view/helpers/cache_helper.rb32
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb19
-rw-r--r--actionpack/lib/action_view/helpers/javascript_helper.rb40
-rw-r--r--actionpack/lib/action_view/helpers/sanitize_helper.rb2
-rw-r--r--actionpack/test/abstract_unit.rb62
-rw-r--r--actionpack/test/controller/caching_test.rb42
-rw-r--r--actionpack/test/dispatch/cookies_test.rb2
-rw-r--r--actionpack/test/dispatch/response_test.rb27
-rw-r--r--actionpack/test/template/form_helper_test.rb6
-rw-r--r--actionpack/test/template/javascript_helper_test.rb42
-rw-r--r--actionpack/test/template/sanitize_helper_test.rb4
-rw-r--r--activemodel/lib/active_model/naming.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/connection_test.rb19
-rw-r--r--activesupport/CHANGELOG.md6
-rw-r--r--activesupport/lib/active_support/json/encoding.rb1
-rw-r--r--activesupport/lib/active_support/json/variable.rb17
-rw-r--r--activesupport/test/json/encoding_test.rb7
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/application.rb8
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt3
-rw-r--r--railties/test/application/assets_test.rb26
38 files changed, 320 insertions, 681 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 236768227c..880263ce87 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,5 +1,35 @@
## Rails 4.0.0 (unreleased) ##
+* Add 'X-Frame-Options' => 'SAMEORIGIN' and
+ 'X-XSS-Protection' => '1; mode=block'
+ as default headers.
+
+ *Egor Homakov*
+
+* Allow data attributes to be set as a first-level option for form_for, so you can write `form_for @record, data: { behavior: 'autosave' }` instead of `form_for @record, html: { data: { behavior: 'autosave' } }` *DHH*
+
+* Deprecate `button_to_function` and `link_to_function` helpers.
+
+ We recommend the use of Unobtrusive JavaScript instead. For example:
+
+ link_to "Greeting", "#", :class => "nav_link"
+
+ $(function() {
+ $('.nav_link').click(function() {
+ // Some complex code
+
+ return false;
+ });
+ });
+
+ or
+
+ link_to "Greeting", '#', onclick: "alert('Hello world!'); return false", class: "nav_link"
+
+ for simple cases.
+
+ *Rafael Mendonça França*
+
* `javascript_include_tag :all` will now not include `application.js` if the file does not exists. *Prem Sichanugrist*
* Send an empty response body when call `head` with status between 100 and 199, 204, 205 or 304.
@@ -146,8 +176,6 @@
* Replace `include_seconds` boolean argument with `:include_seconds => true` option
in `distance_of_time_in_words` and `time_ago_in_words` signature. *Dmitriy Kiriyenko*
-* Remove `button_to_function` and `link_to_function` helpers. *Rafael Mendonça França*
-
* Make current object and counter (when it applies) variables accessible when
rendering templates with :object / :collection. *Carlos Antonio da Silva*
diff --git a/actionpack/README.rdoc b/actionpack/README.rdoc
index 1fdc57e14d..ccd0193515 100644
--- a/actionpack/README.rdoc
+++ b/actionpack/README.rdoc
@@ -28,291 +28,6 @@ by default and Action View rendering is implicitly triggered by Action
Controller. However, these modules are designed to function on their own and
can be used outside of Rails.
-A short rundown of some of the major features:
-
-* Actions grouped in controller as methods instead of separate command objects
- and can therefore share helper methods
-
- class CustomersController < ActionController::Base
- def show
- @customer = find_customer
- end
-
- def update
- @customer = find_customer
- if @customer.update_attributes(params[:customer])
- redirect_to :action => "show"
- else
- render :action => "edit"
- end
- end
-
- private
- def find_customer
- Customer.find params[:id]
- end
- end
-
- {Learn more}[link:classes/ActionController/Base.html]
-
-
-* ERB templates (static content mixed with dynamic output from ruby)
-
- <% @posts.each do |post| %>
- Title: <%= post.title %>
- <% end %>
-
- All post titles: <%= @posts.collect{ |p| p.title }.join(", ") %>
-
- <% unless @person.is_client? %>
- Not for clients to see...
- <% end %>
-
- {Learn more}[link:classes/ActionView.html]
-
-
-* "Builder" templates (great for XML content, like RSS)
-
- xml.rss("version" => "2.0") do
- xml.channel do
- xml.title(@feed_title)
- xml.link(@url)
- xml.description "Basecamp: Recent items"
- xml.language "en-us"
- xml.ttl "40"
-
- @recent_items.each do |item|
- xml.item do
- xml.title(item_title(item))
- xml.description(item_description(item))
- xml.pubDate(item_pubDate(item))
- xml.guid(@recent_items.url(item))
- xml.link(@recent_items.url(item))
- end
- end
- end
- end
-
- {Learn more}[link:classes/ActionView/Base.html]
-
-
-* Filters for pre- and post-processing of the response
-
- class WeblogController < ActionController::Base
- # filters as methods
- before_filter :authenticate, :cache, :audit
-
- # filter as a proc
- after_filter { |c| c.response.body = Gzip::compress(c.response.body) }
-
- # class filter
- after_filter LocalizeFilter
-
- def index
- # Before this action is run, the user will be authenticated, the cache
- # will be examined to see if a valid copy of the results already
- # exists, and the action will be logged for auditing.
-
- # After this action has run, the output will first be localized then
- # compressed to minimize bandwidth usage
- end
-
- private
- def authenticate
- # Implement the filter with full access to both request and response
- end
- end
-
- {Learn more}[link:classes/ActionController/Filters/ClassMethods.html]
-
-
-* Helpers for forms, dates, action links, and text
-
- <%= text_field_tag "post", "title", "size" => 30 %>
- <%= link_to "New post", :controller => "post", :action => "new" %>
- <%= truncate(post.title, :length => 25) %>
-
- {Learn more}[link:classes/ActionView/Helpers.html]
-
-
-* Layout sharing for template reuse
-
- class WeblogController < ActionController::Base
- layout "weblog_layout"
-
- def hello_world
- end
- end
-
- Layout file (called weblog_layout):
- <html><body><%= yield %></body></html>
-
- Template for hello_world action:
- <h1>Hello world</h1>
-
- Result of running hello_world action:
- <html><body><h1>Hello world</h1></body></html>
-
- {Learn more}[link:classes/ActionController/Layout/ClassMethods.html]
-
-
-* Routing makes pretty URLs incredibly easy
-
- match 'clients/:client_name/:project_name/:controller/:action'
-
- Accessing "/clients/37signals/basecamp/project/index" calls ProjectController#index with
- { "client_name" => "37signals", "project_name" => "basecamp" } in `params`
-
- From that action, you can write the redirect in a number of ways:
-
- redirect_to(:action => "edit") =>
- /clients/37signals/basecamp/project/edit
-
- redirect_to(:client_name => "nextangle", :project_name => "rails") =>
- /clients/nextangle/rails/project/index
-
- {Learn more}[link:classes/ActionDispatch/Routing.html]
-
-
-* Easy testing of both controller and rendered template through ActionController::TestCase
-
- class LoginControllerTest < ActionController::TestCase
- def test_failing_authenticate
- process :authenticate, :user_name => "nop", :password => ""
- assert flash.has_key?(:alert)
- assert_redirected_to :action => "index"
- end
- end
-
- {Learn more}[link:classes/ActionController/TestCase.html]
-
-
-* Automated benchmarking and integrated logging
-
- Started GET "/weblog" for 127.0.0.1 at Fri May 28 00:41:55
- Processing by WeblogController#index as HTML
- Rendered weblog/index.html.erb within layouts/application (25.7ms)
- Completed 200 OK in 29.3ms
-
- If Active Record is used as the model, you'll have the database debugging
- as well:
-
- Started POST "/posts" for 127.0.0.1 at Sat Jun 19 14:04:23
- Processing by PostsController#create as HTML
- Parameters: {"post"=>{"title"=>"this is good"}}
- SQL (0.6ms) INSERT INTO posts (title) VALUES('this is good')
- Redirected to http://example.com/posts/5
- Completed 302 Found in 221ms (Views: 215ms | ActiveRecord: 0.6ms)
-
- You specify a logger through a class method, such as:
-
- ActionController::Base.logger = ActiveSupport::Logger.new("Application Log")
- ActionController::Base.logger = Log4r::Logger.new("Application Log")
-
-
-* Caching at three levels of granularity (page, action, fragment)
-
- class WeblogController < ActionController::Base
- caches_page :show
- caches_action :account
-
- def show
- # the output of the method will be cached as
- # ActionController::Base.page_cache_directory + "/weblog/show.html"
- # and the web server will pick it up without even hitting Rails
- end
-
- def account
- # the output of the method will be cached in the fragment store
- # but Rails is hit to retrieve it, so filters are run
- end
-
- def update
- List.update(params[:list][:id], params[:list])
- expire_page :action => "show", :id => params[:list][:id]
- expire_action :action => "account"
- redirect_to :action => "show", :id => params[:list][:id]
- end
- end
-
- {Learn more}[link:classes/ActionController/Caching.html]
-
-
-* Powerful debugging mechanism for local requests
-
- All exceptions raised on actions performed on the request of a local user
- will be presented with a tailored debugging screen that includes exception
- message, stack trace, request parameters, session contents, and the
- half-finished response.
-
- {Learn more}[link:classes/ActionController/Rescue.html]
-
-
-== Simple example (from outside of Rails)
-
-This example will implement a simple weblog system using inline templates and
-an Active Record model. So let's build that WeblogController with just a few
-methods:
-
- require 'action_controller'
- require 'post'
-
- class WeblogController < ActionController::Base
- layout "weblog/layout"
-
- def index
- @posts = Post.all
- end
-
- def show
- @post = Post.find(params[:id])
- end
-
- def new
- @post = Post.new
- end
-
- def create
- @post = Post.create(params[:post])
- redirect_to :action => "show", :id => @post.id
- end
- end
-
- WeblogController::Base.view_paths = [ File.dirname(__FILE__) ]
- WeblogController.process_cgi if $0 == __FILE__
-
-The last two lines are responsible for telling ActionController where the
-template files are located and actually running the controller on a new
-request from the web-server (e.g., Apache).
-
-And the templates look like this:
-
- weblog/layout.html.erb:
- <html><body>
- <%= yield %>
- </body></html>
-
- weblog/index.html.erb:
- <% @posts.each do |post| %>
- <p><%= link_to(post.title, :action => "show", :id => post.id) %></p>
- <% end %>
-
- weblog/show.html.erb:
- <p>
- <b><%= @post.title %></b><br/>
- <b><%= @post.content %></b>
- </p>
-
- weblog/new.html.erb:
- <%= form "post" %>
-
-This simple setup will list all the posts in the system on the index page,
-which is called by accessing /weblog/. It uses the form builder for the Active
-Record model to make the new screen, which in turn hands everything over to
-the create action (that's the default target for the form builder when given a
-new model). After creating the post, it'll redirect to the show page using
-an URL such as /weblog/5 (where 5 is the id of the post).
-
== Download and installation
diff --git a/actionpack/examples/performance.rb b/actionpack/examples/performance.rb
deleted file mode 100644
index 8ea4758961..0000000000
--- a/actionpack/examples/performance.rb
+++ /dev/null
@@ -1,185 +0,0 @@
-ENV['RAILS_ENV'] ||= 'production'
-
-require File.expand_path('../../../load_paths', __FILE__)
-require 'action_pack'
-require 'action_controller'
-require 'action_view'
-require 'active_model'
-require 'benchmark'
-
-MyHash = Class.new(Hash)
-
-Hash.class_eval do
- extend ActiveModel::Naming
- include ActiveModel::Conversion
-end
-
-class Runner
- def initialize(app, output)
- @app, @output = app, output
- end
-
- def puts(*)
- super if @output
- end
-
- def call(env)
- env['n'].to_i.times { @app.call(env) }
- @app.call(env).tap { |response| report(env, response) }
- end
-
- def report(env, response)
- return unless ENV["DEBUG"]
- out = env['rack.errors']
- out.puts response[0], response[1].to_yaml, '---'
- response[2].each { |part| out.puts part }
- out.puts '---'
- end
-
- def self.puts(*)
- super if @output
- end
-
- def self.print(*)
- super if @output
- end
-
- def self.app_and_env_for(action, n)
- env = Rack::MockRequest.env_for("/")
- env.merge!('n' => n, 'rack.input' => StringIO.new(''), 'rack.errors' => $stdout)
- app = lambda { |env| BasePostController.action(action).call(env) }
- return app, env
- end
-
- $ran = []
-
- def self.run(action, n, output = true)
- print "."
- STDOUT.flush
- @output = output
- label = action.to_s
- app, env = app_and_env_for(action, n)
- t = Benchmark.realtime { new(app, output).call(env) }
- $ran << [label, (t * 1000).to_i.to_s] if output
- end
-
- def self.done
- puts
- header, content = "", ""
- $ran.each do |k,v|
- size = [k.size, v.size].max + 1
- header << format("%#{size}s", k)
- content << format("%#{size}s", v)
- end
- puts header
- puts content
- end
-end
-
-ActionController::Base.logger = nil
-ActionController::Base.config.compile_methods!
-ActionView::Resolver.caching = ENV["RAILS_ENV"] == "production"
-
-class BasePostController < ActionController::Base
- append_view_path "#{File.dirname(__FILE__)}/views"
-
- def overhead
- self.response_body = ''
- end
-
- def index
- render :text => ''
- end
-
- $OBJECT = {:name => "Hello my name is omg", :address => "333 omg"}
-
- def partial
- render :partial => "/collection", :object => $OBJECT
- end
-
- def partial_10
- render :partial => "/ten_partials"
- end
-
- def partial_100
- render :partial => "/hundred_partials"
- end
-
- $COLLECTION1 = []
- 10.times do |i|
- $COLLECTION1 << { :name => "Hello my name is omg", :address => "333 omg" }
- end
-
- def coll_10
- render :partial => "/collection", :collection => $COLLECTION1
- end
-
- $COLLECTION2 = []
- 100.times do |i|
- $COLLECTION2 << { :name => "Hello my name is omg", :address => "333 omg" }
- end
-
- def coll_100
- render :partial => "/collection", :collection => $COLLECTION2
- end
-
- def uniq_100
- render :partial => $COLLECTION2
- end
-
- $COLLECTION3 = []
- 50.times do |i|
- $COLLECTION3 << {:name => "Hello my name is omg", :address => "333 omg"}
- $COLLECTION3 << MyHash.new(:name => "Hello my name is omg", :address => "333 omg")
- end
-
- def diff_100
- render :partial => $COLLECTION3
- end
-
- def template_1
- render :template => "template"
- end
-
- module Foo
- def omg
- "omg"
- end
- end
-
- helper Foo
-end
-
-N = (ENV['N'] || 1000).to_i
-# ActionController::Base.use_accept_header = false
-
-def run_all!(times, verbose)
- Runner.run(:overhead, times, verbose)
- Runner.run(:index, times, verbose)
- Runner.run(:template_1, times, verbose)
- Runner.run(:partial, times, verbose)
- Runner.run(:partial_10, times, verbose)
- Runner.run(:coll_10, times, verbose)
- Runner.run(:partial_100, times, verbose)
- Runner.run(:coll_100, times, verbose)
- Runner.run(:uniq_100, times, verbose)
- Runner.run(:diff_100, times, verbose)
-end
-
-if ENV["PROFILE"]
- Runner.run(ENV["PROFILE"].to_sym, 1, false)
- require "ruby-prof"
- RubyProf.start
- Runner.run(ENV["PROFILE"].to_sym, N, true)
- result = RubyProf.stop
- printer = RubyProf::CallStackPrinter.new(result)
- printer.print(File.open("output.html", "w"))
-else
- run_all!(1, false)
-
- (ENV["M"] || 1).to_i.times do
- $ran = []
- run_all!(N, true)
- Runner.done
- end
-end \ No newline at end of file
diff --git a/actionpack/examples/views/_collection.erb b/actionpack/examples/views/_collection.erb
deleted file mode 100644
index cee3fe64c0..0000000000
--- a/actionpack/examples/views/_collection.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-<%= collection[:name] %>
-<%= collection[:address] %>
-<%= omg %> \ No newline at end of file
diff --git a/actionpack/examples/views/_hello.erb b/actionpack/examples/views/_hello.erb
deleted file mode 100644
index 5ab2f8a432..0000000000
--- a/actionpack/examples/views/_hello.erb
+++ /dev/null
@@ -1 +0,0 @@
-Hello \ No newline at end of file
diff --git a/actionpack/examples/views/_hundred_partials.erb b/actionpack/examples/views/_hundred_partials.erb
deleted file mode 100644
index 35c2a6c9d3..0000000000
--- a/actionpack/examples/views/_hundred_partials.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-<% 100.times do %>
- <%= render :partial => "/collection", :object => $OBJECT %>
-<% end %> \ No newline at end of file
diff --git a/actionpack/examples/views/_partial.erb b/actionpack/examples/views/_partial.erb
deleted file mode 100644
index 3ca8e80b52..0000000000
--- a/actionpack/examples/views/_partial.erb
+++ /dev/null
@@ -1,10 +0,0 @@
-<%= "Hello" %>
-<%= "Hello" %>
-<%= "Hello" %>
-<%= "Hello" %>
-<%= "Hello" %>
-<%= "Hello" %>
-<%= "Hello" %>
-<%= "Hello" %>
-<%= "Hello" %>
-<%= "Hello" %>
diff --git a/actionpack/examples/views/_ten_partials.erb b/actionpack/examples/views/_ten_partials.erb
deleted file mode 100644
index fd02991e22..0000000000
--- a/actionpack/examples/views/_ten_partials.erb
+++ /dev/null
@@ -1,10 +0,0 @@
-<%= render :partial => '/collection', :object => $OBJECT %>
-<%= render :partial => '/collection', :object => $OBJECT %>
-<%= render :partial => '/collection', :object => $OBJECT %>
-<%= render :partial => '/collection', :object => $OBJECT %>
-<%= render :partial => '/collection', :object => $OBJECT %>
-<%= render :partial => '/collection', :object => $OBJECT %>
-<%= render :partial => '/collection', :object => $OBJECT %>
-<%= render :partial => '/collection', :object => $OBJECT %>
-<%= render :partial => '/collection', :object => $OBJECT %>
-<%= render :partial => '/collection', :object => $OBJECT %> \ No newline at end of file
diff --git a/actionpack/examples/views/hashes/_hash.erb b/actionpack/examples/views/hashes/_hash.erb
deleted file mode 100644
index c100a290bd..0000000000
--- a/actionpack/examples/views/hashes/_hash.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-<%= hash[:name] %>
-<%= hash[:address] %>
-<%= omg %> \ No newline at end of file
diff --git a/actionpack/examples/views/my_hashes/_my_hash.erb b/actionpack/examples/views/my_hashes/_my_hash.erb
deleted file mode 100644
index e25d84101a..0000000000
--- a/actionpack/examples/views/my_hashes/_my_hash.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-<%= my_hash[:name] %>
-<%= my_hash[:address] %>
-<%= omg %> \ No newline at end of file
diff --git a/actionpack/examples/views/template.html.erb b/actionpack/examples/views/template.html.erb
deleted file mode 100644
index 5ab2f8a432..0000000000
--- a/actionpack/examples/views/template.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-Hello \ No newline at end of file
diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb
index abeb49d16f..9c77b0ccf4 100644
--- a/actionpack/lib/action_controller/caching/fragments.rb
+++ b/actionpack/lib/action_controller/caching/fragments.rb
@@ -5,48 +5,18 @@ module ActionController #:nodoc:
# useful when certain elements of an action change frequently or
# depend on complicated state while other parts rarely change or
# can be shared amongst multiple parties. The caching is done using
- # the <tt>cache</tt> helper available in the Action View. A
- # template with fragment caching might look like:
+ # the <tt>cache</tt> helper available in the Action View. See
+ # ActionView::Helpers::CacheHelper for more information.
#
- # <b>Hello <%= @name %></b>
+ # While it's strongly recommended that you use key-based cache
+ # expiration (see links in CacheHelper for more information),
+ # it is also possible to manually expire caches. For example:
#
- # <% cache do %>
- # All the topics in the system:
- # <%= render :partial => "topic", :collection => Topic.all %>
- # <% end %>
- #
- # This cache will bind the name of the action that called it, so if
- # this code was part of the view for the topics/list action, you
- # would be able to invalidate it using:
- #
- # expire_fragment(:controller => "topics", :action => "list")
- #
- # This default behavior is limited if you need to cache multiple
- # fragments per action or if the action itself is cached using
- # <tt>caches_action</tt>. To remedy this, there is an option to
- # qualify the name of the cached fragment by using the
- # <tt>:action_suffix</tt> option:
- #
- # <% cache(:action => "list", :action_suffix => "all_topics") do %>
- #
- # That would result in a name such as
- # <tt>/topics/list/all_topics</tt>, avoiding conflicts with the
- # action cache and with any fragments that use a different suffix.
- # Note that the URL doesn't have to really exist or be callable
- # - the url_for system is just used to generate unique cache names
- # that we can refer to when we need to expire the cache.
- #
- # The expiration call for this example is:
- #
- # expire_fragment(:controller => "topics",
- # :action => "list",
- # :action_suffix => "all_topics")
+ # expire_fragment("name_of_cache")
module Fragments
# Given a key (as described in <tt>expire_fragment</tt>), returns
# a key suitable for use in reading, writing, or expiring a
- # cached fragment. If the key is a hash, the generated key is the
- # return value of url_for on that hash (without the protocol).
- # All keys are prefixed with <tt>views/</tt> and uses
+ # cached fragment. All keys are prefixed with <tt>views/</tt> and uses
# ActiveSupport::Cache.expand_cache_key for the expansion.
def fragment_cache_key(key)
ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, :views)
diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb
index 43a9e3aa9d..d8fe43b5af 100644
--- a/actionpack/lib/action_controller/metal/live.rb
+++ b/actionpack/lib/action_controller/metal/live.rb
@@ -33,13 +33,13 @@ module ActionController
module Live
class Buffer < ActionDispatch::Response::Buffer #:nodoc:
def initialize(response)
- super(response, Queue.new)
+ super(response, SizedQueue.new(10))
end
def write(string)
unless @response.committed?
@response.headers["Cache-Control"] = "no-cache"
- @response.headers.delete("Content-Length")
+ @response.headers.delete "Content-Length"
end
super
@@ -47,13 +47,13 @@ module ActionController
def each
while str = @buf.pop
- yield(str)
+ yield str
end
end
def close
super
- @buf.push(nil)
+ @buf.push nil
end
end
@@ -78,7 +78,7 @@ module ActionController
end
def initialize(status = 200, header = {}, body = [])
- header = Header.new(self, header)
+ header = Header.new self, header
super(status, header, body)
end
@@ -89,11 +89,11 @@ module ActionController
private
- def build_buffer(response, body)
- buf = Live::Buffer.new(response)
- body.each { |part| buf.write(part) }
- buf
- end
+ def build_buffer(response, body)
+ buf = Live::Buffer.new response
+ body.each { |part| buf.write part }
+ buf
+ end
end
def process(name)
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index bcfd0b0d00..9a7b5bc8c7 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -4,6 +4,11 @@ require 'active_support/core_ext/hash/indifferent_access'
module ActionDispatch
module Http
module Parameters
+ def initialize(env)
+ super
+ @symbolized_path_params = nil
+ end
+
# Returns both GET and POST \parameters in a single hash.
def parameters
@env["action_dispatch.request.parameters"] ||= begin
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 1377e53ce8..d24c7c7f3f 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -38,6 +38,17 @@ module ActionDispatch
METHOD
end
+ def initialize(env)
+ super
+ @method = nil
+ @request_method = nil
+ @remote_ip = nil
+ @original_fullpath = nil
+ @fullpath = nil
+ @ip = nil
+ @uuid = nil
+ end
+
def key?(key)
@env.key?(key)
end
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index d336808e7c..5014ad80aa 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -58,6 +58,7 @@ module ActionDispatch # :nodoc:
LOCATION = "Location".freeze
cattr_accessor(:default_charset) { "utf-8" }
+ cattr_accessor(:default_headers)
include Rack::Response::Helpers
include ActionDispatch::Http::Cache::Response
@@ -96,6 +97,10 @@ module ActionDispatch # :nodoc:
def initialize(status = 200, header = {}, body = [])
super()
+ if self.class.default_headers.respond_to?(:merge)
+ header = self.class.default_headers.merge(header)
+ end
+
self.body, self.header, self.status = body, header, status
@sending_file = false
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index 4266ec042e..8aa02ec482 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -87,6 +87,12 @@ module ActionDispatch
end
end
+ def initialize(env)
+ super
+ @protocol = nil
+ @port = nil
+ end
+
# Returns the complete URL used for this request.
def url
protocol + host_with_port + fullpath
diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb
index 62f906219c..e7f3f07390 100644
--- a/actionpack/lib/action_dispatch/railtie.rb
+++ b/actionpack/lib/action_dispatch/railtie.rb
@@ -23,6 +23,7 @@ module ActionDispatch
ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length
ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header
ActionDispatch::Response.default_charset = app.config.action_dispatch.default_charset || app.config.encoding
+ ActionDispatch::Response.default_headers = app.config.action_dispatch.default_headers
ActionDispatch::ExceptionWrapper.rescue_responses.merge!(config.action_dispatch.rescue_responses)
ActionDispatch::ExceptionWrapper.rescue_templates.merge!(config.action_dispatch.rescue_templates)
diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb
index 33799d7d71..39518268df 100644
--- a/actionpack/lib/action_view/helpers/cache_helper.rb
+++ b/actionpack/lib/action_view/helpers/cache_helper.rb
@@ -8,28 +8,28 @@ module ActionView
# fragments, and so on. This method takes a block that contains
# the content you wish to cache.
#
- # See ActionController::Caching::Fragments for usage instructions.
+ # The best way to use this is by doing key-based cache expiration
+ # on top of a cache store like Memcached that'll automatically
+ # kick out old entries. For more on key-based expiration, see:
+ # http://37signals.com/svn/posts/3113-how-key-based-cache-expiration-works
#
- # If you want to cache a navigation menu, you can do following:
+ # When using this method, you list the cache dependencies as part of
+ # the name of the cache, like so:
#
- # <% cache do %>
- # <%= render :partial => "menu" %>
+ # <% cache [ "v1", project ] do %>
+ # <b>All the topics on this project</b>
+ # <%= render project.topics %>
# <% end %>
#
- # You can also cache static content:
+ # This approach will assume that when a new topic is added, you'll touch
+ # the project. The cache key generated from this call will be something like:
#
- # <% cache do %>
- # <p>Hello users! Welcome to our website!</p>
- # <% end %>
- #
- # Static content with embedded ruby content can be cached as
- # well:
+ # views/v1/projects/123-20120806214154
+ # ^class ^id ^updated_at
#
- # <% cache do %>
- # Topics:
- # <%= render :partial => "topics", :collection => @topic_list %>
- # <i>Topics listed alphabetically</i>
- # <% end %>
+ # If you update the rendering of topics, you just bump the version to v2.
+ # Otherwise the cache is automatically bumped whenever the project updated_at
+ # is touched.
def cache(name = {}, options = nil, &block)
if controller.perform_caching
safe_concat(fragment_for(name, options, &block))
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 13a5671a17..5cfcfdd8d5 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -323,6 +323,24 @@ module ActionView
# ...
# </form>
#
+ # === Setting HTML options
+ #
+ # You can set data attributes directly by passing in a data hash, but all other HTML options must be wrapped in
+ # the HTML key. Example:
+ #
+ # <%= form_for(@post, data: { behavior: "autosave" }, html: { name: "go" }) do |f| %>
+ # ...
+ # <% end %>
+ #
+ # The HTML generated for this would be:
+ #
+ # <form action='http://www.example.com' method='post' data-behavior='autosave' name='go'>
+ # <div style='margin:0;padding:0;display:inline'>
+ # <input name='_method' type='hidden' value='put' />
+ # </div>
+ # ...
+ # </form>
+ #
# === Removing hidden model id's
#
# The form_for method automatically includes the model id as a hidden field in the form.
@@ -409,6 +427,7 @@ module ActionView
apply_form_for_options!(record, object, options)
end
+ options[:html][:data] = options.delete(:data) if options.has_key?(:data)
options[:html][:remote] = options.delete(:remote) if options.has_key?(:remote)
options[:html][:method] = options.delete(:method) if options.has_key?(:method)
options[:html][:authenticity_token] = options.delete(:authenticity_token)
diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb
index cc20518b93..9f8cd8caaa 100644
--- a/actionpack/lib/action_view/helpers/javascript_helper.rb
+++ b/actionpack/lib/action_view/helpers/javascript_helper.rb
@@ -67,6 +67,46 @@ module ActionView
def javascript_cdata_section(content) #:nodoc:
"\n//#{cdata_section("\n#{content}\n//")}\n".html_safe
end
+
+ # Returns a button whose +onclick+ handler triggers the passed JavaScript.
+ #
+ # The helper receives a name, JavaScript code, and an optional hash of HTML options. The
+ # name is used as button label and the JavaScript code goes into its +onclick+ attribute.
+ # If +html_options+ has an <tt>:onclick</tt>, that one is put before +function+.
+ #
+ # button_to_function "Greeting", "alert('Hello world!')", :class => "ok"
+ # # => <input class="ok" onclick="alert('Hello world!');" type="button" value="Greeting" />
+ #
+ def button_to_function(name, function=nil, html_options={})
+ message = "button_to_function is deprecated and will be removed from Rails 4.1. Use Unobtrusive JavaScript instead."
+ ActiveSupport::Deprecation.warn message
+
+ onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};"
+
+ tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick))
+ end
+
+ # Returns a link whose +onclick+ handler triggers the passed JavaScript.
+ #
+ # The helper receives a name, JavaScript code, and an optional hash of HTML options. The
+ # name is used as the link text and the JavaScript code goes into the +onclick+ attribute.
+ # If +html_options+ has an <tt>:onclick</tt>, that one is put before +function+. Once all
+ # the JavaScript is set, the helper appends "; return false;".
+ #
+ # The +href+ attribute of the tag is set to "#" unless +html_options+ has one.
+ #
+ # link_to_function "Greeting", "alert('Hello world!')", :class => "nav_link"
+ # # => <a class="nav_link" href="#" onclick="alert('Hello world!'); return false;">Greeting</a>
+ #
+ def link_to_function(name, function, html_options={})
+ message = "link_to_function is deprecated and will be removed from Rails 4.1. Use Unobtrusive JavaScript instead."
+ ActiveSupport::Deprecation.warn message
+
+ onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
+ href = html_options[:href] || '#'
+
+ content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb
index a727b910e5..aaf0e0344a 100644
--- a/actionpack/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb
@@ -78,7 +78,7 @@ module ActionView
# strip_tags("<div id='top-bar'>Welcome to my website!</div>")
# # => Welcome to my website!
def strip_tags(html)
- self.class.full_sanitizer.sanitize(html).try(:html_safe)
+ self.class.full_sanitizer.sanitize(html)
end
# Strips all link tags from +text+ leaving just the link text.
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 56cebee678..b914bbce4d 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -85,39 +85,28 @@ module RenderERBUtils
end
end
-module SetupOnce
- extend ActiveSupport::Concern
-
- included do
- cattr_accessor :setup_once_block
- self.setup_once_block = nil
-
- setup :run_setup_once
- end
+SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
- module ClassMethods
- def setup_once(&block)
- self.setup_once_block = block
+module ActionDispatch
+ module SharedRoutes
+ def before_setup
+ @routes = SharedTestRoutes
+ super
end
end
- private
- def run_setup_once
- if self.setup_once_block
- self.setup_once_block.call
- self.setup_once_block = nil
- end
+ # Hold off drawing routes until all the possible controller classes
+ # have been loaded.
+ module DrawOnce
+ class << self
+ attr_accessor :drew
end
-end
+ self.drew = false
-SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
+ def before_setup
+ super
+ return if DrawOnce.drew
-module ActiveSupport
- class TestCase
- include SetupOnce
- # Hold off drawing routes until all the possible controller classes
- # have been loaded.
- setup_once do
SharedTestRoutes.draw do
get ':controller(/:action)'
end
@@ -125,10 +114,18 @@ module ActiveSupport
ActionDispatch::IntegrationTest.app.routes.draw do
get ':controller(/:action)'
end
+
+ DrawOnce.drew = true
end
end
end
+module ActiveSupport
+ class TestCase
+ include ActionDispatch::DrawOnce
+ end
+end
+
class RoutedRackApp
attr_reader :routes
@@ -159,9 +156,7 @@ class BasicController
end
class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
- setup do
- @routes = SharedTestRoutes
- end
+ include ActionDispatch::SharedRoutes
def self.build_app(routes = nil)
RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
@@ -290,10 +285,7 @@ module ActionController
class TestCase
include ActionDispatch::TestProcess
-
- setup do
- @routes = SharedTestRoutes
- end
+ include ActionDispatch::SharedRoutes
end
end
@@ -304,9 +296,7 @@ module ActionView
class TestCase
# Must repeat the setup because AV::TestCase is a duplication
# of AC::TestCase
- setup do
- @routes = SharedTestRoutes
- end
+ include ActionDispatch::SharedRoutes
end
end
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index d5afef9086..0efba5b77f 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -349,15 +349,18 @@ class ActionCachingMockController
end
class ActionCacheTest < ActionController::TestCase
+ tests ActionCachingTestController
+
def setup
super
- reset!
+ @request.host = 'hostname.com'
FileUtils.mkdir_p(FILE_STORE_PATH)
@path_class = ActionController::Caching::Actions::ActionCachePath
@mock_controller = ActionCachingMockController.new
end
def teardown
+ super
FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
end
@@ -367,7 +370,6 @@ class ActionCacheTest < ActionController::TestCase
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert fragment_exist?('hostname.com/action_caching_test')
- reset!
get :index
assert_response :success
@@ -380,7 +382,6 @@ class ActionCacheTest < ActionController::TestCase
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert !fragment_exist?('hostname.com/action_caching_test/destroy')
- reset!
get :destroy
assert_response :success
@@ -395,7 +396,6 @@ class ActionCacheTest < ActionController::TestCase
cached_time = content_to_cache
assert_not_equal cached_time, @response.body
assert fragment_exist?('hostname.com/action_caching_test/with_layout')
- reset!
get :with_layout
assert_response :success
@@ -410,7 +410,6 @@ class ActionCacheTest < ActionController::TestCase
cached_time = content_to_cache
assert_not_equal cached_time, @response.body
assert fragment_exist?('hostname.com/action_caching_test/layout_false')
- reset!
get :layout_false
assert_response :success
@@ -425,7 +424,6 @@ class ActionCacheTest < ActionController::TestCase
cached_time = content_to_cache
assert_not_equal cached_time, @response.body
assert fragment_exist?('hostname.com/action_caching_test/with_layout_proc_param')
- reset!
get :with_layout_proc_param, :layout => false
assert_response :success
@@ -440,7 +438,6 @@ class ActionCacheTest < ActionController::TestCase
cached_time = content_to_cache
assert_not_equal cached_time, @response.body
assert fragment_exist?('hostname.com/action_caching_test/with_layout_proc_param')
- reset!
get :with_layout_proc_param, :layout => true
assert_response :success
@@ -477,7 +474,6 @@ class ActionCacheTest < ActionController::TestCase
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert fragment_exist?('test.host/custom/show')
- reset!
get :show
assert_response :success
@@ -488,7 +484,6 @@ class ActionCacheTest < ActionController::TestCase
get :edit
assert_response :success
assert fragment_exist?('test.host/edit')
- reset!
get :edit, :id => 1
assert_response :success
@@ -499,22 +494,18 @@ class ActionCacheTest < ActionController::TestCase
get :index
assert_response :success
cached_time = content_to_cache
- reset!
get :index
assert_response :success
assert_equal cached_time, @response.body
- reset!
get :expire
assert_response :success
- reset!
get :index
assert_response :success
new_cached_time = content_to_cache
assert_not_equal cached_time, @response.body
- reset!
get :index
assert_response :success
@@ -524,12 +515,10 @@ class ActionCacheTest < ActionController::TestCase
def test_cache_expiration_isnt_affected_by_request_format
get :index
cached_time = content_to_cache
- reset!
@request.request_uri = "/action_caching_test/expire.xml"
get :expire, :format => :xml
assert_response :success
- reset!
get :index
assert_response :success
@@ -539,12 +528,10 @@ class ActionCacheTest < ActionController::TestCase
def test_cache_expiration_with_url_string
get :index
cached_time = content_to_cache
- reset!
@request.request_uri = "/action_caching_test/expire_with_url_string"
get :expire_with_url_string
assert_response :success
- reset!
get :index
assert_response :success
@@ -557,23 +544,17 @@ class ActionCacheTest < ActionController::TestCase
assert_response :success
jamis_cache = content_to_cache
- reset!
-
@request.host = 'david.hostname.com'
get :index
assert_response :success
david_cache = content_to_cache
assert_not_equal jamis_cache, @response.body
- reset!
-
@request.host = 'jamis.hostname.com'
get :index
assert_response :success
assert_equal jamis_cache, @response.body
- reset!
-
@request.host = 'david.hostname.com'
get :index
assert_response :success
@@ -583,8 +564,6 @@ class ActionCacheTest < ActionController::TestCase
def test_redirect_is_not_cached
get :redirected
assert_response :redirect
- reset!
-
get :redirected
assert_response :redirect
end
@@ -592,8 +571,6 @@ class ActionCacheTest < ActionController::TestCase
def test_forbidden_is_not_cached
get :forbidden
assert_response :forbidden
- reset!
-
get :forbidden
assert_response :forbidden
end
@@ -609,17 +586,14 @@ class ActionCacheTest < ActionController::TestCase
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert fragment_exist?('hostname.com/action_caching_test/index.xml')
- reset!
get :index, :format => 'xml'
assert_response :success
assert_equal cached_time, @response.body
assert_equal 'application/xml', @response.content_type
- reset!
get :expire_xml
assert_response :success
- reset!
get :index, :format => 'xml'
assert_response :success
@@ -724,14 +698,6 @@ class ActionCacheTest < ActionController::TestCase
assigns(:cache_this)
end
- def reset!
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
- @controller = ActionCachingTestController.new
- @controller.singleton_class.send(:include, @routes.url_helpers)
- @request.host = 'hostname.com'
- end
-
def fragment_exist?(path)
@controller.fragment_exist?(path)
end
diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb
index 2467654a70..347b3b3b5a 100644
--- a/actionpack/test/dispatch/cookies_test.rb
+++ b/actionpack/test/dispatch/cookies_test.rb
@@ -190,7 +190,7 @@ class CookiesTest < ActionController::TestCase
def test_setting_the_same_value_to_permanent_cookie
request.cookies[:user_name] = 'Jamie'
get :set_permanent_cookie
- assert response.cookies, 'user_name' => 'Jamie'
+ assert_equal response.cookies, 'user_name' => 'Jamie'
end
def test_setting_with_escapable_characters
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index e2903d4b36..71609d7340 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -176,6 +176,33 @@ class ResponseTest < ActiveSupport::TestCase
ActionDispatch::Response.default_charset = original
end
end
+
+ test "read x_frame_options and x_xss_protection" do
+ ActionDispatch::Response.default_headers = {
+ 'X-Frame-Options' => 'DENY',
+ 'X-XSS-Protection' => '1;'
+ }
+ resp = ActionDispatch::Response.new.tap { |response|
+ response.body = 'Hello'
+ }
+ resp.to_a
+
+ assert_equal('DENY', resp.headers['X-Frame-Options'])
+ assert_equal('1;', resp.headers['X-XSS-Protection'])
+ end
+
+ test "read custom default_header" do
+ ActionDispatch::Response.default_headers = {
+ 'X-XX-XXXX' => 'Here is my phone number'
+ }
+ resp = ActionDispatch::Response.new.tap { |response|
+ response.body = 'Hello'
+ }
+ resp.to_a
+
+ assert_equal('Here is my phone number', resp.headers['X-XX-XXXX'])
+ end
+
end
class ResponseIntegrationTest < ActionDispatch::IntegrationTest
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index a20a68c1b2..152b35ff0f 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -2637,6 +2637,12 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_form_for_with_data_attributes
+ form_for(@post, data: { behavior: "stuff" }, remote: true) {}
+ assert_match %r|data-behavior="stuff"|, output_buffer
+ assert_match %r|data-remote="true"|, output_buffer
+ end
+
def test_fields_for_returns_block_result
output = fields_for(Post.new) { |f| "fields" }
assert_equal "fields", output
diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb
index fe7607ee26..4a9a382afa 100644
--- a/actionpack/test/template/javascript_helper_test.rb
+++ b/actionpack/test/template/javascript_helper_test.rb
@@ -42,6 +42,48 @@ class JavaScriptHelperTest < ActionView::TestCase
assert_instance_of ActiveSupport::SafeBuffer, escape_javascript(ActiveSupport::SafeBuffer.new(given))
end
+ def test_button_to_function
+ assert_deprecated "button_to_function is deprecated and will be removed from Rails 4.1. Use Unobtrusive JavaScript instead." do
+ assert_dom_equal %(<input type="button" onclick="alert(&#x27;Hello world!&#x27;);" value="Greeting" />),
+ button_to_function("Greeting", "alert('Hello world!')")
+ end
+ end
+
+ def test_button_to_function_with_onclick
+ assert_deprecated "button_to_function is deprecated and will be removed from Rails 4.1. Use Unobtrusive JavaScript instead." do
+ assert_dom_equal "<input onclick=\"alert(&#x27;Goodbye World :(&#x27;); alert(&#x27;Hello world!&#x27;);\" type=\"button\" value=\"Greeting\" />",
+ button_to_function("Greeting", "alert('Hello world!')", :onclick => "alert('Goodbye World :(')")
+ end
+ end
+
+ def test_button_to_function_without_function
+ assert_deprecated "button_to_function is deprecated and will be removed from Rails 4.1. Use Unobtrusive JavaScript instead." do
+ assert_dom_equal "<input onclick=\";\" type=\"button\" value=\"Greeting\" />",
+ button_to_function("Greeting")
+ end
+ end
+
+ def test_link_to_function
+ assert_deprecated "link_to_function is deprecated and will be removed from Rails 4.1. Use Unobtrusive JavaScript instead." do
+ assert_dom_equal %(<a href="#" onclick="alert(&#x27;Hello world!&#x27;); return false;">Greeting</a>),
+ link_to_function("Greeting", "alert('Hello world!')")
+ end
+ end
+
+ def test_link_to_function_with_existing_onclick
+ assert_deprecated "link_to_function is deprecated and will be removed from Rails 4.1. Use Unobtrusive JavaScript instead." do
+ assert_dom_equal %(<a href="#" onclick="confirm(&#x27;Sanity!&#x27;); alert(&#x27;Hello world!&#x27;); return false;">Greeting</a>),
+ link_to_function("Greeting", "alert('Hello world!')", :onclick => "confirm('Sanity!')")
+ end
+ end
+
+ def test_function_with_href
+ assert_deprecated "link_to_function is deprecated and will be removed from Rails 4.1. Use Unobtrusive JavaScript instead." do
+ assert_dom_equal %(<a href="http://example.com/" onclick="alert(&#x27;Hello world!&#x27;); return false;">Greeting</a>),
+ link_to_function("Greeting", "alert('Hello world!')", :href => 'http://example.com/')
+ end
+ end
+
def test_javascript_tag
self.output_buffer = 'foo'
diff --git a/actionpack/test/template/sanitize_helper_test.rb b/actionpack/test/template/sanitize_helper_test.rb
index 4182af590e..7626cdf386 100644
--- a/actionpack/test/template/sanitize_helper_test.rb
+++ b/actionpack/test/template/sanitize_helper_test.rb
@@ -40,9 +40,9 @@ class SanitizeHelperTest < ActionView::TestCase
[nil, '', ' '].each do |blank|
stripped = strip_tags(blank)
assert_equal blank, stripped
- assert stripped.html_safe? unless blank.nil?
end
- assert strip_tags("<script>").html_safe?
+ assert_equal "", strip_tags("<script>")
+ assert_equal "something &lt;img onerror=alert(1337)", ERB::Util.html_escape(strip_tags("something <img onerror=alert(1337)"))
end
def test_sanitize_is_marked_safe
diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb
index 7ba439fb3e..2102282c02 100644
--- a/activemodel/lib/active_model/naming.rb
+++ b/activemodel/lib/active_model/naming.rb
@@ -300,11 +300,9 @@ module ActiveModel
private
def self.model_name_from_record_or_class(record_or_class)
- (record_or_class.is_a?(Class) ? record_or_class : convert_to_model(record_or_class).class).model_name
- end
-
- def self.convert_to_model(object)
- object.respond_to?(:to_model) ? object.to_model : object
+ return record_or_class.model_name if record_or_class.respond_to?(:model_name)
+ return record_or_class.to_model.class.model_name if record_or_class.respond_to?(:to_model)
+ record_or_class.class.model_name
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb
index 202f7e27c5..1ff307c735 100644
--- a/activerecord/test/cases/adapters/postgresql/connection_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb
@@ -85,16 +85,17 @@ module ActiveRecord
assert @connection.active?
original_connection_pid = @connection.query('select pg_backend_pid()')
- # Fail with bad connection after next query attempt.
- connection_class = class << @connection ; self ; end
- connection_class.class_eval <<-CODE
+ # Fail with bad connection on next query attempt.
+ raw_connection = @connection.raw_connection
+ raw_connection_class = class << raw_connection ; self ; end
+ raw_connection_class.class_eval <<-CODE, __FILE__, __LINE__ + 1
def query_fake(*args)
- if @called ||= false
- @connection.stubs(:status).returns(PCconn::CONNECTION_BAD)
+ if !( @called ||= false )
+ self.stubs(:status).returns(PGconn::CONNECTION_BAD)
+ @called = true
raise PGError
else
- @called = true
- @connection.unstub(:status)
+ self.unstub(:status)
query_unfake(*args)
end
end
@@ -107,13 +108,13 @@ module ActiveRecord
@connection.verify!
new_connection_pid = @connection.query('select pg_backend_pid()')
ensure
- connection_class.class_eval <<-CODE
+ raw_connection_class.class_eval <<-CODE
alias query query_unfake
undef query_fake
CODE
end
- assert_equal original_connection_pid, new_connection_pid, "Should have a new underlying connection pid"
+ assert_not_equal original_connection_pid, new_connection_pid, "Should have a new underlying connection pid"
end
# Must have with_manual_interventions set to true for this
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 70bd1bf4d3..6229b89a91 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,10 +1,6 @@
## Rails 4.0.0 (unreleased) ##
-* Add String#indent. *fxn & Ace Suares*
-
-* Inflections can now be defined per locale. `singularize` and `pluralize` accept locale as an extra argument. *David Celis*
-
-* `Object#try` will now return nil instead of raise a NoMethodError if the receiving object does not implement the method, but you can still get the old behavior by using the new `Object#try!` *DHH*
+* `ERB::Util.html_escape` now escapes single quotes. *Santiago Pastorino*
* `Time#change` now works with time values with offsets other than UTC or the local time zone. *Andrew White*
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index 389df58ec4..1a95bd63e6 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/object/to_json'
require 'active_support/core_ext/module/delegation'
+require 'active_support/json/variable'
require 'bigdecimal'
require 'active_support/core_ext/big_decimal/conversions' # for #to_s
diff --git a/activesupport/lib/active_support/json/variable.rb b/activesupport/lib/active_support/json/variable.rb
new file mode 100644
index 0000000000..8af661a795
--- /dev/null
+++ b/activesupport/lib/active_support/json/variable.rb
@@ -0,0 +1,17 @@
+require 'active_support/deprecation'
+
+module ActiveSupport
+ module JSON
+ # Deprecated: A string that returns itself as its JSON-encoded form.
+ class Variable < String
+ def initialize(*args)
+ ActiveSupport::Deprecation.warn 'ActiveSupport::JSON::Variable is deprecated and will be removed in Rails 4.1. ' \
+ 'For your own custom JSON literals, define #as_json and #encode_json yourself.'
+ super
+ end
+
+ def as_json(options = nil) self end #:nodoc:
+ def encode_json(encoder) self end #:nodoc:
+ end
+ end
+end
diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb
index a947635f4a..7ed71f9abc 100644
--- a/activesupport/test/json/encoding_test.rb
+++ b/activesupport/test/json/encoding_test.rb
@@ -85,6 +85,13 @@ class TestJSONEncoding < ActiveSupport::TestCase
end
end
+ def test_json_variable
+ assert_deprecated do
+ assert_equal ActiveSupport::JSON::Variable.new('foo'), 'foo'
+ assert_equal ActiveSupport::JSON::Variable.new('alert("foo")'), 'alert("foo")'
+ end
+ end
+
def test_hash_encoding
assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(:a => :b)
assert_equal %({\"a\":1}), ActiveSupport::JSON.encode('a' => 1)
diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb
index 5915d20010..f20dd78031 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/application.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb
@@ -27,9 +27,6 @@ module <%= app_const_base %>
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
- # Activate observers that should always be running.
- # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
-
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
@@ -44,6 +41,11 @@ module <%= app_const_base %>
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]
+ config.action_dispatch.default_headers = {
+ 'X-Frame-Options' => 'SAMEORIGIN',
+ 'X-XSS-Protection' => '1; mode=block'
+ }
+
# Use SQL instead of Active Record's schema dumper when creating the database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types.
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index 072aa8355d..2ffae66a57 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -20,9 +20,6 @@
# Generate digests for assets URLs.
config.assets.digest = true
-
- # Defaults to nil and saved in location specified by config.assets.prefix
- # config.assets.manifest = YOUR_PATH
<%- end -%>
# Specifies the header that your server uses for sending files.
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
index dd3af86b99..c29fa4d95f 100644
--- a/railties/test/application/assets_test.rb
+++ b/railties/test/application/assets_test.rb
@@ -106,20 +106,28 @@ module ApplicationTests
precompile!
images_should_compile.each do |filename|
- assert File.exists?("#{app_path}/public/assets/#{filename}")
+ assert_file_exists "#{app_path}/public/assets/#{filename}"
end
- assert File.exists?("#{app_path}/public/assets/application.js")
- assert File.exists?("#{app_path}/public/assets/application.css")
+ assert_file_exists("#{app_path}/public/assets/application.js")
+ assert_file_exists("#{app_path}/public/assets/application.css")
+
+ assert_no_file_exists("#{app_path}/public/assets/someapplication.js")
+ assert_no_file_exists("#{app_path}/public/assets/someapplication.css")
- assert !File.exists?("#{app_path}/public/assets/someapplication.js")
- assert !File.exists?("#{app_path}/public/assets/someapplication.css")
+ assert_no_file_exists("#{app_path}/public/assets/something.min.js")
+ assert_no_file_exists("#{app_path}/public/assets/something.min.css")
- assert !File.exists?("#{app_path}/public/assets/something.min.js")
- assert !File.exists?("#{app_path}/public/assets/something.min.css")
+ assert_no_file_exists("#{app_path}/public/assets/something.else.js")
+ assert_no_file_exists("#{app_path}/public/assets/something.else.css")
+ end
+
+ def assert_file_exists(filename)
+ assert File.exists?(filename), "missing #{filename}"
+ end
- assert !File.exists?("#{app_path}/public/assets/something.else.js")
- assert !File.exists?("#{app_path}/public/assets/something.else.css")
+ def assert_no_file_exists(filename)
+ assert !File.exists?(filename), "#{filename} does exist"
end
test "asset pipeline should use a Sprockets::Index when config.assets.digest is true" do