From d2d6aef51000f90f68db6d46fe59533f522fa25a Mon Sep 17 00:00:00 2001 From: wangjohn Date: Sun, 14 Jul 2013 18:48:57 -0400 Subject: Creating an SSE class to be used with ActionController::Live. --- actionpack/lib/action_controller/metal/live.rb | 74 ++++++++++++++++++++++ actionpack/test/controller/live_stream_test.rb | 88 ++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb index 8092fd639f..0dd788645b 100644 --- a/actionpack/lib/action_controller/metal/live.rb +++ b/actionpack/lib/action_controller/metal/live.rb @@ -1,5 +1,6 @@ require 'action_dispatch/http/response' require 'delegate' +require 'active_support/json' module ActionController # Mix this module in to your controller, and all actions in that controller @@ -32,6 +33,79 @@ module ActionController # the main thread. Make sure your actions are thread safe, and this shouldn't # be a problem (don't share state across threads, etc). module Live + # This class provides the ability to write an SSE (Server Sent Event) + # to an IO stream. The class is initialized with a stream and can be used + # to either write a JSON string or an object which can be converted to JSON. + # + # Writing an object will convert it into standard SSE format with whatever + # options you have configured. You may choose to set the following options: + # + # 1) Event. If specified, an event with this name will be dispatched on + # the browser. + # 2) Retry. The reconnection time in milliseconds used when attempting + # to send the event. + # 3) Id. If the connection dies while sending an SSE to the browser, then + # the server will receive a +Last-Event-ID+ header with value equal to +id+. + # + # After setting an option in the constructor of the SSE object, all future + # SSEs sent accross the stream will use those options unless overridden. + # + # Example Usage: + # + # class MyController < ActionController::Base + # include ActionController::Live + # + # def index + # response.headers['Content-Type'] = 'text/event-stream' + # sse = SSE.new(response.stream, retry: 300, event: "event-name") + # sse.write({ name: 'John'}) + # sse.write({ name: 'John'}, id: 10) + # sse.write({ name: 'John'}, id: 10, event: "other-event") + # sse.write({ name: 'John'}, id: 10, event: "other-event", retry: 500) + # ensure + # sse.close + # end + # end + # + # Note: SSEs are not currently supported by IE. However, they are supported + # by Chrome, Firefox, Opera, and Safari. + class SSE + + WHITELISTED_OPTIONS = %w( retry event id ) + + def initialize(stream, options = {}) + @stream = stream + @options = options + end + + def close + @stream.close + end + + def write(object, options = {}) + case object + when String + perform_write(object, options) + else + perform_write(ActiveSupport::JSON.encode(object), options) + end + end + + private + + def perform_write(json, options) + current_options = @options.merge(options).stringify_keys + + WHITELISTED_OPTIONS.each do |option_name| + if (option_value = current_options[option_name]) + @stream.write "#{option_name}: #{option_value}\n" + end + end + + @stream.write "data: #{json}\n\n" + end + end + class Buffer < ActionDispatch::Response::Buffer #:nodoc: def initialize(response) @error_callback = nil diff --git a/actionpack/test/controller/live_stream_test.rb b/actionpack/test/controller/live_stream_test.rb index 34164a19f0..0a25b5fa28 100644 --- a/actionpack/test/controller/live_stream_test.rb +++ b/actionpack/test/controller/live_stream_test.rb @@ -2,6 +2,94 @@ require 'abstract_unit' require 'active_support/concurrency/latch' module ActionController + class SSETest < ActionController::TestCase + class SSETestController < ActionController::Base + include ActionController::Live + + def basic_sse + response.headers['Content-Type'] = 'text/event-stream' + sse = SSE.new(response.stream) + sse.write("{\"name\":\"John\"}") + sse.write({ name: "Ryan" }) + ensure + sse.close + end + + def sse_with_event + sse = SSE.new(response.stream, event: "send-name") + sse.write("{\"name\":\"John\"}") + sse.write({ name: "Ryan" }) + ensure + sse.close + end + + def sse_with_retry + sse = SSE.new(response.stream, retry: 1000) + sse.write("{\"name\":\"John\"}") + sse.write({ name: "Ryan" }, retry: 1500) + ensure + sse.close + end + + def sse_with_id + sse = SSE.new(response.stream) + sse.write("{\"name\":\"John\"}", id: 1) + sse.write({ name: "Ryan" }, id: 2) + ensure + sse.close + end + end + + tests SSETestController + + def wait_for_response_stream_close + while !response.stream.closed? + sleep 0.01 + end + end + + def test_basic_sse + get :basic_sse + + wait_for_response_stream_close + assert_match(/data: {\"name\":\"John\"}/, response.body) + assert_match(/data: {\"name\":\"Ryan\"}/, response.body) + end + + def test_sse_with_event_name + get :sse_with_event + + wait_for_response_stream_close + assert_match(/data: {\"name\":\"John\"}/, response.body) + assert_match(/data: {\"name\":\"Ryan\"}/, response.body) + assert_match(/event: send-name/, response.body) + end + + def test_sse_with_retry + get :sse_with_retry + + wait_for_response_stream_close + first_response, second_response = response.body.split("\n\n") + assert_match(/data: {\"name\":\"John\"}/, first_response) + assert_match(/retry: 1000/, first_response) + + assert_match(/data: {\"name\":\"Ryan\"}/, second_response) + assert_match(/retry: 1500/, second_response) + end + + def test_sse_with_id + get :sse_with_id + + wait_for_response_stream_close + first_response, second_response = response.body.split("\n\n") + assert_match(/data: {\"name\":\"John\"}/, first_response) + assert_match(/id: 1/, first_response) + + assert_match(/data: {\"name\":\"Ryan\"}/, second_response) + assert_match(/id: 2/, second_response) + end + end + class LiveStreamTest < ActionController::TestCase class TestController < ActionController::Base include ActionController::Live -- cgit v1.2.3 From 7e74a01f849db3b85ac04ce425461c22b2b191d3 Mon Sep 17 00:00:00 2001 From: Josh Lauer Date: Mon, 5 Aug 2013 16:36:47 -0400 Subject: Only cache template digests if config.cache_template_loading since ActionView::Resolver.caching is set to the same value as config.cache_template_loading only cache template digests if config.cache_template_loading is not falsy fixes issues #10752 and #10791 --- actionview/CHANGELOG.md | 6 ++++++ actionview/lib/action_view/digestor.rb | 10 +++++++--- actionview/test/template/digestor_test.rb | 13 +++++++++++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index 98b78a7114..8fdbe15dee 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1,3 +1,9 @@ +* Only cache template digests if config.cache_template_loading, since + ActionView::Resolver.caching is set to the same value as + config.cache_template_loading + + *Josh Lauer* *Justin Ridgewell* + * Added an `extname` hash option for `javascript_include_tag` method. Before: diff --git a/actionview/lib/action_view/digestor.rb b/actionview/lib/action_view/digestor.rb index 64239c81b2..95c3200c81 100644 --- a/actionview/lib/action_view/digestor.rb +++ b/actionview/lib/action_view/digestor.rb @@ -32,9 +32,13 @@ module ActionView Digestor end - @@cache[cache_key] = digest = klass.new(name, format, finder, options).digest # Store the actual digest - ensure - @@cache.delete_pair(cache_key, false) if pre_stored && !digest # something went wrong, make sure not to corrupt the @@cache + # Store the actual digest if config.cache_template_loading is true + klass.new(name, format, finder, options).digest.tap do |digest| + @@cache[cache_key] = digest if ActionView::Resolver.caching? + end + rescue Exception + @@cache.delete_pair(cache_key, false) if pre_stored # something went wrong, make sure not to corrupt the @@cache + raise end end diff --git a/actionview/test/template/digestor_test.rb b/actionview/test/template/digestor_test.rb index 67e3775f28..c6608e214a 100644 --- a/actionview/test/template/digestor_test.rb +++ b/actionview/test/template/digestor_test.rb @@ -184,6 +184,15 @@ class TemplateDigestorTest < ActionView::TestCase assert_not_equal digest_phone, digest_fridge_phone end + def test_cache_template_loading + resolver_before = ActionView::Resolver.caching + ActionView::Resolver.caching = false + assert_digest_difference("messages/edit", true) do + change_template("comments/_comment") + end + ActionView::Resolver.caching = resolver_before + end + private def assert_logged(message) old_logger = ActionView::Base.logger @@ -200,9 +209,9 @@ class TemplateDigestorTest < ActionView::TestCase end end - def assert_digest_difference(template_name) + def assert_digest_difference(template_name, persistent = false) previous_digest = digest(template_name) - ActionView::Digestor.cache.clear + ActionView::Digestor.cache.clear unless persistent yield -- cgit v1.2.3 From 9f8116fb778ab4b90592d0a9ab88316132f00a78 Mon Sep 17 00:00:00 2001 From: Gaurish Sharma Date: Fri, 9 Aug 2013 04:32:00 +0530 Subject: Add tests for ActiveModel::Serializers::JSON#as_json ordering --- activemodel/test/cases/serializers/json_serialization_test.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb index f0347081ee..476ba3d8c5 100644 --- a/activemodel/test/cases/serializers/json_serialization_test.rb +++ b/activemodel/test/cases/serializers/json_serialization_test.rb @@ -155,12 +155,21 @@ class JsonSerializationTest < ActiveModel::TestCase end end - test "as_json should keep the default order in the hash" do + test "as_json should keep the MRI default order in the hash" do + skip "on JRuby as order is different" if defined? JRUBY_VERSION json = @contact.as_json assert_equal %w(name age created_at awesome preferences), json.keys end + test "as_json should keep the JRuby default order in the hash" do + skip "on MRI as order is different" unless defined? JRUBY_VERSION + json = @contact.as_json + + assert_equal %w(age name created_at awesome preferences), json.keys + end + + test "from_json should work without a root (class attribute)" do json = @contact.to_json result = Contact.new.from_json(json) -- cgit v1.2.3 From 90c450f6cd792187eeb1e039e0ff3722beb8b5c1 Mon Sep 17 00:00:00 2001 From: Gaurish Sharma Date: Fri, 9 Aug 2013 15:27:21 +0530 Subject: Avoid Skip in test, have a unified test for order --- .../test/cases/serializers/json_serialization_test.rb | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb index 476ba3d8c5..8eb7a58e90 100644 --- a/activemodel/test/cases/serializers/json_serialization_test.rb +++ b/activemodel/test/cases/serializers/json_serialization_test.rb @@ -155,21 +155,18 @@ class JsonSerializationTest < ActiveModel::TestCase end end - test "as_json should keep the MRI default order in the hash" do - skip "on JRuby as order is different" if defined? JRUBY_VERSION + test "as_json should keep the default order in the hash" do json = @contact.as_json - assert_equal %w(name age created_at awesome preferences), json.keys - end - - test "as_json should keep the JRuby default order in the hash" do - skip "on MRI as order is different" unless defined? JRUBY_VERSION - json = @contact.as_json + attributes_order = %w(name age created_at awesome preferences) + #Order on JRUBY is different + if defined? JRUBY_VERSION + attributes_order = %w(age name created_at awesome preferences) + end - assert_equal %w(age name created_at awesome preferences), json.keys + assert_equal attributes_order, json.keys end - test "from_json should work without a root (class attribute)" do json = @contact.to_json result = Contact.new.from_json(json) -- cgit v1.2.3 From 7c17fdfd11ccb991812cabf9d16acaa65eda08a5 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sat, 10 Aug 2013 13:07:01 +0530 Subject: Remove extra case. --- activerecord/lib/active_record/connection_adapters/abstract/quoting.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index c8fa4ef9af..552a22d28a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -51,7 +51,6 @@ module ActiveRecord return value unless column case column.type - when :binary then value when :integer then value.to_i when :float then value.to_f else -- cgit v1.2.3 From cbd2111c67b1603c97c00ebbd5f6f67e4b24eebd Mon Sep 17 00:00:00 2001 From: Federico Ravasio Date: Mon, 12 Aug 2013 11:43:42 +0200 Subject: Rely on NoMethodError#name when deciding to raise DelegationError. Different Ruby implementations present backtraces differently, as it should be an information consumed by humans. A better implementation should use data from the error, in this case returned by NoMethodError#name. Fixes issues with Rubinius, which presents backtraces differently from MRI. --- activesupport/lib/active_support/core_ext/module/delegation.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index bca3800344..182e74d9e1 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -192,8 +192,7 @@ class Module _ = #{to} # _ = client _.#{method}(#{definition}) # _.name(*args, &block) rescue NoMethodError => e # rescue NoMethodError => e - location = "%s:%d:in `%s'" % [__FILE__, __LINE__ - 2, '#{method_prefix}#{method}'] # location = "%s:%d:in `%s'" % [__FILE__, __LINE__ - 2, 'customer_name'] - if _.nil? && e.backtrace.first == location # if _.nil? && e.backtrace.first == location + if _.nil? && e.name == :#{method} # if _.nil? && e.name == :name #{exception} # # add helpful message to the exception else # else raise # raise -- cgit v1.2.3 From 5e6a8b911906ba0afb76b6c8ce8a916a31c8d3b1 Mon Sep 17 00:00:00 2001 From: robertomiranda Date: Wed, 14 Aug 2013 17:59:27 -0500 Subject: Normalize file parameters in same place as other parameters (ActionDispatch::Http::Parameters#normalize_encode_params) --- actionpack/lib/action_dispatch/http/parameters.rb | 2 ++ actionpack/lib/action_dispatch/http/request.rb | 1 - actionpack/lib/action_dispatch/http/upload.rb | 13 ------------- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index 8e992070f1..8e46441d24 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -59,6 +59,8 @@ module ActionDispatch def normalize_encode_params(params) if params.is_a?(String) return params.force_encoding(Encoding::UTF_8).encode! + elsif Hash === params && params.has_key?(:tempfile) + return UploadedFile.new(params) elsif !params.is_a?(Hash) return params end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index b4cf8ad2f7..aba8f66118 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -18,7 +18,6 @@ module ActionDispatch include ActionDispatch::Http::MimeNegotiation include ActionDispatch::Http::Parameters include ActionDispatch::Http::FilterParameters - include ActionDispatch::Http::Upload include ActionDispatch::Http::URL autoload :Session, 'action_dispatch/request/session' diff --git a/actionpack/lib/action_dispatch/http/upload.rb b/actionpack/lib/action_dispatch/http/upload.rb index b57c84dec8..a8d2dc3950 100644 --- a/actionpack/lib/action_dispatch/http/upload.rb +++ b/actionpack/lib/action_dispatch/http/upload.rb @@ -73,18 +73,5 @@ module ActionDispatch filename.force_encoding(Encoding::UTF_8).encode! if filename end end - - module Upload # :nodoc: - # Replace file upload hash with UploadedFile objects - # when normalize and encode parameters. - def normalize_encode_params(value) - if Hash === value && value.has_key?(:tempfile) - UploadedFile.new(value) - else - super - end - end - private :normalize_encode_params - end end end -- cgit v1.2.3 From 7889e3da6c3f41ecff7dc6075a6fce9c597d56be Mon Sep 17 00:00:00 2001 From: Pawel Janiak Date: Fri, 16 Aug 2013 13:04:28 +0200 Subject: Add note about installing and running Memcached for Rails test suite tests that depend on it. [ci skip] --- guides/source/development_dependencies_install.md | 24 ++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index ec25e09222..8d02027f2d 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -113,7 +113,29 @@ and run: $ bundle install --without db ``` -This command will install all dependencies except the MySQL and PostgreSQL Ruby drivers. We will come back to these soon. With dependencies installed, you can run the test suite with: +This command will install all dependencies except the MySQL and PostgreSQL Ruby drivers. We will come back to these soon. + +NOTE: If you would like to run the tests that use memcached, you need to ensure that you have it installed and running. + +You can use homebrew to install memcached on OSX: + +```bash +$ brew install memcached +``` + +On Ubuntu you can install it with apt-get: + +```bash +$ sudo apt-get install memcached +``` + +Or use yum on Fedora or CentOS: + +```bash +$ sudo yum install memcached +``` + +With the dependencies now installed, you can run the test suite with: ```bash $ bundle exec rake test -- cgit v1.2.3 From f87d8c7146d6601c57db1f9f4ec1d04fdd0a3f4a Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Sat, 20 Jul 2013 04:55:37 -0700 Subject: Stop interpreting SQL 'string' columns as :string type. SQL doesn't have a string type, and interpreting 'string' as text is contrary to at least SQLite3's behavior: "Note that a declared type of 'STRING' has an affinity of NUMERIC, not TEXT." http://www.sqlite.org/datatype3.html --- activerecord/lib/active_record/connection_adapters/column.rb | 2 +- activerecord/test/cases/adapters/postgresql/quoting_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index bccfa41ad1..fb53090edc 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -272,7 +272,7 @@ module ActiveRecord :text when /blob/i, /binary/i :binary - when /char/i, /string/i + when /char/i :string when /boolean/i :boolean diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb index b3429648ee..a534f0e56a 100644 --- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb +++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb @@ -47,7 +47,7 @@ module ActiveRecord def test_quote_cast_numeric fixnum = 666 - c = Column.new(nil, nil, 'string') + c = Column.new(nil, nil, 'varchar') assert_equal "'666'", @conn.quote(fixnum, c) c = Column.new(nil, nil, 'text') assert_equal "'666'", @conn.quote(fixnum, c) -- cgit v1.2.3 From 6776980b9648383c7a4c87d291d7dd8fdce5b2d8 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Sat, 17 Aug 2013 08:30:00 -0700 Subject: Split the 1200+ line mime_responds_test into 3 more focused and manageable test files. --- .../test/controller/mime/accept_format_test.rb | 94 ++ actionpack/test/controller/mime/respond_to_test.rb | 493 ++++++++ .../test/controller/mime/respond_with_test.rb | 667 +++++++++++ actionpack/test/controller/mime_responds_test.rb | 1254 -------------------- 4 files changed, 1254 insertions(+), 1254 deletions(-) create mode 100644 actionpack/test/controller/mime/accept_format_test.rb create mode 100644 actionpack/test/controller/mime/respond_to_test.rb create mode 100644 actionpack/test/controller/mime/respond_with_test.rb delete mode 100644 actionpack/test/controller/mime_responds_test.rb diff --git a/actionpack/test/controller/mime/accept_format_test.rb b/actionpack/test/controller/mime/accept_format_test.rb new file mode 100644 index 0000000000..c03c7edeb8 --- /dev/null +++ b/actionpack/test/controller/mime/accept_format_test.rb @@ -0,0 +1,94 @@ +require 'abstract_unit' + +class StarStarMimeController < ActionController::Base + layout nil + + def index + render + end +end + +class StarStarMimeControllerTest < ActionController::TestCase + tests StarStarMimeController + + def test_javascript_with_format + @request.accept = "text/javascript" + get :index, :format => 'js' + assert_match "function addition(a,b){ return a+b; }", @response.body + end + + def test_javascript_with_no_format + @request.accept = "text/javascript" + get :index + assert_match "function addition(a,b){ return a+b; }", @response.body + end + + def test_javascript_with_no_format_only_star_star + @request.accept = "*/*" + get :index + assert_match "function addition(a,b){ return a+b; }", @response.body + end +end + +class AbstractPostController < ActionController::Base + self.view_paths = File.dirname(__FILE__) + "/../../fixtures/post_test/" +end + +# For testing layouts which are set automatically +class PostController < AbstractPostController + around_action :with_iphone + + def index + respond_to(:html, :iphone, :js) + end + +protected + + def with_iphone + request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone" + yield + end +end + +class SuperPostController < PostController +end + +class MimeControllerLayoutsTest < ActionController::TestCase + tests PostController + + def setup + super + @request.host = "www.example.com" + Mime::Type.register_alias("text/html", :iphone) + end + + def teardown + super + Mime::Type.unregister(:iphone) + end + + def test_missing_layout_renders_properly + get :index + assert_equal '
Hello Firefox
', @response.body + + @request.accept = "text/iphone" + get :index + assert_equal 'Hello iPhone', @response.body + end + + def test_format_with_inherited_layouts + @controller = SuperPostController.new + + get :index + assert_equal '
Super Firefox
', @response.body + + @request.accept = "text/iphone" + get :index + assert_equal '
Super iPhone
', @response.body + end + + def test_non_navigational_format_with_no_template_fallbacks_to_html_template_with_no_layout + get :index, :format => :js + assert_equal "Hello Firefox", @response.body + end +end diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb new file mode 100644 index 0000000000..774dabe105 --- /dev/null +++ b/actionpack/test/controller/mime/respond_to_test.rb @@ -0,0 +1,493 @@ +require 'abstract_unit' + +class RespondToController < ActionController::Base + layout :set_layout + + def html_xml_or_rss + respond_to do |type| + type.html { render :text => "HTML" } + type.xml { render :text => "XML" } + type.rss { render :text => "RSS" } + type.all { render :text => "Nothing" } + end + end + + def js_or_html + respond_to do |type| + type.html { render :text => "HTML" } + type.js { render :text => "JS" } + type.all { render :text => "Nothing" } + end + end + + def json_or_yaml + respond_to do |type| + type.json { render :text => "JSON" } + type.yaml { render :text => "YAML" } + end + end + + def html_or_xml + respond_to do |type| + type.html { render :text => "HTML" } + type.xml { render :text => "XML" } + type.all { render :text => "Nothing" } + end + end + + def json_xml_or_html + respond_to do |type| + type.json { render :text => 'JSON' } + type.xml { render :xml => 'XML' } + type.html { render :text => 'HTML' } + end + end + + + def forced_xml + request.format = :xml + + respond_to do |type| + type.html { render :text => "HTML" } + type.xml { render :text => "XML" } + end + end + + def just_xml + respond_to do |type| + type.xml { render :text => "XML" } + end + end + + def using_defaults + respond_to do |type| + type.html + type.xml + end + end + + def using_defaults_with_type_list + respond_to(:html, :xml) + end + + def using_defaults_with_all + respond_to do |type| + type.html + type.all{ render text: "ALL" } + end + end + + def made_for_content_type + respond_to do |type| + type.rss { render :text => "RSS" } + type.atom { render :text => "ATOM" } + type.all { render :text => "Nothing" } + end + end + + def custom_type_handling + respond_to do |type| + type.html { render :text => "HTML" } + type.custom("application/crazy-xml") { render :text => "Crazy XML" } + type.all { render :text => "Nothing" } + end + end + + + def custom_constant_handling + respond_to do |type| + type.html { render :text => "HTML" } + type.mobile { render :text => "Mobile" } + end + end + + def custom_constant_handling_without_block + respond_to do |type| + type.html { render :text => "HTML" } + type.mobile + end + end + + def handle_any + respond_to do |type| + type.html { render :text => "HTML" } + type.any(:js, :xml) { render :text => "Either JS or XML" } + end + end + + def handle_any_any + respond_to do |type| + type.html { render :text => 'HTML' } + type.any { render :text => 'Whatever you ask for, I got it' } + end + end + + def all_types_with_layout + respond_to do |type| + type.html + end + end + + def iphone_with_html_response_type + request.format = :iphone if request.env["HTTP_ACCEPT"] == "text/iphone" + + respond_to do |type| + type.html { @type = "Firefox" } + type.iphone { @type = "iPhone" } + end + end + + def iphone_with_html_response_type_without_layout + request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone" + + respond_to do |type| + type.html { @type = "Firefox"; render :action => "iphone_with_html_response_type" } + type.iphone { @type = "iPhone" ; render :action => "iphone_with_html_response_type" } + end + end + + protected + def set_layout + case action_name + when "all_types_with_layout", "iphone_with_html_response_type" + "respond_to/layouts/standard" + when "iphone_with_html_response_type_without_layout" + "respond_to/layouts/missing" + end + end +end + +class RespondToControllerTest < ActionController::TestCase + tests RespondToController + + def setup + super + @request.host = "www.example.com" + Mime::Type.register_alias("text/html", :iphone) + Mime::Type.register("text/x-mobile", :mobile) + end + + def teardown + super + Mime::Type.unregister(:iphone) + Mime::Type.unregister(:mobile) + end + + def test_html + @request.accept = "text/html" + get :js_or_html + assert_equal 'HTML', @response.body + + get :html_or_xml + assert_equal 'HTML', @response.body + + assert_raises(ActionController::UnknownFormat) do + get :just_xml + end + end + + def test_all + @request.accept = "*/*" + get :js_or_html + assert_equal 'HTML', @response.body # js is not part of all + + get :html_or_xml + assert_equal 'HTML', @response.body + + get :just_xml + assert_equal 'XML', @response.body + end + + def test_xml + @request.accept = "application/xml" + get :html_xml_or_rss + assert_equal 'XML', @response.body + end + + def test_js_or_html + @request.accept = "text/javascript, text/html" + xhr :get, :js_or_html + assert_equal 'JS', @response.body + + @request.accept = "text/javascript, text/html" + xhr :get, :html_or_xml + assert_equal 'HTML', @response.body + + @request.accept = "text/javascript, text/html" + + assert_raises(ActionController::UnknownFormat) do + xhr :get, :just_xml + end + end + + def test_json_or_yaml_with_leading_star_star + @request.accept = "*/*, application/json" + get :json_xml_or_html + assert_equal 'HTML', @response.body + + @request.accept = "*/* , application/json" + get :json_xml_or_html + assert_equal 'HTML', @response.body + end + + def test_json_or_yaml + xhr :get, :json_or_yaml + assert_equal 'JSON', @response.body + + get :json_or_yaml, :format => 'json' + assert_equal 'JSON', @response.body + + get :json_or_yaml, :format => 'yaml' + assert_equal 'YAML', @response.body + + { 'YAML' => %w(text/yaml), + 'JSON' => %w(application/json text/x-json) + }.each do |body, content_types| + content_types.each do |content_type| + @request.accept = content_type + get :json_or_yaml + assert_equal body, @response.body + end + end + end + + def test_js_or_anything + @request.accept = "text/javascript, */*" + xhr :get, :js_or_html + assert_equal 'JS', @response.body + + xhr :get, :html_or_xml + assert_equal 'HTML', @response.body + + xhr :get, :just_xml + assert_equal 'XML', @response.body + end + + def test_using_defaults + @request.accept = "*/*" + get :using_defaults + assert_equal "text/html", @response.content_type + assert_equal 'Hello world!', @response.body + + @request.accept = "application/xml" + get :using_defaults + assert_equal "application/xml", @response.content_type + assert_equal "

Hello world!

\n", @response.body + end + + def test_using_defaults_with_all + @request.accept = "*/*" + get :using_defaults_with_all + assert_equal "HTML!", @response.body.strip + + @request.accept = "text/html" + get :using_defaults_with_all + assert_equal "HTML!", @response.body.strip + + @request.accept = "application/json" + get :using_defaults_with_all + assert_equal "ALL", @response.body + end + + def test_using_defaults_with_type_list + @request.accept = "*/*" + get :using_defaults_with_type_list + assert_equal "text/html", @response.content_type + assert_equal 'Hello world!', @response.body + + @request.accept = "application/xml" + get :using_defaults_with_type_list + assert_equal "application/xml", @response.content_type + assert_equal "

Hello world!

\n", @response.body + end + + def test_with_atom_content_type + @request.accept = "" + @request.env["CONTENT_TYPE"] = "application/atom+xml" + xhr :get, :made_for_content_type + assert_equal "ATOM", @response.body + end + + def test_with_rss_content_type + @request.accept = "" + @request.env["CONTENT_TYPE"] = "application/rss+xml" + xhr :get, :made_for_content_type + assert_equal "RSS", @response.body + end + + def test_synonyms + @request.accept = "application/javascript" + get :js_or_html + assert_equal 'JS', @response.body + + @request.accept = "application/x-xml" + get :html_xml_or_rss + assert_equal "XML", @response.body + end + + def test_custom_types + @request.accept = "application/crazy-xml" + get :custom_type_handling + assert_equal "application/crazy-xml", @response.content_type + assert_equal 'Crazy XML', @response.body + + @request.accept = "text/html" + get :custom_type_handling + assert_equal "text/html", @response.content_type + assert_equal 'HTML', @response.body + end + + def test_xhtml_alias + @request.accept = "application/xhtml+xml,application/xml" + get :html_or_xml + assert_equal 'HTML', @response.body + end + + def test_firefox_simulation + @request.accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" + get :html_or_xml + assert_equal 'HTML', @response.body + end + + def test_handle_any + @request.accept = "*/*" + get :handle_any + assert_equal 'HTML', @response.body + + @request.accept = "text/javascript" + get :handle_any + assert_equal 'Either JS or XML', @response.body + + @request.accept = "text/xml" + get :handle_any + assert_equal 'Either JS or XML', @response.body + end + + def test_handle_any_any + @request.accept = "*/*" + get :handle_any_any + assert_equal 'HTML', @response.body + end + + def test_handle_any_any_parameter_format + get :handle_any_any, {:format=>'html'} + assert_equal 'HTML', @response.body + end + + def test_handle_any_any_explicit_html + @request.accept = "text/html" + get :handle_any_any + assert_equal 'HTML', @response.body + end + + def test_handle_any_any_javascript + @request.accept = "text/javascript" + get :handle_any_any + assert_equal 'Whatever you ask for, I got it', @response.body + end + + def test_handle_any_any_xml + @request.accept = "text/xml" + get :handle_any_any + assert_equal 'Whatever you ask for, I got it', @response.body + end + + def test_browser_check_with_any_any + @request.accept = "application/json, application/xml" + get :json_xml_or_html + assert_equal 'JSON', @response.body + + @request.accept = "application/json, application/xml, */*" + get :json_xml_or_html + assert_equal 'HTML', @response.body + end + + def test_html_type_with_layout + @request.accept = "text/html" + get :all_types_with_layout + assert_equal '
HTML for all_types_with_layout
', @response.body + end + + def test_xhr + xhr :get, :js_or_html + assert_equal 'JS', @response.body + end + + def test_custom_constant + get :custom_constant_handling, :format => "mobile" + assert_equal "text/x-mobile", @response.content_type + assert_equal "Mobile", @response.body + end + + def test_custom_constant_handling_without_block + get :custom_constant_handling_without_block, :format => "mobile" + assert_equal "text/x-mobile", @response.content_type + assert_equal "Mobile", @response.body + end + + def test_forced_format + get :html_xml_or_rss + assert_equal "HTML", @response.body + + get :html_xml_or_rss, :format => "html" + assert_equal "HTML", @response.body + + get :html_xml_or_rss, :format => "xml" + assert_equal "XML", @response.body + + get :html_xml_or_rss, :format => "rss" + assert_equal "RSS", @response.body + end + + def test_internally_forced_format + get :forced_xml + assert_equal "XML", @response.body + + get :forced_xml, :format => "html" + assert_equal "XML", @response.body + end + + def test_extension_synonyms + get :html_xml_or_rss, :format => "xhtml" + assert_equal "HTML", @response.body + end + + def test_render_action_for_html + @controller.instance_eval do + def render(*args) + @action = args.first[:action] unless args.empty? + @action ||= action_name + + response.body = "#{@action} - #{formats}" + end + end + + get :using_defaults + assert_equal "using_defaults - #{[:html].to_s}", @response.body + + get :using_defaults, :format => "xml" + assert_equal "using_defaults - #{[:xml].to_s}", @response.body + end + + def test_format_with_custom_response_type + get :iphone_with_html_response_type + assert_equal '
Hello future from Firefox!
', @response.body + + get :iphone_with_html_response_type, :format => "iphone" + assert_equal "text/html", @response.content_type + assert_equal '
Hello iPhone future from iPhone!
', @response.body + end + + def test_format_with_custom_response_type_and_request_headers + @request.accept = "text/iphone" + get :iphone_with_html_response_type + assert_equal '
Hello iPhone future from iPhone!
', @response.body + assert_equal "text/html", @response.content_type + end + + def test_invalid_format + assert_raises(ActionController::UnknownFormat) do + get :using_defaults, :format => "invalidformat" + end + end +end diff --git a/actionpack/test/controller/mime/respond_with_test.rb b/actionpack/test/controller/mime/respond_with_test.rb new file mode 100644 index 0000000000..582050b78c --- /dev/null +++ b/actionpack/test/controller/mime/respond_with_test.rb @@ -0,0 +1,667 @@ +require 'abstract_unit' +require 'controller/fake_models' + +class RespondWithController < ActionController::Base + respond_to :html, :json, :touch + respond_to :xml, :except => :using_resource_with_block + respond_to :js, :only => [ :using_resource_with_block, :using_resource, 'using_hash_resource' ] + + def using_resource + respond_with(resource) + end + + def using_hash_resource + respond_with({:result => resource}) + end + + def using_resource_with_block + respond_with(resource) do |format| + format.csv { render :text => "CSV" } + end + end + + def using_resource_with_overwrite_block + respond_with(resource) do |format| + format.html { render :text => "HTML" } + end + end + + def using_resource_with_collection + respond_with([resource, Customer.new("jamis", 9)]) + end + + def using_resource_with_parent + respond_with(Quiz::Store.new("developer?", 11), Customer.new("david", 13)) + end + + def using_resource_with_status_and_location + respond_with(resource, :location => "http://test.host/", :status => :created) + end + + def using_invalid_resource_with_template + respond_with(resource) + end + + def using_options_with_template + @customer = resource + respond_with(@customer, :status => 123, :location => "http://test.host/") + end + + def using_resource_with_responder + responder = proc { |c, r, o| c.render :text => "Resource name is #{r.first.name}" } + respond_with(resource, :responder => responder) + end + + def using_resource_with_action + respond_with(resource, :action => :foo) do |format| + format.html { raise ActionView::MissingTemplate.new([], "bar", ["foo"], {}, false) } + end + end + + def using_responder_with_respond + responder = Class.new(ActionController::Responder) do + def respond; @controller.render :text => "respond #{format}"; end + end + respond_with(resource, :responder => responder) + end + +protected + + def resource + Customer.new("david", request.delete? ? nil : 13) + end +end + +class InheritedRespondWithController < RespondWithController + clear_respond_to + respond_to :xml, :json + + def index + respond_with(resource) do |format| + format.json { render :text => "JSON" } + end + end +end + +class RenderJsonRespondWithController < RespondWithController + clear_respond_to + respond_to :json + + def index + respond_with(resource) do |format| + format.json { render :json => RenderJsonTestException.new('boom') } + end + end + + def create + resource = ValidatedCustomer.new(params[:name], 1) + respond_with(resource) do |format| + format.json do + if resource.errors.empty? + render :json => { :valid => true } + else + render :json => { :valid => false } + end + end + end + end +end + +class EmptyRespondWithController < ActionController::Base + def index + respond_with(Customer.new("david", 13)) + end +end + +class RespondWithControllerTest < ActionController::TestCase + tests RespondWithController + + def setup + super + @request.host = "www.example.com" + Mime::Type.register_alias('text/html', :iphone) + Mime::Type.register_alias('text/html', :touch) + Mime::Type.register('text/x-mobile', :mobile) + end + + def teardown + super + Mime::Type.unregister(:iphone) + Mime::Type.unregister(:touch) + Mime::Type.unregister(:mobile) + end + + def test_using_resource + @request.accept = "application/xml" + get :using_resource + assert_equal "application/xml", @response.content_type + assert_equal "david", @response.body + + @request.accept = "application/json" + assert_raise ActionView::MissingTemplate do + get :using_resource + end + end + + def test_using_resource_with_js_simply_tries_to_render_the_template + @request.accept = "text/javascript" + get :using_resource + assert_equal "text/javascript", @response.content_type + assert_equal "alert(\"Hi\");", @response.body + end + + def test_using_hash_resource_with_js_raises_an_error_if_template_cant_be_found + @request.accept = "text/javascript" + assert_raise ActionView::MissingTemplate do + get :using_hash_resource + end + end + + def test_using_hash_resource + @request.accept = "application/xml" + get :using_hash_resource + assert_equal "application/xml", @response.content_type + assert_equal "\n\n david\n\n", @response.body + + @request.accept = "application/json" + get :using_hash_resource + assert_equal "application/json", @response.content_type + assert @response.body.include?("result") + assert @response.body.include?('"name":"david"') + assert @response.body.include?('"id":13') + end + + def test_using_hash_resource_with_post + @request.accept = "application/json" + assert_raise ArgumentError, "Nil location provided. Can't build URI." do + post :using_hash_resource + end + end + + def test_using_resource_with_block + @request.accept = "*/*" + get :using_resource_with_block + assert_equal "text/html", @response.content_type + assert_equal 'Hello world!', @response.body + + @request.accept = "text/csv" + get :using_resource_with_block + assert_equal "text/csv", @response.content_type + assert_equal "CSV", @response.body + + @request.accept = "application/xml" + get :using_resource + assert_equal "application/xml", @response.content_type + assert_equal "david", @response.body + end + + def test_using_resource_with_overwrite_block + get :using_resource_with_overwrite_block + assert_equal "text/html", @response.content_type + assert_equal "HTML", @response.body + end + + def test_not_acceptable + @request.accept = "application/xml" + assert_raises(ActionController::UnknownFormat) do + get :using_resource_with_block + end + + @request.accept = "text/javascript" + assert_raises(ActionController::UnknownFormat) do + get :using_resource_with_overwrite_block + end + end + + def test_using_resource_for_post_with_html_redirects_on_success + with_test_route_set do + post :using_resource + assert_equal "text/html", @response.content_type + assert_equal 302, @response.status + assert_equal "http://www.example.com/customers/13", @response.location + assert @response.redirect? + end + end + + def test_using_resource_for_post_with_html_rerender_on_failure + with_test_route_set do + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + post :using_resource + assert_equal "text/html", @response.content_type + assert_equal 200, @response.status + assert_equal "New world!\n", @response.body + assert_nil @response.location + end + end + + def test_using_resource_for_post_with_xml_yields_created_on_success + with_test_route_set do + @request.accept = "application/xml" + post :using_resource + assert_equal "application/xml", @response.content_type + assert_equal 201, @response.status + assert_equal "david", @response.body + assert_equal "http://www.example.com/customers/13", @response.location + end + end + + def test_using_resource_for_post_with_xml_yields_unprocessable_entity_on_failure + with_test_route_set do + @request.accept = "application/xml" + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + post :using_resource + assert_equal "application/xml", @response.content_type + assert_equal 422, @response.status + assert_equal errors.to_xml, @response.body + assert_nil @response.location + end + end + + def test_using_resource_for_post_with_json_yields_unprocessable_entity_on_failure + with_test_route_set do + @request.accept = "application/json" + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + post :using_resource + assert_equal "application/json", @response.content_type + assert_equal 422, @response.status + errors = {:errors => errors} + assert_equal errors.to_json, @response.body + assert_nil @response.location + end + end + + def test_using_resource_for_patch_with_html_redirects_on_success + with_test_route_set do + patch :using_resource + assert_equal "text/html", @response.content_type + assert_equal 302, @response.status + assert_equal "http://www.example.com/customers/13", @response.location + assert @response.redirect? + end + end + + def test_using_resource_for_patch_with_html_rerender_on_failure + with_test_route_set do + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + patch :using_resource + assert_equal "text/html", @response.content_type + assert_equal 200, @response.status + assert_equal "Edit world!\n", @response.body + assert_nil @response.location + end + end + + def test_using_resource_for_patch_with_html_rerender_on_failure_even_on_method_override + with_test_route_set do + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + @request.env["rack.methodoverride.original_method"] = "POST" + patch :using_resource + assert_equal "text/html", @response.content_type + assert_equal 200, @response.status + assert_equal "Edit world!\n", @response.body + assert_nil @response.location + end + end + + def test_using_resource_for_put_with_html_redirects_on_success + with_test_route_set do + put :using_resource + assert_equal "text/html", @response.content_type + assert_equal 302, @response.status + assert_equal "http://www.example.com/customers/13", @response.location + assert @response.redirect? + end + end + + def test_using_resource_for_put_with_html_rerender_on_failure + with_test_route_set do + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + put :using_resource + assert_equal "text/html", @response.content_type + assert_equal 200, @response.status + assert_equal "Edit world!\n", @response.body + assert_nil @response.location + end + end + + def test_using_resource_for_put_with_html_rerender_on_failure_even_on_method_override + with_test_route_set do + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + @request.env["rack.methodoverride.original_method"] = "POST" + put :using_resource + assert_equal "text/html", @response.content_type + assert_equal 200, @response.status + assert_equal "Edit world!\n", @response.body + assert_nil @response.location + end + end + + def test_using_resource_for_put_with_xml_yields_no_content_on_success + @request.accept = "application/xml" + put :using_resource + assert_equal "application/xml", @response.content_type + assert_equal 204, @response.status + assert_equal "", @response.body + end + + def test_using_resource_for_put_with_json_yields_no_content_on_success + Customer.any_instance.stubs(:to_json).returns('{"name": "David"}') + @request.accept = "application/json" + put :using_resource + assert_equal "application/json", @response.content_type + assert_equal 204, @response.status + assert_equal "", @response.body + end + + def test_using_resource_for_put_with_xml_yields_unprocessable_entity_on_failure + @request.accept = "application/xml" + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + put :using_resource + assert_equal "application/xml", @response.content_type + assert_equal 422, @response.status + assert_equal errors.to_xml, @response.body + assert_nil @response.location + end + + def test_using_resource_for_put_with_json_yields_unprocessable_entity_on_failure + @request.accept = "application/json" + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + put :using_resource + assert_equal "application/json", @response.content_type + assert_equal 422, @response.status + errors = {:errors => errors} + assert_equal errors.to_json, @response.body + assert_nil @response.location + end + + def test_using_resource_for_delete_with_html_redirects_on_success + with_test_route_set do + Customer.any_instance.stubs(:destroyed?).returns(true) + delete :using_resource + assert_equal "text/html", @response.content_type + assert_equal 302, @response.status + assert_equal "http://www.example.com/customers", @response.location + end + end + + def test_using_resource_for_delete_with_xml_yields_no_content_on_success + Customer.any_instance.stubs(:destroyed?).returns(true) + @request.accept = "application/xml" + delete :using_resource + assert_equal "application/xml", @response.content_type + assert_equal 204, @response.status + assert_equal "", @response.body + end + + def test_using_resource_for_delete_with_json_yields_no_content_on_success + Customer.any_instance.stubs(:to_json).returns('{"name": "David"}') + Customer.any_instance.stubs(:destroyed?).returns(true) + @request.accept = "application/json" + delete :using_resource + assert_equal "application/json", @response.content_type + assert_equal 204, @response.status + assert_equal "", @response.body + end + + def test_using_resource_for_delete_with_html_redirects_on_failure + with_test_route_set do + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + Customer.any_instance.stubs(:destroyed?).returns(false) + delete :using_resource + assert_equal "text/html", @response.content_type + assert_equal 302, @response.status + assert_equal "http://www.example.com/customers", @response.location + end + end + + def test_using_resource_with_parent_for_get + @request.accept = "application/xml" + get :using_resource_with_parent + assert_equal "application/xml", @response.content_type + assert_equal 200, @response.status + assert_equal "david", @response.body + end + + def test_using_resource_with_parent_for_post + with_test_route_set do + @request.accept = "application/xml" + + post :using_resource_with_parent + assert_equal "application/xml", @response.content_type + assert_equal 201, @response.status + assert_equal "david", @response.body + assert_equal "http://www.example.com/quiz_stores/11/customers/13", @response.location + + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + post :using_resource + assert_equal "application/xml", @response.content_type + assert_equal 422, @response.status + assert_equal errors.to_xml, @response.body + assert_nil @response.location + end + end + + def test_using_resource_with_collection + @request.accept = "application/xml" + get :using_resource_with_collection + assert_equal "application/xml", @response.content_type + assert_equal 200, @response.status + assert_match(/david<\/name>/, @response.body) + assert_match(/jamis<\/name>/, @response.body) + end + + def test_using_resource_with_action + @controller.instance_eval do + def render(params={}) + self.response_body = "#{params[:action]} - #{formats}" + end + end + + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + + post :using_resource_with_action + assert_equal "foo - #{[:html].to_s}", @controller.response.body + end + + def test_respond_as_responder_entry_point + @request.accept = "text/html" + get :using_responder_with_respond + assert_equal "respond html", @response.body + + @request.accept = "application/xml" + get :using_responder_with_respond + assert_equal "respond xml", @response.body + end + + def test_clear_respond_to + @controller = InheritedRespondWithController.new + @request.accept = "text/html" + assert_raises(ActionController::UnknownFormat) do + get :index + end + end + + def test_first_in_respond_to_has_higher_priority + @controller = InheritedRespondWithController.new + @request.accept = "*/*" + get :index + assert_equal "application/xml", @response.content_type + assert_equal "david", @response.body + end + + def test_block_inside_respond_with_is_rendered + @controller = InheritedRespondWithController.new + @request.accept = "application/json" + get :index + assert_equal "JSON", @response.body + end + + def test_render_json_object_responds_to_str_still_produce_json + @controller = RenderJsonRespondWithController.new + @request.accept = "application/json" + get :index, :format => :json + assert_match(/"message":"boom"/, @response.body) + assert_match(/"error":"RenderJsonTestException"/, @response.body) + end + + def test_api_response_with_valid_resource_respect_override_block + @controller = RenderJsonRespondWithController.new + post :create, :name => "sikachu", :format => :json + assert_equal '{"valid":true}', @response.body + end + + def test_api_response_with_invalid_resource_respect_override_block + @controller = RenderJsonRespondWithController.new + post :create, :name => "david", :format => :json + assert_equal '{"valid":false}', @response.body + end + + def test_no_double_render_is_raised + @request.accept = "text/html" + assert_raise ActionView::MissingTemplate do + get :using_resource + end + end + + def test_using_resource_with_status_and_location + @request.accept = "text/html" + post :using_resource_with_status_and_location + assert @response.redirect? + assert_equal "http://test.host/", @response.location + + @request.accept = "application/xml" + get :using_resource_with_status_and_location + assert_equal 201, @response.status + end + + def test_using_resource_with_status_and_location_with_invalid_resource + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + + @request.accept = "text/xml" + + post :using_resource_with_status_and_location + assert_equal errors.to_xml, @response.body + assert_equal 422, @response.status + assert_equal nil, @response.location + + put :using_resource_with_status_and_location + assert_equal errors.to_xml, @response.body + assert_equal 422, @response.status + assert_equal nil, @response.location + end + + def test_using_invalid_resource_with_template + errors = { :name => :invalid } + Customer.any_instance.stubs(:errors).returns(errors) + + @request.accept = "text/xml" + + post :using_invalid_resource_with_template + assert_equal errors.to_xml, @response.body + assert_equal 422, @response.status + assert_equal nil, @response.location + + put :using_invalid_resource_with_template + assert_equal errors.to_xml, @response.body + assert_equal 422, @response.status + assert_equal nil, @response.location + end + + def test_using_options_with_template + @request.accept = "text/xml" + + post :using_options_with_template + assert_equal "david", @response.body + assert_equal 123, @response.status + assert_equal "http://test.host/", @response.location + + put :using_options_with_template + assert_equal "david", @response.body + assert_equal 123, @response.status + assert_equal "http://test.host/", @response.location + end + + def test_using_resource_with_responder + get :using_resource_with_responder + assert_equal "Resource name is david", @response.body + end + + def test_using_resource_with_set_responder + RespondWithController.responder = proc { |c, r, o| c.render :text => "Resource name is #{r.first.name}" } + get :using_resource + assert_equal "Resource name is david", @response.body + ensure + RespondWithController.responder = ActionController::Responder + end + + def test_error_is_raised_if_no_respond_to_is_declared_and_respond_with_is_called + @controller = EmptyRespondWithController.new + @request.accept = "*/*" + assert_raise RuntimeError do + get :index + end + end + + private + def with_test_route_set + with_routing do |set| + set.draw do + resources :customers + resources :quiz_stores do + resources :customers + end + get ":controller/:action" + end + yield + end + end +end + +class FlashResponder < ActionController::Responder + def initialize(controller, resources, options={}) + super + end + + def to_html + controller.flash[:notice] = 'Success' + super + end +end + +class FlashResponderController < ActionController::Base + self.responder = FlashResponder + respond_to :html + + def index + respond_with Object.new do |format| + format.html { render :text => 'HTML' } + end + end +end + +class FlashResponderControllerTest < ActionController::TestCase + tests FlashResponderController + + def test_respond_with_block_executed + get :index + assert_equal 'HTML', @response.body + end + + def test_flash_responder_executed + get :index + assert_equal 'Success', flash[:notice] + end +end diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb deleted file mode 100644 index a9c62899b5..0000000000 --- a/actionpack/test/controller/mime_responds_test.rb +++ /dev/null @@ -1,1254 +0,0 @@ -require 'abstract_unit' -require 'controller/fake_models' -require 'active_support/core_ext/hash/conversions' - -class StarStarMimeController < ActionController::Base - layout nil - - def index - render - end -end - -class RespondToController < ActionController::Base - layout :set_layout - - def html_xml_or_rss - respond_to do |type| - type.html { render :text => "HTML" } - type.xml { render :text => "XML" } - type.rss { render :text => "RSS" } - type.all { render :text => "Nothing" } - end - end - - def js_or_html - respond_to do |type| - type.html { render :text => "HTML" } - type.js { render :text => "JS" } - type.all { render :text => "Nothing" } - end - end - - def json_or_yaml - respond_to do |type| - type.json { render :text => "JSON" } - type.yaml { render :text => "YAML" } - end - end - - def html_or_xml - respond_to do |type| - type.html { render :text => "HTML" } - type.xml { render :text => "XML" } - type.all { render :text => "Nothing" } - end - end - - def json_xml_or_html - respond_to do |type| - type.json { render :text => 'JSON' } - type.xml { render :xml => 'XML' } - type.html { render :text => 'HTML' } - end - end - - - def forced_xml - request.format = :xml - - respond_to do |type| - type.html { render :text => "HTML" } - type.xml { render :text => "XML" } - end - end - - def just_xml - respond_to do |type| - type.xml { render :text => "XML" } - end - end - - def using_defaults - respond_to do |type| - type.html - type.xml - end - end - - def using_defaults_with_type_list - respond_to(:html, :xml) - end - - def using_defaults_with_all - respond_to do |type| - type.html - type.all{ render text: "ALL" } - end - end - - def made_for_content_type - respond_to do |type| - type.rss { render :text => "RSS" } - type.atom { render :text => "ATOM" } - type.all { render :text => "Nothing" } - end - end - - def custom_type_handling - respond_to do |type| - type.html { render :text => "HTML" } - type.custom("application/crazy-xml") { render :text => "Crazy XML" } - type.all { render :text => "Nothing" } - end - end - - - def custom_constant_handling - respond_to do |type| - type.html { render :text => "HTML" } - type.mobile { render :text => "Mobile" } - end - end - - def custom_constant_handling_without_block - respond_to do |type| - type.html { render :text => "HTML" } - type.mobile - end - end - - def handle_any - respond_to do |type| - type.html { render :text => "HTML" } - type.any(:js, :xml) { render :text => "Either JS or XML" } - end - end - - def handle_any_any - respond_to do |type| - type.html { render :text => 'HTML' } - type.any { render :text => 'Whatever you ask for, I got it' } - end - end - - def all_types_with_layout - respond_to do |type| - type.html - end - end - - def iphone_with_html_response_type - request.format = :iphone if request.env["HTTP_ACCEPT"] == "text/iphone" - - respond_to do |type| - type.html { @type = "Firefox" } - type.iphone { @type = "iPhone" } - end - end - - def iphone_with_html_response_type_without_layout - request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone" - - respond_to do |type| - type.html { @type = "Firefox"; render :action => "iphone_with_html_response_type" } - type.iphone { @type = "iPhone" ; render :action => "iphone_with_html_response_type" } - end - end - - protected - def set_layout - case action_name - when "all_types_with_layout", "iphone_with_html_response_type" - "respond_to/layouts/standard" - when "iphone_with_html_response_type_without_layout" - "respond_to/layouts/missing" - end - end -end - -class StarStarMimeControllerTest < ActionController::TestCase - tests StarStarMimeController - - def test_javascript_with_format - @request.accept = "text/javascript" - get :index, :format => 'js' - assert_match "function addition(a,b){ return a+b; }", @response.body - end - - def test_javascript_with_no_format - @request.accept = "text/javascript" - get :index - assert_match "function addition(a,b){ return a+b; }", @response.body - end - - def test_javascript_with_no_format_only_star_star - @request.accept = "*/*" - get :index - assert_match "function addition(a,b){ return a+b; }", @response.body - end - -end - -class RespondToControllerTest < ActionController::TestCase - tests RespondToController - - def setup - super - @request.host = "www.example.com" - Mime::Type.register_alias("text/html", :iphone) - Mime::Type.register("text/x-mobile", :mobile) - end - - def teardown - super - Mime::Type.unregister(:iphone) - Mime::Type.unregister(:mobile) - end - - def test_html - @request.accept = "text/html" - get :js_or_html - assert_equal 'HTML', @response.body - - get :html_or_xml - assert_equal 'HTML', @response.body - - assert_raises(ActionController::UnknownFormat) do - get :just_xml - end - end - - def test_all - @request.accept = "*/*" - get :js_or_html - assert_equal 'HTML', @response.body # js is not part of all - - get :html_or_xml - assert_equal 'HTML', @response.body - - get :just_xml - assert_equal 'XML', @response.body - end - - def test_xml - @request.accept = "application/xml" - get :html_xml_or_rss - assert_equal 'XML', @response.body - end - - def test_js_or_html - @request.accept = "text/javascript, text/html" - xhr :get, :js_or_html - assert_equal 'JS', @response.body - - @request.accept = "text/javascript, text/html" - xhr :get, :html_or_xml - assert_equal 'HTML', @response.body - - @request.accept = "text/javascript, text/html" - - assert_raises(ActionController::UnknownFormat) do - xhr :get, :just_xml - end - end - - def test_json_or_yaml_with_leading_star_star - @request.accept = "*/*, application/json" - get :json_xml_or_html - assert_equal 'HTML', @response.body - - @request.accept = "*/* , application/json" - get :json_xml_or_html - assert_equal 'HTML', @response.body - end - - def test_json_or_yaml - xhr :get, :json_or_yaml - assert_equal 'JSON', @response.body - - get :json_or_yaml, :format => 'json' - assert_equal 'JSON', @response.body - - get :json_or_yaml, :format => 'yaml' - assert_equal 'YAML', @response.body - - { 'YAML' => %w(text/yaml), - 'JSON' => %w(application/json text/x-json) - }.each do |body, content_types| - content_types.each do |content_type| - @request.accept = content_type - get :json_or_yaml - assert_equal body, @response.body - end - end - end - - def test_js_or_anything - @request.accept = "text/javascript, */*" - xhr :get, :js_or_html - assert_equal 'JS', @response.body - - xhr :get, :html_or_xml - assert_equal 'HTML', @response.body - - xhr :get, :just_xml - assert_equal 'XML', @response.body - end - - def test_using_defaults - @request.accept = "*/*" - get :using_defaults - assert_equal "text/html", @response.content_type - assert_equal 'Hello world!', @response.body - - @request.accept = "application/xml" - get :using_defaults - assert_equal "application/xml", @response.content_type - assert_equal "

Hello world!

\n", @response.body - end - - def test_using_defaults_with_all - @request.accept = "*/*" - get :using_defaults_with_all - assert_equal "HTML!", @response.body.strip - - @request.accept = "text/html" - get :using_defaults_with_all - assert_equal "HTML!", @response.body.strip - - @request.accept = "application/json" - get :using_defaults_with_all - assert_equal "ALL", @response.body - end - - def test_using_defaults_with_type_list - @request.accept = "*/*" - get :using_defaults_with_type_list - assert_equal "text/html", @response.content_type - assert_equal 'Hello world!', @response.body - - @request.accept = "application/xml" - get :using_defaults_with_type_list - assert_equal "application/xml", @response.content_type - assert_equal "

Hello world!

\n", @response.body - end - - def test_with_atom_content_type - @request.accept = "" - @request.env["CONTENT_TYPE"] = "application/atom+xml" - xhr :get, :made_for_content_type - assert_equal "ATOM", @response.body - end - - def test_with_rss_content_type - @request.accept = "" - @request.env["CONTENT_TYPE"] = "application/rss+xml" - xhr :get, :made_for_content_type - assert_equal "RSS", @response.body - end - - def test_synonyms - @request.accept = "application/javascript" - get :js_or_html - assert_equal 'JS', @response.body - - @request.accept = "application/x-xml" - get :html_xml_or_rss - assert_equal "XML", @response.body - end - - def test_custom_types - @request.accept = "application/crazy-xml" - get :custom_type_handling - assert_equal "application/crazy-xml", @response.content_type - assert_equal 'Crazy XML', @response.body - - @request.accept = "text/html" - get :custom_type_handling - assert_equal "text/html", @response.content_type - assert_equal 'HTML', @response.body - end - - def test_xhtml_alias - @request.accept = "application/xhtml+xml,application/xml" - get :html_or_xml - assert_equal 'HTML', @response.body - end - - def test_firefox_simulation - @request.accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" - get :html_or_xml - assert_equal 'HTML', @response.body - end - - def test_handle_any - @request.accept = "*/*" - get :handle_any - assert_equal 'HTML', @response.body - - @request.accept = "text/javascript" - get :handle_any - assert_equal 'Either JS or XML', @response.body - - @request.accept = "text/xml" - get :handle_any - assert_equal 'Either JS or XML', @response.body - end - - def test_handle_any_any - @request.accept = "*/*" - get :handle_any_any - assert_equal 'HTML', @response.body - end - - def test_handle_any_any_parameter_format - get :handle_any_any, {:format=>'html'} - assert_equal 'HTML', @response.body - end - - def test_handle_any_any_explicit_html - @request.accept = "text/html" - get :handle_any_any - assert_equal 'HTML', @response.body - end - - def test_handle_any_any_javascript - @request.accept = "text/javascript" - get :handle_any_any - assert_equal 'Whatever you ask for, I got it', @response.body - end - - def test_handle_any_any_xml - @request.accept = "text/xml" - get :handle_any_any - assert_equal 'Whatever you ask for, I got it', @response.body - end - - def test_browser_check_with_any_any - @request.accept = "application/json, application/xml" - get :json_xml_or_html - assert_equal 'JSON', @response.body - - @request.accept = "application/json, application/xml, */*" - get :json_xml_or_html - assert_equal 'HTML', @response.body - end - - def test_html_type_with_layout - @request.accept = "text/html" - get :all_types_with_layout - assert_equal '
HTML for all_types_with_layout
', @response.body - end - - def test_xhr - xhr :get, :js_or_html - assert_equal 'JS', @response.body - end - - def test_custom_constant - get :custom_constant_handling, :format => "mobile" - assert_equal "text/x-mobile", @response.content_type - assert_equal "Mobile", @response.body - end - - def test_custom_constant_handling_without_block - get :custom_constant_handling_without_block, :format => "mobile" - assert_equal "text/x-mobile", @response.content_type - assert_equal "Mobile", @response.body - end - - def test_forced_format - get :html_xml_or_rss - assert_equal "HTML", @response.body - - get :html_xml_or_rss, :format => "html" - assert_equal "HTML", @response.body - - get :html_xml_or_rss, :format => "xml" - assert_equal "XML", @response.body - - get :html_xml_or_rss, :format => "rss" - assert_equal "RSS", @response.body - end - - def test_internally_forced_format - get :forced_xml - assert_equal "XML", @response.body - - get :forced_xml, :format => "html" - assert_equal "XML", @response.body - end - - def test_extension_synonyms - get :html_xml_or_rss, :format => "xhtml" - assert_equal "HTML", @response.body - end - - def test_render_action_for_html - @controller.instance_eval do - def render(*args) - @action = args.first[:action] unless args.empty? - @action ||= action_name - - response.body = "#{@action} - #{formats}" - end - end - - get :using_defaults - assert_equal "using_defaults - #{[:html].to_s}", @response.body - - get :using_defaults, :format => "xml" - assert_equal "using_defaults - #{[:xml].to_s}", @response.body - end - - def test_format_with_custom_response_type - get :iphone_with_html_response_type - assert_equal '
Hello future from Firefox!
', @response.body - - get :iphone_with_html_response_type, :format => "iphone" - assert_equal "text/html", @response.content_type - assert_equal '
Hello iPhone future from iPhone!
', @response.body - end - - def test_format_with_custom_response_type_and_request_headers - @request.accept = "text/iphone" - get :iphone_with_html_response_type - assert_equal '
Hello iPhone future from iPhone!
', @response.body - assert_equal "text/html", @response.content_type - end - - def test_invalid_format - assert_raises(ActionController::UnknownFormat) do - get :using_defaults, :format => "invalidformat" - end - end -end - -class RespondWithController < ActionController::Base - respond_to :html, :json, :touch - respond_to :xml, :except => :using_resource_with_block - respond_to :js, :only => [ :using_resource_with_block, :using_resource, 'using_hash_resource' ] - - def using_resource - respond_with(resource) - end - - def using_hash_resource - respond_with({:result => resource}) - end - - def using_resource_with_block - respond_with(resource) do |format| - format.csv { render :text => "CSV" } - end - end - - def using_resource_with_overwrite_block - respond_with(resource) do |format| - format.html { render :text => "HTML" } - end - end - - def using_resource_with_collection - respond_with([resource, Customer.new("jamis", 9)]) - end - - def using_resource_with_parent - respond_with(Quiz::Store.new("developer?", 11), Customer.new("david", 13)) - end - - def using_resource_with_status_and_location - respond_with(resource, :location => "http://test.host/", :status => :created) - end - - def using_invalid_resource_with_template - respond_with(resource) - end - - def using_options_with_template - @customer = resource - respond_with(@customer, :status => 123, :location => "http://test.host/") - end - - def using_resource_with_responder - responder = proc { |c, r, o| c.render :text => "Resource name is #{r.first.name}" } - respond_with(resource, :responder => responder) - end - - def using_resource_with_action - respond_with(resource, :action => :foo) do |format| - format.html { raise ActionView::MissingTemplate.new([], "bar", ["foo"], {}, false) } - end - end - - def using_responder_with_respond - responder = Class.new(ActionController::Responder) do - def respond; @controller.render :text => "respond #{format}"; end - end - respond_with(resource, :responder => responder) - end - -protected - - def resource - Customer.new("david", request.delete? ? nil : 13) - end -end - -class InheritedRespondWithController < RespondWithController - clear_respond_to - respond_to :xml, :json - - def index - respond_with(resource) do |format| - format.json { render :text => "JSON" } - end - end -end - -class RenderJsonRespondWithController < RespondWithController - clear_respond_to - respond_to :json - - def index - respond_with(resource) do |format| - format.json { render :json => RenderJsonTestException.new('boom') } - end - end - - def create - resource = ValidatedCustomer.new(params[:name], 1) - respond_with(resource) do |format| - format.json do - if resource.errors.empty? - render :json => { :valid => true } - else - render :json => { :valid => false } - end - end - end - end -end - -class EmptyRespondWithController < ActionController::Base - def index - respond_with(Customer.new("david", 13)) - end -end - -class RespondWithControllerTest < ActionController::TestCase - tests RespondWithController - - def setup - super - @request.host = "www.example.com" - Mime::Type.register_alias('text/html', :iphone) - Mime::Type.register_alias('text/html', :touch) - Mime::Type.register('text/x-mobile', :mobile) - end - - def teardown - super - Mime::Type.unregister(:iphone) - Mime::Type.unregister(:touch) - Mime::Type.unregister(:mobile) - end - - def test_using_resource - @request.accept = "application/xml" - get :using_resource - assert_equal "application/xml", @response.content_type - assert_equal "david", @response.body - - @request.accept = "application/json" - assert_raise ActionView::MissingTemplate do - get :using_resource - end - end - - def test_using_resource_with_js_simply_tries_to_render_the_template - @request.accept = "text/javascript" - get :using_resource - assert_equal "text/javascript", @response.content_type - assert_equal "alert(\"Hi\");", @response.body - end - - def test_using_hash_resource_with_js_raises_an_error_if_template_cant_be_found - @request.accept = "text/javascript" - assert_raise ActionView::MissingTemplate do - get :using_hash_resource - end - end - - def test_using_hash_resource - @request.accept = "application/xml" - get :using_hash_resource - assert_equal "application/xml", @response.content_type - assert_equal "\n\n david\n\n", @response.body - - @request.accept = "application/json" - get :using_hash_resource - assert_equal "application/json", @response.content_type - assert @response.body.include?("result") - assert @response.body.include?('"name":"david"') - assert @response.body.include?('"id":13') - end - - def test_using_hash_resource_with_post - @request.accept = "application/json" - assert_raise ArgumentError, "Nil location provided. Can't build URI." do - post :using_hash_resource - end - end - - def test_using_resource_with_block - @request.accept = "*/*" - get :using_resource_with_block - assert_equal "text/html", @response.content_type - assert_equal 'Hello world!', @response.body - - @request.accept = "text/csv" - get :using_resource_with_block - assert_equal "text/csv", @response.content_type - assert_equal "CSV", @response.body - - @request.accept = "application/xml" - get :using_resource - assert_equal "application/xml", @response.content_type - assert_equal "david", @response.body - end - - def test_using_resource_with_overwrite_block - get :using_resource_with_overwrite_block - assert_equal "text/html", @response.content_type - assert_equal "HTML", @response.body - end - - def test_not_acceptable - @request.accept = "application/xml" - assert_raises(ActionController::UnknownFormat) do - get :using_resource_with_block - end - - @request.accept = "text/javascript" - assert_raises(ActionController::UnknownFormat) do - get :using_resource_with_overwrite_block - end - end - - def test_using_resource_for_post_with_html_redirects_on_success - with_test_route_set do - post :using_resource - assert_equal "text/html", @response.content_type - assert_equal 302, @response.status - assert_equal "http://www.example.com/customers/13", @response.location - assert @response.redirect? - end - end - - def test_using_resource_for_post_with_html_rerender_on_failure - with_test_route_set do - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - post :using_resource - assert_equal "text/html", @response.content_type - assert_equal 200, @response.status - assert_equal "New world!\n", @response.body - assert_nil @response.location - end - end - - def test_using_resource_for_post_with_xml_yields_created_on_success - with_test_route_set do - @request.accept = "application/xml" - post :using_resource - assert_equal "application/xml", @response.content_type - assert_equal 201, @response.status - assert_equal "david", @response.body - assert_equal "http://www.example.com/customers/13", @response.location - end - end - - def test_using_resource_for_post_with_xml_yields_unprocessable_entity_on_failure - with_test_route_set do - @request.accept = "application/xml" - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - post :using_resource - assert_equal "application/xml", @response.content_type - assert_equal 422, @response.status - assert_equal errors.to_xml, @response.body - assert_nil @response.location - end - end - - def test_using_resource_for_post_with_json_yields_unprocessable_entity_on_failure - with_test_route_set do - @request.accept = "application/json" - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - post :using_resource - assert_equal "application/json", @response.content_type - assert_equal 422, @response.status - errors = {:errors => errors} - assert_equal errors.to_json, @response.body - assert_nil @response.location - end - end - - def test_using_resource_for_patch_with_html_redirects_on_success - with_test_route_set do - patch :using_resource - assert_equal "text/html", @response.content_type - assert_equal 302, @response.status - assert_equal "http://www.example.com/customers/13", @response.location - assert @response.redirect? - end - end - - def test_using_resource_for_patch_with_html_rerender_on_failure - with_test_route_set do - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - patch :using_resource - assert_equal "text/html", @response.content_type - assert_equal 200, @response.status - assert_equal "Edit world!\n", @response.body - assert_nil @response.location - end - end - - def test_using_resource_for_patch_with_html_rerender_on_failure_even_on_method_override - with_test_route_set do - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - @request.env["rack.methodoverride.original_method"] = "POST" - patch :using_resource - assert_equal "text/html", @response.content_type - assert_equal 200, @response.status - assert_equal "Edit world!\n", @response.body - assert_nil @response.location - end - end - - def test_using_resource_for_put_with_html_redirects_on_success - with_test_route_set do - put :using_resource - assert_equal "text/html", @response.content_type - assert_equal 302, @response.status - assert_equal "http://www.example.com/customers/13", @response.location - assert @response.redirect? - end - end - - def test_using_resource_for_put_with_html_rerender_on_failure - with_test_route_set do - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - put :using_resource - assert_equal "text/html", @response.content_type - assert_equal 200, @response.status - assert_equal "Edit world!\n", @response.body - assert_nil @response.location - end - end - - def test_using_resource_for_put_with_html_rerender_on_failure_even_on_method_override - with_test_route_set do - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - @request.env["rack.methodoverride.original_method"] = "POST" - put :using_resource - assert_equal "text/html", @response.content_type - assert_equal 200, @response.status - assert_equal "Edit world!\n", @response.body - assert_nil @response.location - end - end - - def test_using_resource_for_put_with_xml_yields_no_content_on_success - @request.accept = "application/xml" - put :using_resource - assert_equal "application/xml", @response.content_type - assert_equal 204, @response.status - assert_equal "", @response.body - end - - def test_using_resource_for_put_with_json_yields_no_content_on_success - Customer.any_instance.stubs(:to_json).returns('{"name": "David"}') - @request.accept = "application/json" - put :using_resource - assert_equal "application/json", @response.content_type - assert_equal 204, @response.status - assert_equal "", @response.body - end - - def test_using_resource_for_put_with_xml_yields_unprocessable_entity_on_failure - @request.accept = "application/xml" - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - put :using_resource - assert_equal "application/xml", @response.content_type - assert_equal 422, @response.status - assert_equal errors.to_xml, @response.body - assert_nil @response.location - end - - def test_using_resource_for_put_with_json_yields_unprocessable_entity_on_failure - @request.accept = "application/json" - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - put :using_resource - assert_equal "application/json", @response.content_type - assert_equal 422, @response.status - errors = {:errors => errors} - assert_equal errors.to_json, @response.body - assert_nil @response.location - end - - def test_using_resource_for_delete_with_html_redirects_on_success - with_test_route_set do - Customer.any_instance.stubs(:destroyed?).returns(true) - delete :using_resource - assert_equal "text/html", @response.content_type - assert_equal 302, @response.status - assert_equal "http://www.example.com/customers", @response.location - end - end - - def test_using_resource_for_delete_with_xml_yields_no_content_on_success - Customer.any_instance.stubs(:destroyed?).returns(true) - @request.accept = "application/xml" - delete :using_resource - assert_equal "application/xml", @response.content_type - assert_equal 204, @response.status - assert_equal "", @response.body - end - - def test_using_resource_for_delete_with_json_yields_no_content_on_success - Customer.any_instance.stubs(:to_json).returns('{"name": "David"}') - Customer.any_instance.stubs(:destroyed?).returns(true) - @request.accept = "application/json" - delete :using_resource - assert_equal "application/json", @response.content_type - assert_equal 204, @response.status - assert_equal "", @response.body - end - - def test_using_resource_for_delete_with_html_redirects_on_failure - with_test_route_set do - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - Customer.any_instance.stubs(:destroyed?).returns(false) - delete :using_resource - assert_equal "text/html", @response.content_type - assert_equal 302, @response.status - assert_equal "http://www.example.com/customers", @response.location - end - end - - def test_using_resource_with_parent_for_get - @request.accept = "application/xml" - get :using_resource_with_parent - assert_equal "application/xml", @response.content_type - assert_equal 200, @response.status - assert_equal "david", @response.body - end - - def test_using_resource_with_parent_for_post - with_test_route_set do - @request.accept = "application/xml" - - post :using_resource_with_parent - assert_equal "application/xml", @response.content_type - assert_equal 201, @response.status - assert_equal "david", @response.body - assert_equal "http://www.example.com/quiz_stores/11/customers/13", @response.location - - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - post :using_resource - assert_equal "application/xml", @response.content_type - assert_equal 422, @response.status - assert_equal errors.to_xml, @response.body - assert_nil @response.location - end - end - - def test_using_resource_with_collection - @request.accept = "application/xml" - get :using_resource_with_collection - assert_equal "application/xml", @response.content_type - assert_equal 200, @response.status - assert_match(/david<\/name>/, @response.body) - assert_match(/jamis<\/name>/, @response.body) - end - - def test_using_resource_with_action - @controller.instance_eval do - def render(params={}) - self.response_body = "#{params[:action]} - #{formats}" - end - end - - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - - post :using_resource_with_action - assert_equal "foo - #{[:html].to_s}", @controller.response.body - end - - def test_respond_as_responder_entry_point - @request.accept = "text/html" - get :using_responder_with_respond - assert_equal "respond html", @response.body - - @request.accept = "application/xml" - get :using_responder_with_respond - assert_equal "respond xml", @response.body - end - - def test_clear_respond_to - @controller = InheritedRespondWithController.new - @request.accept = "text/html" - assert_raises(ActionController::UnknownFormat) do - get :index - end - end - - def test_first_in_respond_to_has_higher_priority - @controller = InheritedRespondWithController.new - @request.accept = "*/*" - get :index - assert_equal "application/xml", @response.content_type - assert_equal "david", @response.body - end - - def test_block_inside_respond_with_is_rendered - @controller = InheritedRespondWithController.new - @request.accept = "application/json" - get :index - assert_equal "JSON", @response.body - end - - def test_render_json_object_responds_to_str_still_produce_json - @controller = RenderJsonRespondWithController.new - @request.accept = "application/json" - get :index, :format => :json - assert_match(/"message":"boom"/, @response.body) - assert_match(/"error":"RenderJsonTestException"/, @response.body) - end - - def test_api_response_with_valid_resource_respect_override_block - @controller = RenderJsonRespondWithController.new - post :create, :name => "sikachu", :format => :json - assert_equal '{"valid":true}', @response.body - end - - def test_api_response_with_invalid_resource_respect_override_block - @controller = RenderJsonRespondWithController.new - post :create, :name => "david", :format => :json - assert_equal '{"valid":false}', @response.body - end - - def test_no_double_render_is_raised - @request.accept = "text/html" - assert_raise ActionView::MissingTemplate do - get :using_resource - end - end - - def test_using_resource_with_status_and_location - @request.accept = "text/html" - post :using_resource_with_status_and_location - assert @response.redirect? - assert_equal "http://test.host/", @response.location - - @request.accept = "application/xml" - get :using_resource_with_status_and_location - assert_equal 201, @response.status - end - - def test_using_resource_with_status_and_location_with_invalid_resource - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - - @request.accept = "text/xml" - - post :using_resource_with_status_and_location - assert_equal errors.to_xml, @response.body - assert_equal 422, @response.status - assert_equal nil, @response.location - - put :using_resource_with_status_and_location - assert_equal errors.to_xml, @response.body - assert_equal 422, @response.status - assert_equal nil, @response.location - end - - def test_using_invalid_resource_with_template - errors = { :name => :invalid } - Customer.any_instance.stubs(:errors).returns(errors) - - @request.accept = "text/xml" - - post :using_invalid_resource_with_template - assert_equal errors.to_xml, @response.body - assert_equal 422, @response.status - assert_equal nil, @response.location - - put :using_invalid_resource_with_template - assert_equal errors.to_xml, @response.body - assert_equal 422, @response.status - assert_equal nil, @response.location - end - - def test_using_options_with_template - @request.accept = "text/xml" - - post :using_options_with_template - assert_equal "david", @response.body - assert_equal 123, @response.status - assert_equal "http://test.host/", @response.location - - put :using_options_with_template - assert_equal "david", @response.body - assert_equal 123, @response.status - assert_equal "http://test.host/", @response.location - end - - def test_using_resource_with_responder - get :using_resource_with_responder - assert_equal "Resource name is david", @response.body - end - - def test_using_resource_with_set_responder - RespondWithController.responder = proc { |c, r, o| c.render :text => "Resource name is #{r.first.name}" } - get :using_resource - assert_equal "Resource name is david", @response.body - ensure - RespondWithController.responder = ActionController::Responder - end - - def test_error_is_raised_if_no_respond_to_is_declared_and_respond_with_is_called - @controller = EmptyRespondWithController.new - @request.accept = "*/*" - assert_raise RuntimeError do - get :index - end - end - - private - def with_test_route_set - with_routing do |set| - set.draw do - resources :customers - resources :quiz_stores do - resources :customers - end - get ":controller/:action" - end - yield - end - end -end - -class AbstractPostController < ActionController::Base - self.view_paths = File.dirname(__FILE__) + "/../fixtures/post_test/" -end - -# For testing layouts which are set automatically -class PostController < AbstractPostController - around_action :with_iphone - - def index - respond_to(:html, :iphone, :js) - end - -protected - - def with_iphone - request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone" - yield - end -end - -class SuperPostController < PostController -end - -class MimeControllerLayoutsTest < ActionController::TestCase - tests PostController - - def setup - super - @request.host = "www.example.com" - Mime::Type.register_alias("text/html", :iphone) - end - - def teardown - super - Mime::Type.unregister(:iphone) - end - - def test_missing_layout_renders_properly - get :index - assert_equal '
Hello Firefox
', @response.body - - @request.accept = "text/iphone" - get :index - assert_equal 'Hello iPhone', @response.body - end - - def test_format_with_inherited_layouts - @controller = SuperPostController.new - - get :index - assert_equal '
Super Firefox
', @response.body - - @request.accept = "text/iphone" - get :index - assert_equal '
Super iPhone
', @response.body - end - - def test_non_navigational_format_with_no_template_fallbacks_to_html_template_with_no_layout - get :index, :format => :js - assert_equal "Hello Firefox", @response.body - end -end - -class FlashResponder < ActionController::Responder - def initialize(controller, resources, options={}) - super - end - - def to_html - controller.flash[:notice] = 'Success' - super - end -end - -class FlashResponderController < ActionController::Base - self.responder = FlashResponder - respond_to :html - - def index - respond_with Object.new do |format| - format.html { render :text => 'HTML' } - end - end -end - -class FlashResponderControllerTest < ActionController::TestCase - tests FlashResponderController - - def test_respond_with_block_executed - get :index - assert_equal 'HTML', @response.body - end - - def test_flash_responder_executed - get :index - assert_equal 'Success', flash[:notice] - end -end -- cgit v1.2.3 From f84c6201dd592f9ef0b5e8473951bf6ceec213e6 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Sat, 17 Aug 2013 18:45:50 -0700 Subject: Fail informatively in #respond_with when no appropriate #api_behavior renderer is available. Currently if a user calls #respond_with(csvable), but has not csv renderer available, Responder will just run through the default render behavior twice, raising ActionView::MissingTemplate both times. This changes ActionController::Metal::Responder#api_behavior to check in advance whether there is a renderer available, and raise ActionController::MissingRenderer if not. --- .../lib/action_controller/metal/renderers.rb | 7 +++++ .../lib/action_controller/metal/responder.rb | 6 +++++ .../test/controller/mime/respond_with_test.rb | 31 ++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index 5272dc6cdb..abed6e53cc 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -6,6 +6,13 @@ module ActionController Renderers.add(key, &block) end + class MissingRenderer < LoadError + def initialize(format) + @format = format + super("No renderer defined for format: #{@format}") + end + end + module Renderers extend ActiveSupport::Concern diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index fd5b661209..66ff34a794 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -202,6 +202,7 @@ module ActionController #:nodoc: # This is the common behavior for formats associated with APIs, such as :xml and :json. def api_behavior(error) raise error unless resourceful? + raise MissingRenderer.new(format) unless has_renderer? if get? display resource @@ -269,6 +270,11 @@ module ActionController #:nodoc: resource.respond_to?(:errors) && !resource.errors.empty? end + # Check whether the neceessary Renderer is available + def has_renderer? + Renderers::RENDERERS.include?(format) + end + # By default, render the :edit action for HTML requests with errors, unless # the verb was POST. # diff --git a/actionpack/test/controller/mime/respond_with_test.rb b/actionpack/test/controller/mime/respond_with_test.rb index 582050b78c..29ddbff8d4 100644 --- a/actionpack/test/controller/mime/respond_with_test.rb +++ b/actionpack/test/controller/mime/respond_with_test.rb @@ -107,6 +107,20 @@ class RenderJsonRespondWithController < RespondWithController end end +class CsvRespondWithController < ActionController::Base + respond_to :csv + + class RespondWithCsv + def to_csv + "c,s,v" + end + end + + def index + respond_with(RespondWithCsv.new) + end +end + class EmptyRespondWithController < ActionController::Base def index respond_with(Customer.new("david", 13)) @@ -607,6 +621,23 @@ class RespondWithControllerTest < ActionController::TestCase RespondWithController.responder = ActionController::Responder end + def test_uses_renderer_if_an_api_behavior + ActionController::Renderers.add :csv do |obj, options| + send_data obj.to_csv, type: Mime::CSV + end + @controller = CsvRespondWithController.new + get :index, format: 'csv' + assert_equal Mime::CSV, @response.content_type + assert_equal "c,s,v", @response.body + end + + def test_raises_missing_renderer_if_an_api_behavior_with_no_renderer + @controller = CsvRespondWithController.new + assert_raise ActionController::MissingRenderer do + get :index, format: 'csv' + end + end + def test_error_is_raised_if_no_respond_to_is_declared_and_respond_with_is_called @controller = EmptyRespondWithController.new @request.accept = "*/*" -- cgit v1.2.3 From c40111c346b91dcf05a2d1b2b7d46525f045989e Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Sun, 18 Aug 2013 02:36:41 -0500 Subject: Refactor serialization test for hash order --- .../test/cases/serializers/json_serialization_test.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb index 8eb7a58e90..00a636e633 100644 --- a/activemodel/test/cases/serializers/json_serialization_test.rb +++ b/activemodel/test/cases/serializers/json_serialization_test.rb @@ -155,16 +155,15 @@ class JsonSerializationTest < ActiveModel::TestCase end end - test "as_json should keep the default order in the hash" do + test "as_json should keep the default order in the hash according to used engine" do json = @contact.as_json - attributes_order = %w(name age created_at awesome preferences) - #Order on JRUBY is different - if defined? JRUBY_VERSION - attributes_order = %w(age name created_at awesome preferences) + # Check for original order only on MRI and sort for other implementations + if RUBY_ENGINE == 'ruby' + assert_equal %w(name age created_at awesome preferences), json.keys + else + assert_equal %w(age awesome created_at name preferences), json.keys.sort end - - assert_equal attributes_order, json.keys end test "from_json should work without a root (class attribute)" do -- cgit v1.2.3 From 7c9f9dcc2128d3211129da2c506fd42450d916e0 Mon Sep 17 00:00:00 2001 From: scaryguy Date: Sun, 18 Aug 2013 20:28:02 +0300 Subject: blorgh_engine to blorgh [ci-skip] --- guides/source/engines.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guides/source/engines.md b/guides/source/engines.md index 9106b6382d..60b95fa668 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -104,7 +104,7 @@ At the root of this brand new engine's directory lives a `blorgh.gemspec` file. gem 'blorgh', path: "vendor/engines/blorgh" ``` -By specifying it as a gem within the `Gemfile`, Bundler will load it as such, parsing this `blorgh.gemspec` file and requiring a file within the `lib` directory called `lib/blorgh.rb`. This file requires the `blorgh/engine.rb` file (located at `lib/blorgh/engine.rb`) and defines a base module called `Blorgh`. +Don't foget to ` bundle install` as usual. By specifying it as a gem within the `Gemfile`, Bundler will load it as such, parsing this `blorgh.gemspec` file and requiring a file within the `lib` directory called `lib/blorgh.rb`. This file requires the `blorgh/engine.rb` file (located at `lib/blorgh/engine.rb`) and defines a base module called `Blorgh`. ```ruby require "blorgh/engine" @@ -466,7 +466,7 @@ NOTE: Other engines, such as Devise, handle this a little differently by making The engine contains migrations for the `blorgh_posts` and `blorgh_comments` table which need to be created in the application's database so that the engine's models can query them correctly. To copy these migrations into the application use this command: ```bash -$ rake blorgh_engine:install:migrations +$ rake blorgh:install:migrations ``` If you have multiple engines that need migrations copied over, use `railties:install:migrations` instead: -- cgit v1.2.3 From 99e33c03b7ccad3254c787a19bc7082e23dbcd27 Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Sun, 18 Aug 2013 16:39:31 -0500 Subject: Dont' check for any order in hash since we aren't sorting it and this is determinated only by the used interpreter --- activemodel/test/cases/serializers/json_serialization_test.rb | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb index 00a636e633..e4f5e61e91 100644 --- a/activemodel/test/cases/serializers/json_serialization_test.rb +++ b/activemodel/test/cases/serializers/json_serialization_test.rb @@ -155,17 +155,6 @@ class JsonSerializationTest < ActiveModel::TestCase end end - test "as_json should keep the default order in the hash according to used engine" do - json = @contact.as_json - - # Check for original order only on MRI and sort for other implementations - if RUBY_ENGINE == 'ruby' - assert_equal %w(name age created_at awesome preferences), json.keys - else - assert_equal %w(age awesome created_at name preferences), json.keys.sort - end - end - test "from_json should work without a root (class attribute)" do json = @contact.to_json result = Contact.new.from_json(json) -- cgit v1.2.3 From 7193f750ffe0276a16b3703f4cf05e7b36e7df7b Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Sun, 18 Aug 2013 17:02:25 -0500 Subject: Rename @locals to @_locals in Thread to avoid conflict with Rubinius. Closes #11831 --- activesupport/lib/active_support/core_ext/thread.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/thread.rb b/activesupport/lib/active_support/core_ext/thread.rb index 5481766f10..de752f14ef 100644 --- a/activesupport/lib/active_support/core_ext/thread.rb +++ b/activesupport/lib/active_support/core_ext/thread.rb @@ -23,14 +23,14 @@ class Thread # for the fiber local. The fiber is executed in the same thread, so the # thread local values are available. def thread_variable_get(key) - locals[key.to_sym] + _locals[key.to_sym] end # Sets a thread local with +key+ to +value+. Note that these are local to # threads, and not to fibers. Please see Thread#thread_variable_get for # more information. def thread_variable_set(key, value) - locals[key.to_sym] = value + _locals[key.to_sym] = value end # Returns an an array of the names of the thread-local variables (as Symbols). @@ -45,7 +45,7 @@ class Thread # Note that these are not fiber local variables. Please see Thread#thread_variable_get # for more details. def thread_variables - locals.keys + _locals.keys end # Returns true if the given string (or symbol) exists as a @@ -59,16 +59,16 @@ class Thread # Note that these are not fiber local variables. Please see Thread#thread_variable_get # for more details. def thread_variable?(key) - locals.has_key?(key.to_sym) + _locals.has_key?(key.to_sym) end private - def locals + def _locals if defined?(@locals) - @locals + @_locals else - LOCK.synchronize { @locals ||= {} } + LOCK.synchronize { @_locals ||= {} } end end end unless Thread.instance_methods.include?(:thread_variable_set) -- cgit v1.2.3 From 48c8135423dd7a8ff676b858cad6795a15903826 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 18 Aug 2013 16:52:15 -0700 Subject: duration is called multiple times in dev, so lets cache it --- activesupport/lib/active_support/notifications/instrumenter.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb index 0c9a729ce5..3a244b34b5 100644 --- a/activesupport/lib/active_support/notifications/instrumenter.rb +++ b/activesupport/lib/active_support/notifications/instrumenter.rb @@ -54,10 +54,11 @@ module ActiveSupport @transaction_id = transaction_id @end = ending @children = [] + @duration = nil end def duration - 1000.0 * (self.end - time) + @duration ||= 1000.0 * (self.end - time) end def <<(event) -- cgit v1.2.3 From 726001485005629b155240fe85f8a011f15d6b84 Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Sun, 18 Aug 2013 19:47:33 -0500 Subject: oops, I missed this in 7193f75 --- activesupport/lib/active_support/core_ext/thread.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/core_ext/thread.rb b/activesupport/lib/active_support/core_ext/thread.rb index de752f14ef..878ec73ef0 100644 --- a/activesupport/lib/active_support/core_ext/thread.rb +++ b/activesupport/lib/active_support/core_ext/thread.rb @@ -65,7 +65,7 @@ class Thread private def _locals - if defined?(@locals) + if defined?(@_locals) @_locals else LOCK.synchronize { @_locals ||= {} } -- cgit v1.2.3 From 6846d9146bcbad58b132695907b417592a0f14e0 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Mon, 19 Aug 2013 00:34:19 -0300 Subject: Fix typo [ci skip] --- guides/source/engines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/engines.md b/guides/source/engines.md index 60b95fa668..7a125fd341 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -104,7 +104,7 @@ At the root of this brand new engine's directory lives a `blorgh.gemspec` file. gem 'blorgh', path: "vendor/engines/blorgh" ``` -Don't foget to ` bundle install` as usual. By specifying it as a gem within the `Gemfile`, Bundler will load it as such, parsing this `blorgh.gemspec` file and requiring a file within the `lib` directory called `lib/blorgh.rb`. This file requires the `blorgh/engine.rb` file (located at `lib/blorgh/engine.rb`) and defines a base module called `Blorgh`. +Don't forget to run `bundle install` as usual. By specifying it as a gem within the `Gemfile`, Bundler will load it as such, parsing this `blorgh.gemspec` file and requiring a file within the `lib` directory called `lib/blorgh.rb`. This file requires the `blorgh/engine.rb` file (located at `lib/blorgh/engine.rb`) and defines a base module called `Blorgh`. ```ruby require "blorgh/engine" -- cgit v1.2.3 From 331632585bb583d5ecd56261ab6d71ba18cfa639 Mon Sep 17 00:00:00 2001 From: Rex Feng Date: Mon, 19 Aug 2013 00:31:41 -0400 Subject: clarify instructions in contributing_to_ruby_on_rails.md for committing [ci skip] --- guides/source/contributing_to_ruby_on_rails.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index 2f8a178376..f95a194c30 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -184,7 +184,7 @@ Ruby on Rails has two main sets of documentation: the guides help you in learnin You can help improve the Rails guides by making them more coherent, consistent or readable, adding missing information, correcting factual errors, fixing typos, or bringing it up to date with the latest edge Rails. To get involved in the translation of Rails guides, please see [Translating Rails Guides](https://wiki.github.com/rails/docrails/translating-rails-guides). -You can either ask for commit bit if you'd like to contribute to [Docrails](http://github.com/rails/docrails) regularly (Please contact anyone from [the core team](http://rubyonrails.org/core)), or else open a pull request to [Rails](http://github.com/rails/rails) itself. +You can either push your fix to [Docrails](http://github.com/rails/docrails) (ask the [Rails core team](http://rubyonrails.org/core) for push access if you'd like to contribute regularly), or open a pull request to [Rails](http://github.com/rails/rails) itself. Docrails is merged with master regularly, so you are effectively editing the Ruby on Rails documentation. -- cgit v1.2.3 From 2fcef6678a02fc03aa3ee18ad2d056e093551bd2 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Mon, 19 Aug 2013 13:49:35 +0200 Subject: explain how to contribute to the documentation. Follow-up to #11934 --- guides/source/contributing_to_ruby_on_rails.md | 6 +++++- guides/source/layout.html.erb | 10 ++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index f95a194c30..a0352790f4 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -184,7 +184,11 @@ Ruby on Rails has two main sets of documentation: the guides help you in learnin You can help improve the Rails guides by making them more coherent, consistent or readable, adding missing information, correcting factual errors, fixing typos, or bringing it up to date with the latest edge Rails. To get involved in the translation of Rails guides, please see [Translating Rails Guides](https://wiki.github.com/rails/docrails/translating-rails-guides). -You can either push your fix to [Docrails](http://github.com/rails/docrails) (ask the [Rails core team](http://rubyonrails.org/core) for push access if you'd like to contribute regularly), or open a pull request to [Rails](http://github.com/rails/rails) itself. +You can either open a pull request to [Rails](http://github.com/rails/rails) or +ask the [Rails core team](http://rubyonrails.org/core) for commit access on +[docrails](http://github.com/rails/docrails) if you contribute regularly. +Please do not open pull requests in docrails, if you'd like to get feedback on your +change, ask for it in [Rails](http://github.com/rails/rails) instead. Docrails is merged with master regularly, so you are effectively editing the Ruby on Rails documentation. diff --git a/guides/source/layout.html.erb b/guides/source/layout.html.erb index 71d3c5638b..24e1e23497 100644 --- a/guides/source/layout.html.erb +++ b/guides/source/layout.html.erb @@ -101,14 +101,8 @@ You're encouraged to help improve the quality of this guide.

- If you see any typos or factual errors that you are confident to fix, - you can push the fix to <%= link_to 'docrails', 'https://github.com/rails/docrails' %> (Ask - the <%= link_to 'Rails core team', 'http://rubyonrails.org/core' %> for push access). - If you choose to open a pull request, please do it in <%= link_to 'Rails', 'https://github.com/rails/rails' %> - and not in the <%= link_to 'docrails', 'https://github.com/rails/docrails' %> repository. - Commits made to docrails are still reviewed, but that happens after you've submitted your - contribution. <%= link_to 'docrails', 'https://github.com/rails/docrails' %> is - cross-merged with master periodically. + Please contribute if you see any typos or factual errors. + To get started, you can read our <%= link_to 'documentation contributions', 'http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#contributing-to-the-rails-documentation' %> section.

You may also find incomplete content, or stuff that is not up to date. -- cgit v1.2.3 From 565c367d344228211f03d7736de79d1cfff26422 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 Aug 2013 14:17:49 +0200 Subject: let AR::FinderMethods#exists? return singletons in all cases [closes #11592] This fixes a regression. The documentation said in its introduction paragraph that the method returns truthy/falsy, but then below it was said that if there were no arguments you'd get `true` or `false`. Also when the argument is exactly `false` a singleton is documented to be returned. The method was not returning the singletons so it didn't conform to those special cases. The best solution here seems to be to just return singletons in all cases. This solution is backwards compatible. Also, the contract has been revised because it has no sense that the predicate varies that way depending on the input. I bet the previous contract was just an accident, not something mixed on purpose. Conflicts: activerecord/lib/active_record/relation/finder_methods.rb activerecord/test/cases/finder_test.rb --- .../lib/active_record/relation/finder_methods.rb | 14 +++--- activerecord/test/cases/finder_test.rb | 56 +++++++++++----------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 2d3bd563ac..0132a02f83 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -171,21 +171,21 @@ module ActiveRecord last or raise RecordNotFound end - # Returns truthy if a record exists in the table that matches the +id+ or - # conditions given, or falsy otherwise. The argument can take six forms: + # Returns +true+ if a record exists in the table that matches the +id+ or + # conditions given, or +false+ otherwise. The argument can take six forms: # # * Integer - Finds the record with this primary key. # * String - Finds the record with a primary key corresponding to this # string (such as '5'). # * Array - Finds the record that matches these +find+-style conditions - # (such as ['color = ?', 'red']). + # (such as ['name LIKE ?', "%#{query}%"]). # * Hash - Finds the record that matches these +find+-style conditions - # (such as {color: 'red'}). + # (such as {name: 'David'}). # * +false+ - Returns always +false+. # * No args - Returns +false+ if the table is empty, +true+ otherwise. # - # For more information about specifying conditions as a Hash or Array, - # see the Conditions section in the introduction to ActiveRecord::Base. + # For more information about specifying conditions as a hash or array, + # see the Conditions section in the introduction to ActiveRecord::Base. # # Note: You can't pass in a condition as a string (like name = # 'Jamie'), since it would be sanitized and then queried against @@ -213,7 +213,7 @@ module ActiveRecord relation = relation.where(table[primary_key].eq(conditions)) if conditions != :none end - connection.select_value(relation.arel, "#{name} Exists", relation.bind_values) + connection.select_value(relation, "#{name} Exists", relation.bind_values) ? true : false end # This method is called whenever no records are found with either a single diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 51a8a13d04..949e994f8d 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -45,17 +45,18 @@ class FinderTest < ActiveRecord::TestCase end def test_exists - assert Topic.exists?(1) - assert Topic.exists?("1") - assert Topic.exists?(title: "The First Topic") - assert Topic.exists?(heading: "The First Topic") - assert Topic.exists?(:author_name => "Mary", :approved => true) - assert Topic.exists?(["parent_id = ?", 1]) - assert !Topic.exists?(45) - assert !Topic.exists?(Topic.new) + assert_equal true, Topic.exists?(1) + assert_equal true, Topic.exists?("1") + assert_equal true, Topic.exists?(title: "The First Topic") + assert_equal true, Topic.exists?(heading: "The First Topic") + assert_equal true, Topic.exists?(:author_name => "Mary", :approved => true) + assert_equal true, Topic.exists?(["parent_id = ?", 1]) + + assert_equal false, Topic.exists?(45) + assert_equal false, Topic.exists?(Topic.new) begin - assert !Topic.exists?("foo") + assert_equal false, Topic.exists?("foo") rescue ActiveRecord::StatementInvalid # PostgreSQL complains about string comparison with integer field rescue Exception @@ -72,61 +73,62 @@ class FinderTest < ActiveRecord::TestCase end def test_exists_returns_true_with_one_record_and_no_args - assert Topic.exists? + assert_equal true, Topic.exists? end def test_exists_returns_false_with_false_arg - assert !Topic.exists?(false) + assert_equal false, Topic.exists?(false) end # exists? should handle nil for id's that come from URLs and always return false # (example: Topic.exists?(params[:id])) where params[:id] is nil def test_exists_with_nil_arg - assert !Topic.exists?(nil) - assert Topic.exists? - assert !Topic.first.replies.exists?(nil) - assert Topic.first.replies.exists? + assert_equal false, Topic.exists?(nil) + assert_equal true, Topic.exists? + + assert_equal false, Topic.first.replies.exists?(nil) + assert_equal true, Topic.first.replies.exists? end # ensures +exists?+ runs valid SQL by excluding order value def test_exists_with_order - assert Topic.order(:id).distinct.exists? + assert_equal true, Topic.order(:id).distinct.exists? end def test_exists_with_includes_limit_and_empty_result - assert !Topic.includes(:replies).limit(0).exists? - assert !Topic.includes(:replies).limit(1).where('0 = 1').exists? + assert_equal false, Topic.includes(:replies).limit(0).exists? + assert_equal false, Topic.includes(:replies).limit(1).where('0 = 1').exists? end def test_exists_with_distinct_association_includes_and_limit author = Author.first - assert !author.unique_categorized_posts.includes(:special_comments).limit(0).exists? - assert author.unique_categorized_posts.includes(:special_comments).limit(1).exists? + assert_equal false, author.unique_categorized_posts.includes(:special_comments).limit(0).exists? + assert_equal true, author.unique_categorized_posts.includes(:special_comments).limit(1).exists? end def test_exists_with_distinct_association_includes_limit_and_order author = Author.first - assert !author.unique_categorized_posts.includes(:special_comments).order('comments.taggings_count DESC').limit(0).exists? - assert author.unique_categorized_posts.includes(:special_comments).order('comments.taggings_count DESC').limit(1).exists? + assert_equal false, author.unique_categorized_posts.includes(:special_comments).order('comments.taggings_count DESC').limit(0).exists? + assert_equal true, author.unique_categorized_posts.includes(:special_comments).order('comments.taggings_count DESC').limit(1).exists? end def test_exists_with_empty_table_and_no_args_given Topic.delete_all - assert !Topic.exists? + assert_equal false, Topic.exists? end def test_exists_with_aggregate_having_three_mappings existing_address = customers(:david).address - assert Customer.exists?(:address => existing_address) + assert_equal true, Customer.exists?(:address => existing_address) end def test_exists_with_aggregate_having_three_mappings_with_one_difference existing_address = customers(:david).address - assert !Customer.exists?(:address => + assert_equal false, Customer.exists?(:address => Address.new(existing_address.street, existing_address.city, existing_address.country + "1")) - assert !Customer.exists?(:address => + assert_equal false, Customer.exists?(:address => Address.new(existing_address.street, existing_address.city + "1", existing_address.country)) - assert !Customer.exists?(:address => + assert_equal false, Customer.exists?(:address => Address.new(existing_address.street + "1", existing_address.city, existing_address.country)) end -- cgit v1.2.3 From 2443e0d11c0db352ec1a7c62748f19042c2c725d Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 Aug 2013 14:39:51 +0200 Subject: documents 565c367 in the CHANGELOG --- activerecord/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 904ed0e362..bb56c8c615 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* `ActiveRecord::FinderMethods#exists?` returns `true`/`false` in all cases. + + *Xavier Noria* + * Assign inet/cidr attribute with `nil` value for invalid address. Example: -- cgit v1.2.3 From a0b948e9f554979282baff6464944a33e4f89883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Mon, 19 Aug 2013 10:52:01 -0300 Subject: Fix the indentation on the from template of the scaffold generator --- railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb | 6 +++--- railties/test/generators/scaffold_generator_test.rb | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb index 4a40ba654d..69c10efa47 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb @@ -21,13 +21,13 @@ <%%= f.label :password_confirmation %>
<%%= f.password_field :password_confirmation %> <% else -%> - <% if attribute.reference? -%> + <%- if attribute.reference? -%> <%%= f.label :<%= attribute.column_name %> %>
<%%= f.<%= attribute.field_type %> :<%= attribute.column_name %> %> - <% else -%> + <%- else -%> <%%= f.label :<%= attribute.name %> %>
<%%= f.<%= attribute.field_type %> :<%= attribute.name %> %> - <% end -%> + <%- end -%> <% end -%> <% end -%> diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index 4b837da483..524bbde2b7 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -305,8 +305,8 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase end assert_file "app/views/accounts/_form.html.erb" do |content| - assert_match(/<%= f\.text_field :name %>/, content) - assert_match(/<%= f\.text_field :currency_id %>/, content) + assert_match(/^\W{4}<%= f\.text_field :name %>/, content) + assert_match(/^\W{4}<%= f\.text_field :currency_id %>/, content) end end -- cgit v1.2.3 From eb11e350e4f6f8a102762820cf3b328e0870f5e1 Mon Sep 17 00:00:00 2001 From: Prathamesh Sonpatki Date: Sat, 17 Aug 2013 16:40:07 +0530 Subject: Change the wording to explain following methods skip callbacks [ci skip] --- guides/source/active_record_callbacks.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/guides/source/active_record_callbacks.md b/guides/source/active_record_callbacks.md index df1dd22971..95eb84dd1f 100644 --- a/guides/source/active_record_callbacks.md +++ b/guides/source/active_record_callbacks.md @@ -180,7 +180,7 @@ NOTE: The `find_by_*` and `find_by_*!` methods are dynamic finders generated aut Skipping Callbacks ------------------ -Just as with validations, it is also possible to skip callbacks. These methods should be used with caution, however, because important business rules and application logic may be kept in callbacks. Bypassing them without understanding the potential implications may lead to invalid data. +Just as with validations, it is also possible to skip callbacks by using the following methods: * `decrement` * `decrement_counter` @@ -195,6 +195,8 @@ Just as with validations, it is also possible to skip callbacks. These methods s * `update_all` * `update_counters` +These methods should be used with caution, however, because important business rules and application logic may be kept in callbacks. Bypassing them without understanding the potential implications may lead to invalid data. + Halting Execution ----------------- -- cgit v1.2.3 From e5945e49653e38f4df445284eafda6fa288f071b Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 19 Aug 2013 15:17:11 -0300 Subject: Organize normalize_encoding_params' conditionals a bit better and use a case statement for it Refactor of the work done in #11891 --- actionpack/lib/action_dispatch/http/parameters.rb | 33 ++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index 8e46441d24..ca10da702c 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -57,24 +57,27 @@ module ActionDispatch # you'll get a weird error down the road, but our form handling # should really prevent that from happening def normalize_encode_params(params) - if params.is_a?(String) - return params.force_encoding(Encoding::UTF_8).encode! - elsif Hash === params && params.has_key?(:tempfile) - return UploadedFile.new(params) - elsif !params.is_a?(Hash) - return params - end - - new_hash = {} - params.each do |key, val| - new_key = key.is_a?(String) ? key.dup.force_encoding(Encoding::UTF_8).encode! : key - new_hash[new_key] = if val.is_a?(Array) - val.map! { |el| normalize_encode_params(el) } + case params + when String + params.force_encoding(Encoding::UTF_8).encode! + when Hash + if params.has_key?(:tempfile) + UploadedFile.new(params) else - normalize_encode_params(val) + new_hash = {} + params.each do |key, val| + new_key = key.is_a?(String) ? key.dup.force_encoding(Encoding::UTF_8).encode! : key + new_hash[new_key] = if val.is_a?(Array) + val.map! { |el| normalize_encode_params(el) } + else + normalize_encode_params(val) + end + end + new_hash.with_indifferent_access end + else + params end - new_hash.with_indifferent_access end end end -- cgit v1.2.3 From 55360ddf7fd5f3fedc327476bf07aac3ba698e0d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 19 Aug 2013 15:23:03 -0300 Subject: Use each_with_object --- actionpack/lib/action_dispatch/http/parameters.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index ca10da702c..dcb299ed03 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -64,16 +64,14 @@ module ActionDispatch if params.has_key?(:tempfile) UploadedFile.new(params) else - new_hash = {} - params.each do |key, val| + params.each_with_object({}) do |(key, val), new_hash| new_key = key.is_a?(String) ? key.dup.force_encoding(Encoding::UTF_8).encode! : key new_hash[new_key] = if val.is_a?(Array) val.map! { |el| normalize_encode_params(el) } else normalize_encode_params(val) end - end - new_hash.with_indifferent_access + end.with_indifferent_access end else params -- cgit v1.2.3 From dfb923e6e52d1fed768672b5b7e6277a599f136a Mon Sep 17 00:00:00 2001 From: Nick Howard Date: Mon, 19 Aug 2013 12:39:40 -0600 Subject: ensure freeze on Thread freezes locals --- activesupport/lib/active_support/core_ext/thread.rb | 5 +++++ activesupport/test/core_ext/thread_test.rb | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/activesupport/lib/active_support/core_ext/thread.rb b/activesupport/lib/active_support/core_ext/thread.rb index 878ec73ef0..e80f442973 100644 --- a/activesupport/lib/active_support/core_ext/thread.rb +++ b/activesupport/lib/active_support/core_ext/thread.rb @@ -62,6 +62,11 @@ class Thread _locals.has_key?(key.to_sym) end + def freeze + _locals.freeze + super + end + private def _locals diff --git a/activesupport/test/core_ext/thread_test.rb b/activesupport/test/core_ext/thread_test.rb index 230c1203ad..cf1b48d511 100644 --- a/activesupport/test/core_ext/thread_test.rb +++ b/activesupport/test/core_ext/thread_test.rb @@ -63,6 +63,15 @@ class ThreadExt < ActiveSupport::TestCase end end + def test_thread_variable_frozen_after_set + t = Thread.new { }.join + t.thread_variable_set :foo, "bar" + t.freeze + assert_raises(RuntimeError) do + t.thread_variable_set(:baz, "qux") + end + end + def test_thread_variable_security t = Thread.new { sleep } -- cgit v1.2.3 From 9f3b089b7b288cce1cb891537a8ecae7dba015df Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Tue, 20 Aug 2013 18:24:48 +0200 Subject: write changelog entry for #11922. [ci skip] --- activerecord/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index bb56c8c615..98d2fa62d7 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,8 @@ +* Stop interpreting SQL 'string' columns as :string type because there is no + common STRING datatype in SQL. + + *Ben Woosley* + * `ActiveRecord::FinderMethods#exists?` returns `true`/`false` in all cases. *Xavier Noria* -- cgit v1.2.3 From 3ec6cc70f34a553d36c778731105d3351ccc6bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 20 Aug 2013 15:31:43 -0300 Subject: Fix the indentation :scissors: --- Gemfile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Gemfile b/Gemfile index cff6ae4dec..d703a2e404 100644 --- a/Gemfile +++ b/Gemfile @@ -61,13 +61,13 @@ platforms :ruby do end platforms :jruby do - git 'git://github.com/jruby/activerecord-jdbc-adapter.git' do - gem 'activerecord-jdbcsqlite3-adapter' - group :db do - gem 'activerecord-jdbcmysql-adapter' - gem 'activerecord-jdbcpostgresql-adapter' - end + git 'git://github.com/jruby/activerecord-jdbc-adapter.git' do + gem 'activerecord-jdbcsqlite3-adapter' + group :db do + gem 'activerecord-jdbcmysql-adapter' + gem 'activerecord-jdbcpostgresql-adapter' end + end end # gems that are necessary for ActiveRecord tests with Oracle database -- cgit v1.2.3 From df52eee15fc63b5224c0ff993c748ae9784b5b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luka=20Mar=C4=8Deti=C4=87?= Date: Wed, 21 Aug 2013 04:54:27 +0200 Subject: Remove set_primary_key, replace with primary_key= First deprecated, now removed: https://github.com/rails/rails/commit/9add7608f1acaa68b025470e7a38901d7e6161ca#activerecord/lib/active_record/attribute_methods/primary_key.rb --- guides/source/active_record_basics.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md index 556c2544ff..bff60efc33 100644 --- a/guides/source/active_record_basics.md +++ b/guides/source/active_record_basics.md @@ -188,11 +188,11 @@ end ``` It's also possible to override the column that should be used as the table's -primary key using the `ActiveRecord::Base.set_primary_key` method: +primary key using the `ActiveRecord::Base.primary_key=` method: ```ruby class Product < ActiveRecord::Base - set_primary_key "product_id" + self.primary_key = "product_id" end ``` -- cgit v1.2.3 From a67b956d28f8c5dddcab65414d2469a2a89c3287 Mon Sep 17 00:00:00 2001 From: Gaurish Sharma Date: Mon, 19 Aug 2013 05:14:33 +0530 Subject: Skip few of the ActiveSupport'sinflector test on JRuby --- activesupport/test/inflector_test.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb index 1bb2d7e920..32739d45a9 100644 --- a/activesupport/test/inflector_test.rb +++ b/activesupport/test/inflector_test.rb @@ -230,25 +230,35 @@ class InflectorTest < ActiveSupport::TestCase end end +# FIXME: get following tests to pass on jruby, currently skipped +# +# Currently this fails because ActiveSupport::Multibyte::Unicode#tidy_bytes +# required a specific Encoding::Converter(UTF-8 to UTF8-MAC) which unavailable on JRuby +# causing our tests to error out. +# related bug http://jira.codehaus.org/browse/JRUBY-7194 def test_parameterize + jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterized.each do |some_string, parameterized_string| assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string)) end end def test_parameterize_and_normalize + jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterizedAndNormalized.each do |some_string, parameterized_string| assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string)) end end def test_parameterize_with_custom_separator + jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterizeWithUnderscore.each do |some_string, parameterized_string| assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string, '_')) end end def test_parameterize_with_multi_character_separator + jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterized.each do |some_string, parameterized_string| assert_equal(parameterized_string.gsub('-', '__sep__'), ActiveSupport::Inflector.parameterize(some_string, '__sep__')) end -- cgit v1.2.3 From 631a2d977016df28ccf15f894f78ccaf3dfef913 Mon Sep 17 00:00:00 2001 From: Prathamesh Sonpatki Date: Wed, 21 Aug 2013 11:41:08 +0530 Subject: Moved "`mod_expires` to be enabled" to new line. - Right now the comment was not rendering properly. # The Expires* directives requires the Apache module `mod_expires` to be # enabled. - After this change - # The Expires* directives requires the Apache module # `mod_expires` to be enabled. --- guides/source/asset_pipeline.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index 862742679c..d5f193ff06 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -760,8 +760,8 @@ headers. For Apache: ```apache -# The Expires* directives requires the Apache module `mod_expires` to be -# enabled. +# The Expires* directives requires the Apache module +# `mod_expires` to be enabled. # Use of ETag is discouraged when Last-Modified is present Header unset ETag FileETag None -- cgit v1.2.3 From 7fd475273a4a09e7a10835cca94e6b0dc396c719 Mon Sep 17 00:00:00 2001 From: Adrien Siami Date: Wed, 21 Aug 2013 15:29:12 +0200 Subject: Escape the message of an exception in debug_exceptions to avoid bad rendering --- .../lib/action_dispatch/middleware/templates/rescues/diagnostics.erb | 2 +- .../action_dispatch/middleware/templates/rescues/missing_template.erb | 2 +- .../lib/action_dispatch/middleware/templates/rescues/routing_error.erb | 2 +- .../lib/action_dispatch/middleware/templates/rescues/template_error.erb | 2 +- .../lib/action_dispatch/middleware/templates/rescues/unknown_action.erb | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb index 57a2940802..f154021ae6 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb @@ -8,7 +8,7 @@

-

<%= @exception.message %>

+

<%= h @exception.message %>

<%= render template: "rescues/_source" %> <%= render template: "rescues/_trace" %> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb index ca14215946..5c016e544e 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb @@ -3,5 +3,5 @@
-

<%= @exception.message %>

+

<%= h @exception.message %>

diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb index cd3daff065..7e9cedb95e 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb @@ -2,7 +2,7 @@

Routing Error

-

<%= @exception.message %>

+

<%= h @exception.message %>

<% unless @exception.failures.empty? %>

Failure reasons:

diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb index 31f46ee340..027a0f5b3e 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb @@ -10,7 +10,7 @@

Showing <%= @exception.file_name %> where line #<%= @exception.line_number %> raised:

-
<%= @exception.message %>
+
<%= h @exception.message %>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb index c1fbf67eed..259fb2bb3b 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb @@ -2,5 +2,5 @@

Unknown action

-

<%= @exception.message %>

+

<%= h @exception.message %>

-- cgit v1.2.3 From 9773d2c291cd931aba6dda9705f65460a18b32f3 Mon Sep 17 00:00:00 2001 From: Federico Ravasio Date: Wed, 21 Aug 2013 17:07:33 +0200 Subject: Added method to skip tests on Rubinius to AS/abstract_unit. --- activesupport/test/abstract_unit.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb index 939bd7bfa8..62105da49c 100644 --- a/activesupport/test/abstract_unit.rb +++ b/activesupport/test/abstract_unit.rb @@ -24,3 +24,7 @@ Thread.abort_on_exception = true # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true + +def rubinius_skip(message = '') + skip message if RUBY_ENGINE == 'rbx' +end -- cgit v1.2.3 From a9f6c8f8e1034ba8cb8838bc0136828826f66af8 Mon Sep 17 00:00:00 2001 From: Federico Ravasio Date: Wed, 21 Aug 2013 17:07:45 +0200 Subject: Skip tests involving $SAFE, it's not supported on Rubinius. --- activesupport/test/core_ext/thread_test.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/activesupport/test/core_ext/thread_test.rb b/activesupport/test/core_ext/thread_test.rb index cf1b48d511..54d2dcd8dd 100644 --- a/activesupport/test/core_ext/thread_test.rb +++ b/activesupport/test/core_ext/thread_test.rb @@ -73,6 +73,8 @@ class ThreadExt < ActiveSupport::TestCase end def test_thread_variable_security + rubinius_skip "$SAFE is not supported on Rubinius." + t = Thread.new { sleep } assert_raises(SecurityError) do -- cgit v1.2.3 From e998edd2c02667af53dd55cff1b37a6d4661c181 Mon Sep 17 00:00:00 2001 From: Gaurish Sharma Date: Wed, 21 Aug 2013 09:25:28 +0530 Subject: Define jruby_skip to skip test on JRuby --- activesupport/test/abstract_unit.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb index 939bd7bfa8..1b295b0ce0 100644 --- a/activesupport/test/abstract_unit.rb +++ b/activesupport/test/abstract_unit.rb @@ -24,3 +24,8 @@ Thread.abort_on_exception = true # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true + +# Skips the current run on JRuby using Minitest::Assertions#skip +def jruby_skip(message = '') + skip message if RUBY_ENGINE == 'jruby' +end -- cgit v1.2.3 From 0643daaf4c5a0111842d3421a2b4fecac51916c5 Mon Sep 17 00:00:00 2001 From: Paul Nikitochkin Date: Wed, 21 Aug 2013 22:49:12 +0300 Subject: Updated bug report templates * use `Minitest::Test` instead of deprectaed `MiniTest::Unit::TestCase` [ci skip] --- guides/bug_report_templates/active_record_gem.rb | 2 +- guides/bug_report_templates/active_record_master.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/guides/bug_report_templates/active_record_gem.rb b/guides/bug_report_templates/active_record_gem.rb index a8868a1877..63fbe27aed 100644 --- a/guides/bug_report_templates/active_record_gem.rb +++ b/guides/bug_report_templates/active_record_gem.rb @@ -25,7 +25,7 @@ class Comment < ActiveRecord::Base belongs_to :post end -class BugTest < MiniTest::Unit::TestCase +class BugTest < Minitest::Test def test_association_stuff post = Post.create! post.comments << Comment.create! diff --git a/guides/bug_report_templates/active_record_master.rb b/guides/bug_report_templates/active_record_master.rb index 68069cdd8d..29dedd88d0 100644 --- a/guides/bug_report_templates/active_record_master.rb +++ b/guides/bug_report_templates/active_record_master.rb @@ -36,7 +36,7 @@ class Comment < ActiveRecord::Base belongs_to :post end -class BugTest < MiniTest::Unit::TestCase +class BugTest < Minitest::Test def test_association_stuff post = Post.create! post.comments << Comment.create! -- cgit v1.2.3 From 9d9254f5e0b91323bd3fcdaec06c7d5c71326c14 Mon Sep 17 00:00:00 2001 From: Paul Nikitochkin Date: Wed, 21 Aug 2013 23:09:06 +0300 Subject: Added bug report template for ActionController [ci skip] --- .../bug_report_templates/action_controller_gem.rb | 42 ++++++++++++++++++ .../action_controller_master.rb | 51 ++++++++++++++++++++++ guides/source/contributing_to_ruby_on_rails.md | 10 +++-- 3 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 guides/bug_report_templates/action_controller_gem.rb create mode 100644 guides/bug_report_templates/action_controller_master.rb diff --git a/guides/bug_report_templates/action_controller_gem.rb b/guides/bug_report_templates/action_controller_gem.rb new file mode 100644 index 0000000000..693bc320b3 --- /dev/null +++ b/guides/bug_report_templates/action_controller_gem.rb @@ -0,0 +1,42 @@ +# Activate the gem you are reporting the issue against. +gem 'rails', '4.0.0' + +require 'rails' +require 'action_controller/railtie' + +class TestApp < Rails::Application + config.root = File.dirname(__FILE__) + config.session_store :cookie_store, key: 'cookie_store_key' + config.secret_token = 'secret_token' + config.secret_key_base = 'secret_key_base' + + config.logger = Logger.new($stdout) + Rails.logger = config.logger + + routes.draw do + get '/' => 'test#index' + end +end + +class TestController < ActionController::Base + def index + render text: 'Home' + end +end + +require 'minitest/autorun' +require 'rack/test' + +class BugTest < MiniTest::Unit::TestCase + include Rack::Test::Methods + + def test_returns_success + get '/' + assert last_response.ok? + end + + private + def app + Rails.application + end +end \ No newline at end of file diff --git a/guides/bug_report_templates/action_controller_master.rb b/guides/bug_report_templates/action_controller_master.rb new file mode 100644 index 0000000000..375ed9bc5d --- /dev/null +++ b/guides/bug_report_templates/action_controller_master.rb @@ -0,0 +1,51 @@ +unless File.exists?('Gemfile') + File.write('Gemfile', <<-GEMFILE) + source 'https://rubygems.org' + gem 'rails', github: 'rails/rails' + GEMFILE + + system 'bundle' +end + +require 'bundler' +Bundler.setup(:default) + +require 'rails' +require 'action_controller/railtie' + +class TestApp < Rails::Application + config.root = File.dirname(__FILE__) + config.session_store :cookie_store, key: 'cookie_store_key' + config.secret_token = 'secret_token' + config.secret_key_base = 'secret_key_base' + + config.logger = Logger.new($stdout) + Rails.logger = config.logger + + routes.draw do + get '/' => 'test#index' + end +end + +class TestController < ActionController::Base + def index + render text: 'Home' + end +end + +require 'minitest/autorun' +require 'rack/test' + +class BugTest < Minitest::Test + include Rack::Test::Methods + + def test_returns_success + get '/' + assert last_response.ok? + end + + private + def app + Rails.application + end +end \ No newline at end of file diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index a0352790f4..e3d1165604 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -30,12 +30,14 @@ At the minimum, your issue report needs a title and descriptive text. But that's Then, don't get your hopes up! Unless you have a "Code Red, Mission Critical, the World is Coming to an End" kind of bug, you're creating this issue report in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the issue report will automatically see any activity or that others will jump to fix it. Creating an issue like this is mostly to help yourself start on the path of fixing the problem and for others to confirm it with an "I'm having this problem too" comment. -### Create a Self-Contained gist for Active Record Issues +### Create a Self-Contained gist for Active Record and Action Controller Issues -If you are filing a bug report for Active Record, please use -[this template for gems](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_gem.rb) +If you are filing a bug report, please use +[Active Record template for gems](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_gem.rb) or +[Action Controller template for gems](https://github.com/rails/rails/blob/master/guides/bug_report_templates/action_controller_gem.rb) if the bug is found in a published gem, and -[this template for master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_master.rb) +[Active Record template for master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_master.rb) or +[Action Controller template for master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/action_controller_master.rb) if the bug happens in the master branch. ### Special Treatment for Security Issues -- cgit v1.2.3 From ae54e41824011692106fe7a27dc0991a6342096d Mon Sep 17 00:00:00 2001 From: wangjohn Date: Wed, 21 Aug 2013 16:34:36 -0400 Subject: Removing merge conflict remnants in the guides. --- guides/source/development_dependencies_install.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index 034fef71c8..42340cc2b4 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -86,7 +86,6 @@ And if you are on Fedora or CentOS, you're done with $ sudo yum install sqlite3 sqlite3-devel ``` -<<<<<<< HEAD If you are on Arch Linux, you will need to run: ```bash @@ -101,8 +100,6 @@ For FreeBSD users, you're done with: Or compile the `databases/sqlite3` port. -======= ->>>>>>> ec8ef1e1055c4e1598da13f49d30261f07f4a9b4 Get a recent version of [Bundler](http://gembundler.com/) ```bash @@ -169,7 +166,6 @@ $ sudo yum install mysql-server mysql-devel $ sudo yum install postgresql-server postgresql-devel ``` -<<<<<<< HEAD If you are running Arch Linux, MySQL isn't supported anymore so you will need to use MariaDB instead (see [this announcement](https://www.archlinux.org/news/mariadb-replaces-mysql-in-repositories/)): @@ -189,8 +185,6 @@ Or install them through ports (they are located under the `databases` folder). If you run into troubles during the installation of MySQL, please see [the MySQL documentation](http://dev.mysql.com/doc/refman/5.1/en/freebsd-installation.html). -======= ->>>>>>> ec8ef1e1055c4e1598da13f49d30261f07f4a9b4 After that, run: ```bash -- cgit v1.2.3 From de2043ade69508070fbc80a6eb4f7d5bce58ca76 Mon Sep 17 00:00:00 2001 From: wangjohn Date: Wed, 21 Aug 2013 18:00:47 -0500 Subject: Document ability to run a single test. --- guides/source/development_dependencies_install.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index 42340cc2b4..a5016b6ea8 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -133,13 +133,20 @@ $ cd railties $ TEST_DIR=generators bundle exec rake test ``` -You can run any single test separately too: +You can run the tests for a particular file by using: ```bash $ cd actionpack $ bundle exec ruby -Itest test/template/form_helper_test.rb ``` +Or, you can run a single test in a particular file: + +```bash +$ cd actionpack +$ bundle exec ruby -Itest path/to/test.rb -n test_name +``` + ### Active Record Setup The test suite of Active Record attempts to run four times: once for SQLite3, once for each of the two MySQL gems (`mysql` and `mysql2`), and once for PostgreSQL. We are going to see now how to set up the environment for them. -- cgit v1.2.3 From 646bfe1a5e7b30863e5ab8a5927246be3a69ed3b Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 20 Aug 2013 19:27:17 -0700 Subject: Avoid compiling regexs in AR::Base.respond_to? Caches the patterns of ActiveRecord::DynamicMatchers in a class instance variable. --- activerecord/lib/active_record/dynamic_matchers.rb | 2 +- activerecord/test/cases/finder_respond_to_test.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/dynamic_matchers.rb b/activerecord/lib/active_record/dynamic_matchers.rb index 3bac31c6aa..e650ebcf64 100644 --- a/activerecord/lib/active_record/dynamic_matchers.rb +++ b/activerecord/lib/active_record/dynamic_matchers.rb @@ -35,7 +35,7 @@ module ActiveRecord end def pattern - /^#{prefix}_([_a-zA-Z]\w*)#{suffix}$/ + @pattern ||= /\A#{prefix}_([_a-zA-Z]\w*)#{suffix}\Z/ end def prefix diff --git a/activerecord/test/cases/finder_respond_to_test.rb b/activerecord/test/cases/finder_respond_to_test.rb index 6101eb7b68..3ff22f222f 100644 --- a/activerecord/test/cases/finder_respond_to_test.rb +++ b/activerecord/test/cases/finder_respond_to_test.rb @@ -21,6 +21,11 @@ class FinderRespondToTest < ActiveRecord::TestCase assert_respond_to Topic, :find_by_title end + def test_should_respond_to_find_by_with_bang + ensure_topic_method_is_not_cached(:find_by_title!) + assert_respond_to Topic, :find_by_title! + end + def test_should_respond_to_find_by_two_attributes ensure_topic_method_is_not_cached(:find_by_title_and_author_name) assert_respond_to Topic, :find_by_title_and_author_name -- cgit v1.2.3 From 2c02fc3fd7181ab1cc39b0426491a830e0c52d5a Mon Sep 17 00:00:00 2001 From: Prathamesh Sonpatki Date: Thu, 22 Aug 2013 09:08:38 +0530 Subject: Add error message for including nokogiri in Gemfile for rake doc:guides [ci skip] - When `rake doc:guides` is run from applications, it complains for presence of redcarpet if it not present in Gemfile - Similarly it should complain about nokogiri --- guides/rails_guides.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/guides/rails_guides.rb b/guides/rails_guides.rb index ce409868ca..33975718c9 100644 --- a/guides/rails_guides.rb +++ b/guides/rails_guides.rb @@ -39,6 +39,25 @@ ERROR exit 1 end +begin + require 'nokogiri' +rescue LoadError + # This can happen if doc:guides is executed in an application. + $stderr.puts('Generating guides requires Nokogiri.') + $stderr.puts(< Date: Thu, 22 Aug 2013 14:56:22 +0700 Subject: Use infinity const --- activerecord/lib/active_record/connection_adapters/postgresql/cast.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb index ef7b976d4f..ea44e818e5 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb @@ -17,8 +17,8 @@ module ActiveRecord return string unless String === string case string - when 'infinity'; 1.0 / 0.0 - when '-infinity'; -1.0 / 0.0 + when 'infinity'; Float::INFINITY + when '-infinity'; -Float::INFINITY when / BC$/ super("-" + string.sub(/ BC$/, "")) else -- cgit v1.2.3 From 8ddb4fcbd3fe4d7f2b11afe4316cca4f6c6ca2ec Mon Sep 17 00:00:00 2001 From: edogawaconan Date: Thu, 22 Aug 2013 17:56:07 +0900 Subject: Stray nodoc causes rest of file not parsed [ci skip] --- activerecord/lib/active_record/associations/collection_proxy.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 6dc2da56d1..ea7f768a68 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -848,8 +848,6 @@ module ActiveRecord def scope @association.scope end - - # :nodoc: alias spawn scope # Equivalent to Array#==. Returns +true+ if the two arrays -- cgit v1.2.3 From e744ac7b5429bf996d5cfa1a23c8f502269b2904 Mon Sep 17 00:00:00 2001 From: Sugino Yasuhiro Date: Tue, 20 Aug 2013 11:12:16 +0900 Subject: Add examples of AR order method's hash notation to Rails Guide [ci skip] --- guides/source/active_record_querying.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index ce571c6f96..ba0dc6d9eb 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -524,12 +524,18 @@ To retrieve records from the database in a specific order, you can use the `orde For example, if you're getting a set of records and want to order them in ascending order by the `created_at` field in your table: ```ruby +Client.order(:created_at) +# OR Client.order("created_at") ``` You could specify `ASC` or `DESC` as well: ```ruby +Client.order(created_at: :desc) +# OR +Client.order(created_at: :asc) +# OR Client.order("created_at DESC") # OR Client.order("created_at ASC") @@ -538,6 +544,10 @@ Client.order("created_at ASC") Or ordering by multiple fields: ```ruby +Client.order(orders_count: :asc, created_at: :desc) +# OR +Client.order(:orders_count, created_at: :desc) +# OR Client.order("orders_count ASC, created_at DESC") # OR Client.order("orders_count ASC", "created_at DESC") -- cgit v1.2.3 From a725a453b38057b46878afae39dc107ada2cf326 Mon Sep 17 00:00:00 2001 From: Kir Shatrov Date: Wed, 21 Aug 2013 16:42:04 +0400 Subject: Display exceptions in text format for xhr request --- actionpack/CHANGELOG.md | 4 ++ .../action_dispatch/middleware/debug_exceptions.rb | 34 ++++++++++------- .../templates/rescues/_request_and_response.erb | 34 ----------------- .../rescues/_request_and_response.html.erb | 34 +++++++++++++++++ .../rescues/_request_and_response.text.erb | 23 ++++++++++++ .../middleware/templates/rescues/_trace.erb | 24 ------------ .../middleware/templates/rescues/_trace.html.erb | 24 ++++++++++++ .../middleware/templates/rescues/_trace.text.erb | 15 ++++++++ .../templates/rescues/missing_template.erb | 7 ---- .../templates/rescues/missing_template.html.erb | 7 ++++ .../templates/rescues/missing_template.text.erb | 3 ++ .../middleware/templates/rescues/routing_error.erb | 30 --------------- .../templates/rescues/routing_error.html.erb | 30 +++++++++++++++ .../templates/rescues/routing_error.text.erb | 11 ++++++ .../templates/rescues/template_error.erb | 43 ---------------------- .../templates/rescues/template_error.html.erb | 43 ++++++++++++++++++++++ .../templates/rescues/template_error.text.erb | 8 ++++ .../templates/rescues/unknown_action.erb | 6 --- .../templates/rescues/unknown_action.html.erb | 6 +++ .../templates/rescues/unknown_action.text.erb | 3 ++ actionpack/test/dispatch/debug_exceptions_test.rb | 41 +++++++++++++++++++++ 21 files changed, 273 insertions(+), 157 deletions(-) delete mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb delete mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb delete mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb delete mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb delete mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb delete mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 4e090ed526..6e8ba88b77 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,7 @@ +* Development mode exceptions are rendered in text format in case of XHR request. + + *Kir Shatrov* + * Fix an issue where :if and :unless controller action procs were being run before checking for the correct action in the :only and :unless options. diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb index 64230ff1ae..0ca1a87645 100644 --- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb @@ -34,27 +34,35 @@ module ActionDispatch log_error(env, wrapper) if env['action_dispatch.show_detailed_exceptions'] + request = Request.new(env) template = ActionView::Base.new([RESCUES_TEMPLATE_PATH], - :request => Request.new(env), - :exception => wrapper.exception, - :application_trace => wrapper.application_trace, - :framework_trace => wrapper.framework_trace, - :full_trace => wrapper.full_trace, - :routes_inspector => routes_inspector(exception), - :source_extract => wrapper.source_extract, - :line_number => wrapper.line_number, - :file => wrapper.file + request: request, + exception: wrapper.exception, + application_trace: wrapper.application_trace, + framework_trace: wrapper.framework_trace, + full_trace: wrapper.full_trace, + routes_inspector: routes_inspector(exception), + source_extract: wrapper.source_extract, + line_number: wrapper.line_number, + file: wrapper.file ) file = "rescues/#{wrapper.rescue_template}" - body = template.render(:template => file, :layout => 'rescues/layout') - render(wrapper.status_code, body) + + if request.xhr? + body = template.render(template: file, layout: false, formats: [:text]) + format = "text/plain" + else + body = template.render(template: file, layout: 'rescues/layout') + format = "text/html" + end + render(wrapper.status_code, body, format) else raise exception end end - def render(status, body) - [status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]] + def render(status, body, format) + [status, {'Content-Type' => "#{format}; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]] end def log_error(env, wrapper) diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb deleted file mode 100644 index db219c8fa9..0000000000 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +++ /dev/null @@ -1,34 +0,0 @@ -<% unless @exception.blamed_files.blank? %> - <% if (hide = @exception.blamed_files.length > 8) %> - Toggle blamed files - <% end %> -
><%= @exception.describe_blame %>
-<% end %> - -<% - clean_params = @request.filtered_parameters.clone - clean_params.delete("action") - clean_params.delete("controller") - - request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n") - - def debug_hash(object) - object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n") - end unless self.class.method_defined?(:debug_hash) -%> - -

Request

-

Parameters:

<%= request_dump %>
- -
- - -
- -
- - -
- -

Response

-

Headers:

<%= defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb new file mode 100644 index 0000000000..db219c8fa9 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb @@ -0,0 +1,34 @@ +<% unless @exception.blamed_files.blank? %> + <% if (hide = @exception.blamed_files.length > 8) %> + Toggle blamed files + <% end %> +
><%= @exception.describe_blame %>
+<% end %> + +<% + clean_params = @request.filtered_parameters.clone + clean_params.delete("action") + clean_params.delete("controller") + + request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n") + + def debug_hash(object) + object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n") + end unless self.class.method_defined?(:debug_hash) +%> + +

Request

+

Parameters:

<%= request_dump %>
+ +
+ + +
+ +
+ + +
+ +

Response

+

Headers:

<%= defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb new file mode 100644 index 0000000000..396768ecee --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb @@ -0,0 +1,23 @@ +<% + clean_params = @request.filtered_parameters.clone + clean_params.delete("action") + clean_params.delete("controller") + + request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n") + + def debug_hash(object) + object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n") + end unless self.class.method_defined?(:debug_hash) +%> + +Request parameters +<%= request_dump %> + +Session dump +<%= debug_hash @request.session %> + +Env dump +<%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %> + +Response headers +<%= defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb deleted file mode 100644 index b181909bff..0000000000 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb +++ /dev/null @@ -1,24 +0,0 @@ -<% - traces = { "Application Trace" => @application_trace, - "Framework Trace" => @framework_trace, - "Full Trace" => @full_trace } - names = traces.keys -%> - -

Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %>

- -
- <% names.each do |name| %> - <% - show = "show('#{name.gsub(/\s/, '-')}');" - hide = (names - [name]).collect {|hide_name| "hide('#{hide_name.gsub(/\s/, '-')}');"} - %> - <%= name %> <%= '|' unless names.last == name %> - <% end %> - - <% traces.each do |name, trace| %> -
;"> -
<%= trace.join "\n" %>
-
- <% end %> -
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb new file mode 100644 index 0000000000..b181909bff --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb @@ -0,0 +1,24 @@ +<% + traces = { "Application Trace" => @application_trace, + "Framework Trace" => @framework_trace, + "Full Trace" => @full_trace } + names = traces.keys +%> + +

Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %>

+ +
+ <% names.each do |name| %> + <% + show = "show('#{name.gsub(/\s/, '-')}');" + hide = (names - [name]).collect {|hide_name| "hide('#{hide_name.gsub(/\s/, '-')}');"} + %> + <%= name %> <%= '|' unless names.last == name %> + <% end %> + + <% traces.each do |name, trace| %> +
;"> +
<%= trace.join "\n" %>
+
+ <% end %> +
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb new file mode 100644 index 0000000000..d4af5c9b06 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb @@ -0,0 +1,15 @@ +<% + traces = { "Application Trace" => @application_trace, + "Framework Trace" => @framework_trace, + "Full Trace" => @full_trace } +%> + +Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %> + +<% traces.each do |name, trace| %> +<% if trace.any? %> +<%= name %> +<%= trace.join("\n") %> + +<% end %> +<% end %> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb deleted file mode 100644 index 5c016e544e..0000000000 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +++ /dev/null @@ -1,7 +0,0 @@ -
-

Template is missing

-
- -
-

<%= h @exception.message %>

-
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb new file mode 100644 index 0000000000..5c016e544e --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb @@ -0,0 +1,7 @@ +
+

Template is missing

+
+ +
+

<%= h @exception.message %>

+
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb new file mode 100644 index 0000000000..ae62d9eb02 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb @@ -0,0 +1,3 @@ +Template is missing + +<%= @exception.message %> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb deleted file mode 100644 index 7e9cedb95e..0000000000 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +++ /dev/null @@ -1,30 +0,0 @@ -
-

Routing Error

-
-
-

<%= h @exception.message %>

- <% unless @exception.failures.empty? %> -

-

Failure reasons:

-
    - <% @exception.failures.each do |route, reason| %> -
  1. <%= route.inspect.delete('\\') %> failed because <%= reason.downcase %>
  2. - <% end %> -
-

- <% end %> - - <%= render template: "rescues/_trace" %> - - <% if @routes_inspector %> -

- Routes -

- -

- Routes match in priority from top to bottom -

- - <%= @routes_inspector.format(ActionDispatch::Routing::HtmlTableFormatter.new(self)) %> - <% end %> -
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb new file mode 100644 index 0000000000..7e9cedb95e --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb @@ -0,0 +1,30 @@ +
+

Routing Error

+
+
+

<%= h @exception.message %>

+ <% unless @exception.failures.empty? %> +

+

Failure reasons:

+
    + <% @exception.failures.each do |route, reason| %> +
  1. <%= route.inspect.delete('\\') %> failed because <%= reason.downcase %>
  2. + <% end %> +
+

+ <% end %> + + <%= render template: "rescues/_trace" %> + + <% if @routes_inspector %> +

+ Routes +

+ +

+ Routes match in priority from top to bottom +

+ + <%= @routes_inspector.format(ActionDispatch::Routing::HtmlTableFormatter.new(self)) %> + <% end %> +
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb new file mode 100644 index 0000000000..f6e4dac1f3 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb @@ -0,0 +1,11 @@ +Routing Error + +<%= @exception.message %> +<% unless @exception.failures.empty? %> +Failure reasons: +<% @exception.failures.each do |route, reason| %> + - <%= route.inspect.delete('\\') %> failed because <%= reason.downcase %> +<% end %> +<% end %> + +<%= render template: "rescues/_trace", format: :text %> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb deleted file mode 100644 index 027a0f5b3e..0000000000 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb +++ /dev/null @@ -1,43 +0,0 @@ -<% @source_extract = @exception.source_extract(0, :html) %> -
-

- <%= @exception.original_exception.class.to_s %> in - <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %> -

-
- -
-

- Showing <%= @exception.file_name %> where line #<%= @exception.line_number %> raised: -

-
<%= h @exception.message %>
- -
-
-

Extracted source (around line #<%= @exception.line_number %>):

-
-
- - - - - -
-
-            <% @source_extract.keys.each do |line_number| %>
-<%= line_number -%>
-            <% end %>
-          
-
-
-<% @source_extract.each do |line, source| -%>
"><%= source -%>
<% end -%> -
-
-
-
- -

<%= @exception.sub_template_message %>

- - <%= render template: "rescues/_trace" %> - <%= render template: "rescues/_request_and_response" %> -
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb new file mode 100644 index 0000000000..027a0f5b3e --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb @@ -0,0 +1,43 @@ +<% @source_extract = @exception.source_extract(0, :html) %> +
+

+ <%= @exception.original_exception.class.to_s %> in + <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %> +

+
+ +
+

+ Showing <%= @exception.file_name %> where line #<%= @exception.line_number %> raised: +

+
<%= h @exception.message %>
+ +
+
+

Extracted source (around line #<%= @exception.line_number %>):

+
+
+ + + + + +
+
+            <% @source_extract.keys.each do |line_number| %>
+<%= line_number -%>
+            <% end %>
+          
+
+
+<% @source_extract.each do |line, source| -%>
"><%= source -%>
<% end -%> +
+
+
+
+ +

<%= @exception.sub_template_message %>

+ + <%= render template: "rescues/_trace" %> + <%= render template: "rescues/_request_and_response" %> +
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb new file mode 100644 index 0000000000..5da21d9784 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb @@ -0,0 +1,8 @@ +<% @source_extract = @exception.source_extract(0, :html) %> +<%= @exception.original_exception.class.to_s %> in <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %> + +Showing <%= @exception.file_name %> where line #<%= @exception.line_number %> raised: +<%= @exception.message %> +<%= @exception.sub_template_message %> +<%= render template: "rescues/_trace", format: :text %> +<%= render template: "rescues/_request_and_response", format: :text %> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb deleted file mode 100644 index 259fb2bb3b..0000000000 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +++ /dev/null @@ -1,6 +0,0 @@ -
-

Unknown action

-
-
-

<%= h @exception.message %>

-
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb new file mode 100644 index 0000000000..259fb2bb3b --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb @@ -0,0 +1,6 @@ +
+

Unknown action

+
+
+

<%= h @exception.message %>

+
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb new file mode 100644 index 0000000000..83973addcb --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb @@ -0,0 +1,3 @@ +Unknown action + +<%= @exception.message %> diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb index ff0baccd76..3045a07ad6 100644 --- a/actionpack/test/dispatch/debug_exceptions_test.rb +++ b/actionpack/test/dispatch/debug_exceptions_test.rb @@ -128,6 +128,47 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest assert_match(/ActionController::ParameterMissing/, body) end + test "rescue with text error for xhr request" do + @app = DevelopmentApp + xhr_request_env = {'action_dispatch.show_exceptions' => true, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'} + + get "/", {}, xhr_request_env + assert_response 500 + assert_no_match(//, body) + assert_equal response.content_type, "text/plain" + assert_match(/puke/, body) + + get "/not_found", {}, xhr_request_env + assert_response 404 + assert_no_match(//, body) + assert_equal response.content_type, "text/plain" + assert_match(/#{AbstractController::ActionNotFound.name}/, body) + + get "/method_not_allowed", {}, xhr_request_env + assert_response 405 + assert_no_match(//, body) + assert_equal response.content_type, "text/plain" + assert_match(/ActionController::MethodNotAllowed/, body) + + get "/unknown_http_method", {}, xhr_request_env + assert_response 405 + assert_no_match(//, body) + assert_equal response.content_type, "text/plain" + assert_match(/ActionController::UnknownHttpMethod/, body) + + get "/bad_request", {}, xhr_request_env + assert_response 400 + assert_no_match(//, body) + assert_equal response.content_type, "text/plain" + assert_match(/ActionController::BadRequest/, body) + + get "/parameter_missing", {}, xhr_request_env + assert_response 400 + assert_no_match(//, body) + assert_equal response.content_type, "text/plain" + assert_match(/ActionController::ParameterMissing/, body) + end + test "does not show filtered parameters" do @app = DevelopmentApp -- cgit v1.2.3 From 8c5d62f79669fcf67d106036177d731703f3aa44 Mon Sep 17 00:00:00 2001 From: wangjohn Date: Thu, 22 Aug 2013 16:15:11 -0400 Subject: Making proper_table_name take in options. The options will specify the prefix and the suffix. Also, I'm moving the method to be an instance method on the +Migration+ instance. This makes more sense than being a class method on the +Migrator+ class because the only place that uses it is on a +Migration+ instance (in a method_missing hook). The logic for the Migrator shouldn't be doing any work to calculate the table name, it should be the Migration itself. Also made some small indentation fixes. --- activerecord/lib/active_record/migration.rb | 58 ++++++++++++++++++++--------- activerecord/test/cases/migration_test.rb | 29 ++++++++++++++- 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 19c6f8148b..888e8771ce 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -373,23 +373,23 @@ module ActiveRecord class << self attr_accessor :delegate # :nodoc: attr_accessor :disable_ddl_transaction # :nodoc: - end - def self.check_pending! - raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration? - end + def check_pending! + raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration? + end - def self.method_missing(name, *args, &block) # :nodoc: - (delegate || superclass.delegate).send(name, *args, &block) - end + def method_missing(name, *args, &block) # :nodoc: + (delegate || superclass.delegate).send(name, *args, &block) + end - def self.migrate(direction) - new.migrate direction - end + def migrate(direction) + new.migrate direction + end - # Disable DDL transactions for this migration. - def self.disable_ddl_transaction! - @disable_ddl_transaction = true + # Disable DDL transactions for this migration. + def disable_ddl_transaction! + @disable_ddl_transaction = true + end end def disable_ddl_transaction # :nodoc: @@ -617,8 +617,8 @@ module ActiveRecord say_with_time "#{method}(#{arg_list})" do unless @connection.respond_to? :revert unless arguments.empty? || method == :execute - arguments[0] = Migrator.proper_table_name(arguments.first) - arguments[1] = Migrator.proper_table_name(arguments.second) if method == :rename_table + arguments[0] = proper_table_name(arguments.first, table_name_options) + arguments[1] = proper_table_name(arguments.second, table_name_options) if method == :rename_table end end return super unless connection.respond_to?(method) @@ -671,6 +671,17 @@ module ActiveRecord copied end + # Finds the correct table name given an Active Record object. + # Uses the Active Record object's own table_name, or pre/suffix from the + # options passed in. + def proper_table_name(name, options = {}) + if name.respond_to? :table_name + name.table_name + else + "#{options[:table_name_prefix]}#{name}#{options[:table_name_suffix]}" + end + end + # Determines the version number of the next migration. def next_migration_number(number) if ActiveRecord::Base.timestamped_migrations @@ -680,6 +691,13 @@ module ActiveRecord end end + def table_name_options(config = ActiveRecord::Base) + { + table_name_prefix: config.table_name_prefix, + table_name_suffix: config.table_name_suffix + } + end + private def execute_block if connection.respond_to? :execute_block @@ -809,12 +827,16 @@ module ActiveRecord migrations(migrations_paths).last || NullMigration.new end - def proper_table_name(name) - # Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string + def proper_table_name(name, options = {}) + ActiveSupport::Deprecation.warn "ActiveRecord::Migrator.proper_table_name is deprecated and will be removed in Rails 4.1. Use the proper_table_name instance method on ActiveRecord::Migration instead" + options = { + table_name_prefix: ActiveRecord::Base.table_name_prefix, + table_name_suffix: ActiveRecord::Base.table_name_suffix + }.merge(options) if name.respond_to? :table_name name.table_name else - "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}" + "#{options[:table_name_prefix]}#{name}#{options[:table_name_suffix]}" end end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index ed080b2995..cbc9e96473 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -321,7 +321,7 @@ class MigrationTest < ActiveRecord::TestCase assert_equal "schema_migrations", ActiveRecord::Migrator.schema_migrations_table_name end - def test_proper_table_name + def test_proper_table_name_on_migrator assert_equal "table", ActiveRecord::Migrator.proper_table_name('table') assert_equal "table", ActiveRecord::Migrator.proper_table_name(:table) assert_equal "reminders", ActiveRecord::Migrator.proper_table_name(Reminder) @@ -347,6 +347,33 @@ class MigrationTest < ActiveRecord::TestCase assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name(:table) end + def test_proper_table_name_on_migration + migration = ActiveRecord::Migration.new + assert_equal "table", migration.proper_table_name('table') + assert_equal "table", migration.proper_table_name(:table) + assert_equal "reminders", migration.proper_table_name(Reminder) + Reminder.reset_table_name + assert_equal Reminder.table_name, migration.proper_table_name(Reminder) + + # Use the model's own prefix/suffix if a model is given + ActiveRecord::Base.table_name_prefix = "ARprefix_" + ActiveRecord::Base.table_name_suffix = "_ARsuffix" + Reminder.table_name_prefix = 'prefix_' + Reminder.table_name_suffix = '_suffix' + Reminder.reset_table_name + assert_equal "prefix_reminders_suffix", migration.proper_table_name(Reminder) + Reminder.table_name_prefix = '' + Reminder.table_name_suffix = '' + Reminder.reset_table_name + + # Use AR::Base's prefix/suffix if string or symbol is given + ActiveRecord::Base.table_name_prefix = "prefix_" + ActiveRecord::Base.table_name_suffix = "_suffix" + Reminder.reset_table_name + assert_equal "prefix_table_suffix", migration.proper_table_name('table', migration.table_name_options) + assert_equal "prefix_table_suffix", migration.proper_table_name(:table, migration.table_name_options) + end + def test_rename_table_with_prefix_and_suffix assert !Thing.table_exists? ActiveRecord::Base.table_name_prefix = 'p_' -- cgit v1.2.3 From ef7b09016bcaf0e78ecae5fe5c39e6d4d744d027 Mon Sep 17 00:00:00 2001 From: Prathamesh Sonpatki Date: Fri, 23 Aug 2013 08:35:15 +0530 Subject: Add a note about edge guides in the feedback section[ci skip] --- guides/source/layout.html.erb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/guides/source/layout.html.erb b/guides/source/layout.html.erb index 24e1e23497..0513066f5a 100644 --- a/guides/source/layout.html.erb +++ b/guides/source/layout.html.erb @@ -106,8 +106,10 @@

You may also find incomplete content, or stuff that is not up to date. - Please do add any missing documentation for master. Check the - <%= link_to 'Ruby on Rails Guides Guidelines', 'ruby_on_rails_guides_guidelines.html' %> + Please do add any missing documentation for master. Make sure to check + <%= link_to 'Edge Guides','http://edgeguides.rubyonrails.org' %> first to verify + if the issues are already fixed or not on the master branch. + Check the <%= link_to 'Ruby on Rails Guides Guidelines', 'ruby_on_rails_guides_guidelines.html' %> for style and conventions.

-- cgit v1.2.3 From 9f478deaab796f2464c8f105d16b55ef0b02a64d Mon Sep 17 00:00:00 2001 From: Rajarshi Das Date: Fri, 23 Aug 2013 15:40:09 +0530 Subject: remove unused instance variable --- activemodel/test/cases/serializers/xml_serialization_test.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activemodel/test/cases/serializers/xml_serialization_test.rb b/activemodel/test/cases/serializers/xml_serialization_test.rb index c4cfb0c255..11ee17bb27 100644 --- a/activemodel/test/cases/serializers/xml_serialization_test.rb +++ b/activemodel/test/cases/serializers/xml_serialization_test.rb @@ -53,8 +53,7 @@ class XmlSerializationTest < ActiveModel::TestCase @contact.address.city = "Springfield" @contact.address.apt_number = 35 @contact.friends = [Contact.new, Contact.new] - @related_contact = SerializableContact.new - @contact.contact = @related_contact + @contact.contact = SerializableContact.new end test "should serialize default root" do -- cgit v1.2.3 From d1f33e09635af7bca1399de0533091fa7b47a49f Mon Sep 17 00:00:00 2001 From: Semyon Perepelitsa Date: Fri, 23 Aug 2013 15:27:37 +0400 Subject: Fix typo in file path, should include extension. --- railties/lib/rails/engine.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 8000fc3b1e..f25f629aa5 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -102,7 +102,7 @@ module Rails # paths["config"] # => ["config"] # paths["config/initializers"] # => ["config/initializers"] # paths["config/locales"] # => ["config/locales"] - # paths["config/routes"] # => ["config/routes.rb"] + # paths["config/routes.rb"] # => ["config/routes.rb"] # end # # The Application class adds a couple more paths to this set. And as in your -- cgit v1.2.3 From 3aa46da47179e78773c096380ce82f3915d11f10 Mon Sep 17 00:00:00 2001 From: Akshay Surve Date: Fri, 23 Aug 2013 18:09:49 +0530 Subject: Adds Akshay Surve to Rails Guides credits list I had written the original guide for "A Guide to Testing Rails Applications". The current documents maintains the same structure and examples I had drafted albeit with some minor changes to keep up with newer version of Rails. Older version which had credits included: http://guides.rubyonrails.org/v2.3.11/testing.html Github lifo/docrails History: https://github.com/rails/rails/commits/ff359af86505b4d317b7467e7f79aa2ef2c5e795/railties/doc/guides/source/testing_rails_applications.txt --- guides/assets/images/akshaysurve.jpg | Bin 0 -> 3444 bytes guides/source/credits.html.erb | 4 ++++ 2 files changed, 4 insertions(+) create mode 100644 guides/assets/images/akshaysurve.jpg diff --git a/guides/assets/images/akshaysurve.jpg b/guides/assets/images/akshaysurve.jpg new file mode 100644 index 0000000000..cfc3333958 Binary files /dev/null and b/guides/assets/images/akshaysurve.jpg differ diff --git a/guides/source/credits.html.erb b/guides/source/credits.html.erb index 10dd8178fb..a2c57fca8c 100644 --- a/guides/source/credits.html.erb +++ b/guides/source/credits.html.erb @@ -74,3 +74,7 @@ Oscar Del Ben is a software engineer at Wi <%= author('Heiko Webers', 'hawe') do %> Heiko Webers is the founder of bauland42, a German web application security consulting and development company focused on Ruby on Rails. He blogs at the Ruby on Rails Security Project. After 10 years of desktop application development, Heiko has rarely looked back. <% end %> + +<%= author('Akshay Surve', 'startupjockey', 'akshaysurve.jpg') do %> + Akshay Surve is the Founder at DeltaX, hackathon specialist, a midnight code junkie and ocassionally writes prose. You can connect with him on Twitter, Linkedin, Peronal Blog or Quora. +<% end %> -- cgit v1.2.3 From b77f25cb8479a8ff6c93b1d6bbf0771e5368434f Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 23 Aug 2013 17:59:11 +0200 Subject: cleans the guides sources from fancy non-ASCII stuff --- guides/source/2_3_release_notes.md | 8 ++--- guides/source/action_controller_overview.md | 4 +-- guides/source/action_view_overview.md | 6 ++-- guides/source/active_record_validations.md | 2 +- guides/source/api_documentation_guidelines.md | 2 +- guides/source/asset_pipeline.md | 12 +++---- guides/source/association_basics.md | 4 +-- guides/source/caching_with_rails.md | 4 +-- guides/source/configuring.md | 16 ++++----- guides/source/contributing_to_ruby_on_rails.md | 18 +++++----- guides/source/debugging_rails_applications.md | 2 +- guides/source/development_dependencies_install.md | 4 +-- guides/source/engines.md | 8 ++--- guides/source/form_helpers.md | 10 +++--- guides/source/getting_started.md | 8 ++--- guides/source/i18n.md | 20 +++++------ guides/source/nested_model_forms.md | 6 ++-- guides/source/plugins.md | 2 +- guides/source/rails_application_templates.md | 10 +++--- guides/source/security.md | 44 +++++++++++------------ guides/source/testing.md | 2 +- 21 files changed, 96 insertions(+), 96 deletions(-) diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md index 0f05cc6b85..911d8d2eef 100644 --- a/guides/source/2_3_release_notes.md +++ b/guides/source/2_3_release_notes.md @@ -237,7 +237,7 @@ If you're one of the people who has always been bothered by the special-case nam ### HTTP Digest Authentication Support -Rails now has built-in support for HTTP digest authentication. To use it, you call `authenticate_or_request_with_http_digest` with a block that returns the user’s password (which is then hashed and compared against the transmitted credentials): +Rails now has built-in support for HTTP digest authentication. To use it, you call `authenticate_or_request_with_http_digest` with a block that returns the uses's password (which is then hashed and compared against the transmitted credentials): ```ruby class PostsController < ApplicationController @@ -451,11 +451,11 @@ select(:post, :category, Post::CATEGORIES, :disabled => 'private') returns ```html - - + ``` @@ -606,7 +606,7 @@ A few pieces of older code are deprecated in this release: * If you're one of the (fairly rare) Rails developers who deploys in a fashion that depends on the inspector, reaper, and spawner scripts, you'll need to know that those scripts are no longer included in core Rails. If you need them, you'll be able to pick up copies via the [irs_process_scripts](http://github.com/rails/irs_process_scripts/tree) plugin. * `render_component` goes from "deprecated" to "nonexistent" in Rails 2.3. If you still need it, you can install the [render_component plugin](http://github.com/rails/render_component/tree/master.) * Support for Rails components has been removed. -* If you were one of the people who got used to running `script/performance/request` to look at performance based on integration tests, you need to learn a new trick: that script has been removed from core Rails now. There’s a new request_profiler plugin that you can install to get the exact same functionality back. +* If you were one of the people who got used to running `script/performance/request` to look at performance based on integration tests, you need to learn a new trick: that script has been removed from core Rails now. There's a new request_profiler plugin that you can install to get the exact same functionality back. * `ActionController::Base#session_enabled?` is deprecated because sessions are lazy-loaded now. * The `:digest` and `:secret` options to `protect_from_forgery` are deprecated and have no effect. * Some integration test helpers have been removed. `response.headers["Status"]` and `headers["Status"]` will no longer return anything. Rack does not allow "Status" in its return headers. However you can still use the `status` and `status_message` helpers. `response.headers["cookie"]` and `headers["cookie"]` will no longer return any CGI cookies. You can inspect `headers["Set-Cookie"]` to see the raw cookie header or use the `cookies` helper to get a hash of the cookies sent to the client. diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index ecaee02cce..8dcd544a52 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -348,7 +348,7 @@ All session stores use a cookie to store a unique ID for each session (you must For most stores, this ID is used to look up the session data on the server, e.g. in a database table. There is one exception, and that is the default and recommended session store - the CookieStore - which stores all session data in the cookie itself (the ID is still available to you if you need it). This has the advantage of being very lightweight and it requires zero setup in a new application in order to use the session. The cookie data is cryptographically signed to make it tamper-proof. And it is also encrypted so anyone with access to it can't read its contents. (Rails will not accept it if it has been edited). -The CookieStore can store around 4kB of data — much less than the others — but this is usually enough. Storing large amounts of data in the session is discouraged no matter which session store your application uses. You should especially avoid storing complex objects (anything other than basic Ruby objects, the most common example being model instances) in the session, as the server might not be able to reassemble them between requests, which will result in an error. +The CookieStore can store around 4kB of data - much less than the others - but this is usually enough. Storing large amounts of data in the session is discouraged no matter which session store your application uses. You should especially avoid storing complex objects (anything other than basic Ruby objects, the most common example being model instances) in the session, as the server might not be able to reassemble them between requests, which will result in an error. If your user sessions don't store critical data or don't need to be around for long periods (for instance if you just use the flash for messaging), you can consider using ActionDispatch::Session::CacheStore. This will store sessions using the cache implementation you have configured for your application. The advantage of this is that you can use your existing cache infrastructure for storing sessions without requiring any additional setup or administration. The downside, of course, is that the sessions will be ephemeral and could disappear at any time. @@ -538,7 +538,7 @@ end Cookies ------- -Your application can store small amounts of data on the client — called cookies — that will be persisted across requests and even sessions. Rails provides easy access to cookies via the `cookies` method, which — much like the `session` — works like a hash: +Your application can store small amounts of data on the client - called cookies - that will be persisted across requests and even sessions. Rails provides easy access to cookies via the `cookies` method, which - much like the `session` - works like a hash: ```ruby class CommentsController < ApplicationController diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md index f7d2016784..5cda104138 100644 --- a/guides/source/action_view_overview.md +++ b/guides/source/action_view_overview.md @@ -152,7 +152,7 @@ By default, Rails will compile each template to a method in order to render it. ### Partials -Partial templates – usually just called "partials" – are another device for breaking the rendering process into more manageable chunks. With partials, you can extract pieces of code from your templates to separate files and also reuse them throughout your templates. +Partial templates - usually just called "partials" - are another device for breaking the rendering process into more manageable chunks. With partials, you can extract pieces of code from your templates to separate files and also reuse them throughout your templates. #### Naming Partials @@ -1526,7 +1526,7 @@ The SanitizeHelper module provides a set of methods for scrubbing text of undesi #### sanitize -This sanitize helper will html encode all tags and strip all attributes that aren’t specifically allowed. +This sanitize helper will html encode all tags and strip all attributes that aren't specifically allowed. ```ruby sanitize @article.body @@ -1583,7 +1583,7 @@ strip_tags("Bold no more! See more") # => Bold no more! See more ``` -NB: The output may still contain unescaped ‘<’, ‘>’, ‘&’ characters and confuse browsers. +NB: The output may still contain unescaped '<', '>', '&' characters and confuse browsers. Localized Views diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md index 8154d4e1cc..0b2f0a47fa 100644 --- a/guides/source/active_record_validations.md +++ b/guides/source/active_record_validations.md @@ -684,7 +684,7 @@ class GoodnessValidator end end - # … + # ... end ``` diff --git a/guides/source/api_documentation_guidelines.md b/guides/source/api_documentation_guidelines.md index 7e056d970c..98ead9570f 100644 --- a/guides/source/api_documentation_guidelines.md +++ b/guides/source/api_documentation_guidelines.md @@ -172,7 +172,7 @@ In lists of options, parameters, etc. use a hyphen between the item and its desc # * :allow_nil - Skip validation if attribute is +nil+. ``` -The description starts in upper case and ends with a full stop—it's standard English. +The description starts in upper case and ends with a full stop-it's standard English. Dynamically Generated Methods ----------------------------- diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index 862742679c..0b553ca75f 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -151,7 +151,7 @@ environments. You can enable or disable it in your configuration through the More reading: * [Optimize caching](http://code.google.com/speed/page-speed/docs/caching.html) -* [Revving Filenames: don’t use +* [Revving Filenames: don't use * querystring](http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/) @@ -378,8 +378,8 @@ it would make sense to have an image in one of the asset load paths, such as already available in `public/assets` as a fingerprinted file, then that path is referenced. -If you want to use a [data URI](http://en.wikipedia.org/wiki/Data_URI_scheme) — -a method of embedding the image data directly into the CSS file — you can use +If you want to use a [data URI](http://en.wikipedia.org/wiki/Data_URI_scheme) - +a method of embedding the image data directly into the CSS file - you can use the `asset_data_uri` helper. ```css @@ -428,7 +428,7 @@ $('#logo').attr src: "<%= asset_path('logo.png') %>" ### Manifest Files and Directives Sprockets uses manifest files to determine which assets to include and serve. -These manifest files contain _directives_ — instructions that tell Sprockets +These manifest files contain _directives_ - instructions that tell Sprockets which files to require in order to build a single CSS or JavaScript file. With these directives, Sprockets loads the files specified, processes them if necessary, concatenates them into one single file and then compresses them (if @@ -536,7 +536,7 @@ Additional layers of preprocessing can be requested by adding other extensions, where each extension is processed in a right-to-left manner. These should be used in the order the processing should be applied. For example, a stylesheet called `app/assets/stylesheets/projects.css.scss.erb` is first processed as ERB, -then SCSS, and finally served as CSS. The same applies to a JavaScript file — +then SCSS, and finally served as CSS. The same applies to a JavaScript file - `app/assets/javascripts/projects.js.coffee.erb` is processed as ERB, then CoffeeScript, and served as JavaScript. @@ -589,7 +589,7 @@ generate instead: Assets are compiled and cached on the first request after the server is started. Sprockets sets a `must-revalidate` Cache-Control HTTP header to reduce request -overhead on subsequent requests — on these the browser gets a 304 (Not Modified) +overhead on subsequent requests - on these the browser gets a 304 (Not Modified) response. If any of the files in the manifest have changed between requests, the server diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index e133e71d42..c58dd2e90a 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -40,7 +40,7 @@ end @customer.destroy ``` -With Active Record associations, we can streamline these — and other — operations by declaratively telling Rails that there is a connection between the two models. Here's the revised code for setting up customers and orders: +With Active Record associations, we can streamline these - and other - operations by declaratively telling Rails that there is a connection between the two models. Here's the revised code for setting up customers and orders: ```ruby class Customer < ActiveRecord::Base @@ -69,7 +69,7 @@ To learn more about the different types of associations, read the next section o The Types of Associations ------------------------- -In Rails, an _association_ is a connection between two Active Record models. Associations are implemented using macro-style calls, so that you can declaratively add features to your models. For example, by declaring that one model `belongs_to` another, you instruct Rails to maintain Primary Key–Foreign Key information between instances of the two models, and you also get a number of utility methods added to your model. Rails supports six types of associations: +In Rails, an _association_ is a connection between two Active Record models. Associations are implemented using macro-style calls, so that you can declaratively add features to your models. For example, by declaring that one model `belongs_to` another, you instruct Rails to maintain Primary Key-Foreign Key information between instances of the two models, and you also get a number of utility methods added to your model. Rails supports six types of associations: * `belongs_to` * `has_one` diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md index 1e196b0e42..3cf6631c32 100644 --- a/guides/source/caching_with_rails.md +++ b/guides/source/caching_with_rails.md @@ -301,7 +301,7 @@ Conditional GET support Conditional GETs are a feature of the HTTP specification that provide a way for web servers to tell browsers that the response to a GET request hasn't changed since the last request and can be safely pulled from the browser cache. -They work by using the `HTTP_IF_NONE_MATCH` and `HTTP_IF_MODIFIED_SINCE` headers to pass back and forth both a unique content identifier and the timestamp of when the content was last changed. If the browser makes a request where the content identifier (etag) or last modified since timestamp matches the server’s version then the server only needs to send back an empty response with a not modified status. +They work by using the `HTTP_IF_NONE_MATCH` and `HTTP_IF_MODIFIED_SINCE` headers to pass back and forth both a unique content identifier and the timestamp of when the content was last changed. If the browser makes a request where the content identifier (etag) or last modified since timestamp matches the server's version then the server only needs to send back an empty response with a not modified status. It is the server's (i.e. our) responsibility to look for a last modified timestamp and the if-none-match header and determine whether or not to send back the full response. With conditional-get support in Rails this is a pretty easy task: @@ -338,7 +338,7 @@ class ProductsController < ApplicationController end ``` -If you don't have any special response processing and are using the default rendering mechanism (i.e. you're not using respond_to or calling render yourself) then you’ve got an easy helper in fresh_when: +If you don't have any special response processing and are using the default rendering mechanism (i.e. you're not using respond_to or calling render yourself) then you've got an easy helper in fresh_when: ```ruby class ProductsController < ApplicationController diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 0620849519..ce18091ff9 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -107,7 +107,7 @@ numbers. New applications filter out passwords by adding the following `config.f * `config.log_level` defines the verbosity of the Rails logger. This option defaults to `:debug` for all modes except production, where it defaults to `:info`. -* `config.log_tags` accepts a list of methods that respond to `request` object. This makes it easy to tag log lines with debug information like subdomain and request id — both very helpful in debugging multi-user production applications. +* `config.log_tags` accepts a list of methods that respond to `request` object. This makes it easy to tag log lines with debug information like subdomain and request id - both very helpful in debugging multi-user production applications. * `config.logger` accepts a logger conforming to the interface of Log4r or the default Ruby `Logger` class. Defaults to an instance of `ActiveSupport::Logger`, with auto flushing off in production mode. @@ -117,7 +117,7 @@ numbers. New applications filter out passwords by adding the following `config.f * `config.secret_key_base` used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering. Applications get `config.secret_key_base` initialized to a random key in `config/initializers/secret_token.rb`. -* `config.serve_static_assets` configures Rails itself to serve static assets. Defaults to true, but in the production environment is turned off as the server software (e.g. Nginx or Apache) used to run the application should serve static assets instead. Unlike the default setting set this to true when running (absolutely not recommended!) or testing your app in production mode using WEBrick. Otherwise you won´t be able use page caching and requests for files that exist regularly under the public directory will anyway hit your Rails app. +* `config.serve_static_assets` configures Rails itself to serve static assets. Defaults to true, but in the production environment is turned off as the server software (e.g. Nginx or Apache) used to run the application should serve static assets instead. Unlike the default setting set this to true when running (absolutely not recommended!) or testing your app in production mode using WEBrick. Otherwise you won't be able use page caching and requests for files that exist regularly under the public directory will anyway hit your Rails app. * `config.session_store` is usually set up in `config/initializers/session_store.rb` and specifies what class to use to store the session. Possible values are `:cookie_store` which is the default, `:mem_cache_store`, and `:disabled`. The last one tells Rails not to deal with sessions. Custom session stores can also be specified: @@ -662,7 +662,7 @@ Below is a comprehensive list of all the initializers found in Rails in the orde * `initialize_cache` If `Rails.cache` isn't set yet, initializes the cache by referencing the value in `config.cache_store` and stores the outcome as `Rails.cache`. If this object responds to the `middleware` method, its middleware is inserted before `Rack::Runtime` in the middleware stack. -* `set_clear_dependencies_hook` Provides a hook for `active_record.set_dispatch_hooks` to use, which will run before this initializer. This initializer — which runs only if `cache_classes` is set to `false` — uses `ActionDispatch::Callbacks.after` to remove the constants which have been referenced during the request from the object space so that they will be reloaded during the following request. +* `set_clear_dependencies_hook` Provides a hook for `active_record.set_dispatch_hooks` to use, which will run before this initializer. This initializer - which runs only if `cache_classes` is set to `false` - uses `ActionDispatch::Callbacks.after` to remove the constants which have been referenced during the request from the object space so that they will be reloaded during the following request. * `initialize_dependency_mechanism` If `config.cache_classes` is true, configures `ActiveSupport::Dependencies.mechanism` to `require` dependencies rather than `load` them. @@ -673,7 +673,7 @@ Below is a comprehensive list of all the initializers found in Rails in the orde * `active_support.initialize_whiny_nils` Requires `active_support/whiny_nil` if `config.whiny_nils` is true. This file will output errors such as: ``` - Called id for nil, which would mistakenly be 4 — if you really wanted the id of nil, use object_id + Called id for nil, which would mistakenly be 4 - if you really wanted the id of nil, use object_id ``` And: @@ -694,9 +694,9 @@ Below is a comprehensive list of all the initializers found in Rails in the orde * `action_view.set_configs` Sets up Action View by using the settings in `config.action_view` by `send`'ing the method names as setters to `ActionView::Base` and passing the values through. -* `action_controller.logger` Sets `ActionController::Base.logger` — if it's not already set — to `Rails.logger`. +* `action_controller.logger` Sets `ActionController::Base.logger` - if it's not already set - to `Rails.logger`. -* `action_controller.initialize_framework_caches` Sets `ActionController::Base.cache_store` — if it's not already set — to `Rails.cache`. +* `action_controller.initialize_framework_caches` Sets `ActionController::Base.cache_store` - if it's not already set - to `Rails.cache`. * `action_controller.set_configs` Sets up Action Controller by using the settings in `config.action_controller` by `send`'ing the method names as setters to `ActionController::Base` and passing the values through. @@ -704,7 +704,7 @@ Below is a comprehensive list of all the initializers found in Rails in the orde * `active_record.initialize_timezone` Sets `ActiveRecord::Base.time_zone_aware_attributes` to true, as well as setting `ActiveRecord::Base.default_timezone` to UTC. When attributes are read from the database, they will be converted into the time zone specified by `Time.zone`. -* `active_record.logger` Sets `ActiveRecord::Base.logger` — if it's not already set — to `Rails.logger`. +* `active_record.logger` Sets `ActiveRecord::Base.logger` - if it's not already set - to `Rails.logger`. * `active_record.set_configs` Sets up Active Record by using the settings in `config.active_record` by `send`'ing the method names as setters to `ActiveRecord::Base` and passing the values through. @@ -714,7 +714,7 @@ Below is a comprehensive list of all the initializers found in Rails in the orde * `active_record.set_dispatch_hooks` Resets all reloadable connections to the database if `config.cache_classes` is set to `false`. -* `action_mailer.logger` Sets `ActionMailer::Base.logger` — if it's not already set — to `Rails.logger`. +* `action_mailer.logger` Sets `ActionMailer::Base.logger` - if it's not already set - to `Rails.logger`. * `action_mailer.set_configs` Sets up Action Mailer by using the settings in `config.action_mailer` by `send`'ing the method names as setters to `ActionMailer::Base` and passing the values through. diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index e3d1165604..fa3a5958f6 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -11,7 +11,7 @@ After reading this guide, you will know: * How to contribute to the Ruby on Rails documentation. * How to contribute to the Ruby on Rails code. -Ruby on Rails is not "someone else's framework." Over the years, hundreds of people have contributed to Ruby on Rails ranging from a single character to massive architectural changes or significant documentation — all with the goal of making Ruby on Rails better for everyone. Even if you don't feel up to writing code or documentation yet, there are a variety of other ways that you can contribute, from reporting issues to testing patches. +Ruby on Rails is not "someone else's framework." Over the years, hundreds of people have contributed to Ruby on Rails ranging from a single character to massive architectural changes or significant documentation - all with the goal of making Ruby on Rails better for everyone. Even if you don't feel up to writing code or documentation yet, there are a variety of other ways that you can contribute, from reporting issues to testing patches. -------------------------------------------------------------------------------- @@ -26,7 +26,7 @@ NOTE: Bugs in the most recent released version of Ruby on Rails are likely to ge If you've found a problem in Ruby on Rails which is not a security risk, do a search in GitHub under [Issues](https://github.com/rails/rails/issues) in case it was already reported. If you find no issue addressing it you can [add a new one](https://github.com/rails/rails/issues/new). (See the next section for reporting security issues.) -At the minimum, your issue report needs a title and descriptive text. But that's only a minimum. You should include as much relevant information as possible. You need at least to post the code sample that has the issue. Even better is to include a unit test that shows how the expected behavior is not occurring. Your goal should be to make it easy for yourself — and others — to replicate the bug and figure out a fix. +At the minimum, your issue report needs a title and descriptive text. But that's only a minimum. You should include as much relevant information as possible. You need at least to post the code sample that has the issue. Even better is to include a unit test that shows how the expected behavior is not occurring. Your goal should be to make it easy for yourself - and others - to replicate the bug and figure out a fix. Then, don't get your hopes up! Unless you have a "Code Red, Mission Critical, the World is Coming to an End" kind of bug, you're creating this issue report in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the issue report will automatically see any activity or that others will jump to fix it. Creating an issue like this is mostly to help yourself start on the path of fixing the problem and for others to confirm it with an "I'm having this problem too" comment. @@ -174,7 +174,7 @@ After applying their branch, test it out! Here are some things to think about: Once you're happy that the pull request contains a good change, comment on the GitHub issue indicating your approval. Your comment should indicate that you like the change and what you like about it. Something like:

-I like the way you've restructured that code in generate_finder_sql — much nicer. The tests look good too. +I like the way you've restructured that code in generate_finder_sql - much nicer. The tests look good too.
If your comment simply says "+1", then odds are that other reviewers aren't going to take it too seriously. Show that you took the time to review the pull request. @@ -222,11 +222,11 @@ $ cd rails $ git checkout -b my_new_branch ``` -It doesn’t matter much what name you use, because this branch will only exist on your local computer and your personal repository on GitHub. It won't be part of the Rails Git repository. +It doesn't matter much what name you use, because this branch will only exist on your local computer and your personal repository on GitHub. It won't be part of the Rails Git repository. ### Write Your Code -Now get busy and add or edit code. You’re on your branch now, so you can write whatever you want (you can check to make sure you’re on the right branch with `git branch -a`). But if you’re planning to submit your change back for inclusion in Rails, keep a few things in mind: +Now get busy and add or edit code. You're on your branch now, so you can write whatever you want (you can check to make sure you're on the right branch with `git branch -a`). But if you're planning to submit your change back for inclusion in Rails, keep a few things in mind: * Get the code right. * Use Rails idioms and helpers. @@ -262,7 +262,7 @@ Rails follows a simple set of coding style conventions: * Prefer `method { do_stuff }` instead of `method{do_stuff}` for single-line blocks. * Follow the conventions in the source you see used already. -The above are guidelines — please use your best judgment in using them. +The above are guidelines - please use your best judgment in using them. ### Updating the CHANGELOG @@ -291,7 +291,7 @@ Your name can be added directly after the last word if you don't provide any cod ### Sanity Check -You should not be the only person who looks at the code before you submit it. You know at least one other Rails developer, right? Show them what you’re doing and ask for feedback. Doing this in private before you push a patch out publicly is the “smoke test” for a patch: if you can’t convince one other developer of the beauty of your code, you’re unlikely to convince the core team either. +You should not be the only person who looks at the code before you submit it. You know at least one other Rails developer, right? Show them what you're doing and ask for feedback. Doing this in private before you push a patch out publicly is the "smoke test" for a patch: if you can't convince one other developer of the beauty of your code, you're unlikely to convince the core team either. ### Commit Your Changes @@ -335,7 +335,7 @@ TIP. Please squash your commits into a single commit when appropriate. This simp ### Update Your Branch -It’s pretty likely that other changes to master have happened while you were working. Go get them: +It's pretty likely that other changes to master have happened while you were working. Go get them: ```bash $ git checkout master @@ -419,7 +419,7 @@ Now you need to get other people to look at your patch, just as you've looked at ### Iterate as Necessary -It’s entirely possible that the feedback you get will suggest changes. Don’t get discouraged: the whole point of contributing to an active open source project is to tap into community knowledge. If people are encouraging you to tweak your code, then it’s worth making the tweaks and resubmitting. If the feedback is that your code doesn’t belong in the core, you might still think about releasing it as a gem. +It's entirely possible that the feedback you get will suggest changes. Don't get discouraged: the whole point of contributing to an active open source project is to tap into community knowledge. If people are encouraging you to tweak your code, then it's worth making the tweaks and resubmitting. If the feedback is that your code doesn't belong in the core, you might still think about releasing it as a gem. #### Squashing commits diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md index 50ee934b87..14d65e4747 100644 --- a/guides/source/debugging_rails_applications.md +++ b/guides/source/debugging_rails_applications.md @@ -198,7 +198,7 @@ Adding extra logging like this makes it easy to search for unexpected or unusual ### Tagged Logging -When running multi-user, multi-account applications, it’s often useful +When running multi-user, multi-account applications, it's often useful to be able to filter the logs using some custom rules. `TaggedLogging` in Active Support helps in doing exactly that by stamping log lines with subdomains, request ids, and anything else to aid debugging such applications. diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index 7e61c78ed9..12b192fa87 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -74,7 +74,7 @@ ports. If you have any problems with these libraries, you can install them manually by compiling the source code. Just follow the instructions at the [Red Hat/CentOS section of the Nokogiri tutorials](http://nokogiri.org/tutorials/installing_nokogiri.html#red_hat__centos) . -Also, SQLite3 and its development files for the `sqlite3-ruby` gem — in Ubuntu you're done with just +Also, SQLite3 and its development files for the `sqlite3-ruby` gem - in Ubuntu you're done with just ```bash $ sudo apt-get install sqlite3 libsqlite3-dev @@ -272,4 +272,4 @@ NOTE: Using the rake task to create the test databases ensures they have the cor NOTE: You'll see the following warning (or localized warning) during activating HStore extension in PostgreSQL 9.1.x or earlier: "WARNING: => is deprecated as an operator". -If you’re using another database, check the file `activerecord/test/config.yml` or `activerecord/test/config.example.yml` for default connection information. You can edit `activerecord/test/config.yml` to provide different credentials on your machine if you must, but obviously you should not push any such changes back to Rails. +If you're using another database, check the file `activerecord/test/config.yml` or `activerecord/test/config.example.yml` for default connection information. You can edit `activerecord/test/config.yml` to provide different credentials on your machine if you must, but obviously you should not push any such changes back to Rails. diff --git a/guides/source/engines.md b/guides/source/engines.md index 7a125fd341..bc404ccb7f 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -579,7 +579,7 @@ Run this migration using this command: $ rake db:migrate ``` -Now with all the pieces in place, an action will take place that will associate an author — represented by a record in the `users` table — with a post, represented by the `blorgh_posts` table from the engine. +Now with all the pieces in place, an action will take place that will associate an author - represented by a record in the `users` table - with a post, represented by the `blorgh_posts` table from the engine. Finally, the author's name should be displayed on the post's page. Add this code above the "Title" output inside `app/views/blorgh/posts/show.html.erb`: @@ -689,8 +689,8 @@ There are now no strict dependencies on what the class is, only what the API for Within an engine, there may come a time where you wish to use things such as initializers, internationalization or other configuration options. The great news is that these things are entirely possible because a Rails engine shares much the same functionality as a Rails application. In fact, a Rails application's functionality is actually a superset of what is provided by engines! -If you wish to use an initializer — code that should run before the engine is -loaded — the place for it is the `config/initializers` folder. This directory's +If you wish to use an initializer - code that should run before the engine is +loaded - the place for it is the `config/initializers` folder. This directory's functionality is explained in the [Initializers section](configuring.html#initializers) of the Configuring guide, and works precisely the same way as the `config/initializers` directory inside @@ -707,7 +707,7 @@ The `test` directory should be treated like a typical Rails testing environment, ### Functional tests -A matter worth taking into consideration when writing functional tests is that the tests are going to be running on an application — the `test/dummy` application — rather than your engine. This is due to the setup of the testing environment; an engine needs an application as a host for testing its main functionality, especially controllers. This means that if you were to make a typical `GET` to a controller in a controller's functional test like this: +A matter worth taking into consideration when writing functional tests is that the tests are going to be running on an application - the `test/dummy` application - rather than your engine. This is due to the setup of the testing environment; an engine needs an application as a host for testing its main functionality, especially controllers. This means that if you were to make a typical `GET` to a controller in a controller's functional test like this: ```ruby get :index diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md index 3a18fb81d8..578cfbe105 100644 --- a/guides/source/form_helpers.md +++ b/guides/source/form_helpers.md @@ -290,7 +290,7 @@ The object yielded by `fields_for` is a form builder like the one yielded by `fo ### Relying on Record Identification -The Article model is directly available to users of the application, so — following the best practices for developing with Rails — you should declare it **a resource**: +The Article model is directly available to users of the application, so - following the best practices for developing with Rails - you should declare it **a resource**: ```ruby resources :articles @@ -381,7 +381,7 @@ Here you have a list of cities whose names are presented to the user. Internally ### The Select and Option Tags -The most generic helper is `select_tag`, which — as the name implies — simply generates the `SELECT` tag that encapsulates an options string: +The most generic helper is `select_tag`, which - as the name implies - simply generates the `SELECT` tag that encapsulates an options string: ```erb <%= select_tag(:city_id, '...') %> @@ -421,7 +421,7 @@ output: Whenever Rails sees that the internal value of an option being generated matches this value, it will add the `selected` attribute to that option. -TIP: The second argument to `options_for_select` must be exactly equal to the desired internal value. In particular if the value is the integer 2 you cannot pass "2" to `options_for_select` — you must pass 2. Be aware of values extracted from the `params` hash as they are all strings. +TIP: The second argument to `options_for_select` must be exactly equal to the desired internal value. In particular if the value is the integer 2 you cannot pass "2" to `options_for_select` - you must pass 2. Be aware of values extracted from the `params` hash as they are all strings. WARNING: when `:include_blank` or `:prompt` are not present, `:include_blank` is forced true if the select attribute `required` is true, display `size` is one and `multiple` is not true. @@ -451,7 +451,7 @@ In most cases form controls will be tied to a specific database model and as you <%= select(:person, :city_id, [['Lisbon', 1], ['Madrid', 2], ...]) %> ``` -Notice that the third parameter, the options array, is the same kind of argument you pass to `options_for_select`. One advantage here is that you don't have to worry about pre-selecting the correct city if the user already has one — Rails will do this for you by reading from the `@person.city_id` attribute. +Notice that the third parameter, the options array, is the same kind of argument you pass to `options_for_select`. One advantage here is that you don't have to worry about pre-selecting the correct city if the user already has one - Rails will do this for you by reading from the `@person.city_id` attribute. As with other helpers, if you were to use the `select` helper on a form builder scoped to the `@person` object, the syntax would be: @@ -664,7 +664,7 @@ Understanding Parameter Naming Conventions As you've seen in the previous sections, values from forms can be at the top level of the `params` hash or nested in another hash. For example in a standard `create` action for a Person model, `params[:person]` would usually be a hash of all the attributes for the person to create. The `params` hash can also contain arrays, arrays of hashes and so on. -Fundamentally HTML forms don't know about any sort of structured data, all they generate is name–value pairs, where pairs are just plain strings. The arrays and hashes you see in your application are the result of some parameter naming conventions that Rails uses. +Fundamentally HTML forms don't know about any sort of structured data, all they generate is name-value pairs, where pairs are just plain strings. The arrays and hashes you see in your application are the result of some parameter naming conventions that Rails uses. TIP: You may find you can try out examples in this section faster by using the console to directly invoke Racks' parameter parser. For example, diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 021aa070fb..5b1758a771 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -169,7 +169,7 @@ This will fire up WEBrick, a webserver built into Ruby by default. To see your a TIP: To stop the web server, hit Ctrl+C in the terminal window where it's running. To verify the server has stopped you should see your command prompt cursor again. For most UNIX-like systems including Mac OS X this will be a dollar sign `$`. In development mode, Rails does not generally require you to restart the server; changes you make in files will be automatically picked up by the server. -The "Welcome Aboard" page is the _smoke test_ for a new Rails application: it makes sure that you have your software configured correctly enough to serve a page. You can also click on the _About your application’s environment_ link to see a summary of your application's environment. +The "Welcome Aboard" page is the _smoke test_ for a new Rails application: it makes sure that you have your software configured correctly enough to serve a page. You can also click on the _About your application's environment_ link to see a summary of your application's environment. ### Say "Hello", Rails @@ -343,7 +343,7 @@ That's quite a lot of text! Let's quickly go through and understand what each pa The first part identifies what template is missing. In this case, it's the `posts/new` template. Rails will first look for this template. If not found, then it will attempt to load a template called `application/new`. It looks for one here because the `PostsController` inherits from `ApplicationController`. -The next part of the message contains a hash. The `:locale` key in this hash simply indicates what spoken language template should be retrieved. By default, this is the English — or "en" — template. The next key, `:formats` specifies the format of template to be served in response. The default format is `:html`, and so Rails is looking for an HTML template. The final key, `:handlers`, is telling us what _template handlers_ could be used to render our template. `:erb` is most commonly used for HTML templates, `:builder` is used for XML templates, and `:coffee` uses CoffeeScript to build JavaScript templates. +The next part of the message contains a hash. The `:locale` key in this hash simply indicates what spoken language template should be retrieved. By default, this is the English - or "en" - template. The next key, `:formats` specifies the format of template to be served in response. The default format is `:html`, and so Rails is looking for an HTML template. The final key, `:handlers`, is telling us what _template handlers_ could be used to render our template. `:erb` is most commonly used for HTML templates, `:builder` is used for XML templates, and `:coffee` uses CoffeeScript to build JavaScript templates. The final part of this message tells us where Rails has looked for the templates. Templates within a basic Rails application like this are kept in a single location, but in more complex applications it could be many different paths. @@ -386,7 +386,7 @@ If you refresh the page now, you'll see the exact same form as in the example. B When you call `form_for`, you pass it an identifying object for this form. In this case, it's the symbol `:post`. This tells the `form_for` helper what this form is for. Inside the block for this method, the -`FormBuilder` object — represented by `f` — is used to build two labels and two text fields, one each for the title and text of a post. Finally, a call to `submit` on the `f` object will create a submit button for the form. +`FormBuilder` object - represented by `f` - is used to build two labels and two text fields, one each for the title and text of a post. Finally, a call to `submit` on the `f` object will create a submit button for the form. There's one problem with this form though. If you inspect the HTML that is generated, by viewing the source of the page, you will see that the `action` attribute for the form is pointing at `/posts/new`. This is a problem because this route goes to the very page that you're on right at the moment, and that route should only be used to display the form for a new post. @@ -717,7 +717,7 @@ Let's add links to the other views as well, starting with adding this "New Post" <%= link_to 'New post', new_post_path %> ``` -This link will allow you to bring up the form that lets you create a new post. You should also add a link to this template — `app/views/posts/new.html.erb` — to go back to the `index` action. Do this by adding this underneath the form in this template: +This link will allow you to bring up the form that lets you create a new post. You should also add a link to this template - `app/views/posts/new.html.erb` - to go back to the `index` action. Do this by adding this underneath the form in this template: ```erb <%= form_for :post do |f| %> diff --git a/guides/source/i18n.md b/guides/source/i18n.md index e4214fd74e..ead9c6b94d 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -13,8 +13,8 @@ So, in the process of _internationalizing_ your Rails application you have to: In the process of _localizing_ your application you'll probably want to do the following three things: -* Replace or supplement Rails' default locale — e.g. date and time formats, month names, Active Record model names, etc. -* Abstract strings in your application into keyed dictionaries — e.g. flash messages, static text in your views, etc. +* Replace or supplement Rails' default locale - e.g. date and time formats, month names, Active Record model names, etc. +* Abstract strings in your application into keyed dictionaries - e.g. flash messages, static text in your views, etc. * Store the resulting dictionaries somewhere. This guide will walk you through the I18n API and contains a tutorial on how to internationalize a Rails application from the start. @@ -38,13 +38,13 @@ Internationalization is a complex problem. Natural languages differ in so many w * providing support for English and similar languages out of the box * making it easy to customize and extend everything for other languages -As part of this solution, **every static string in the Rails framework** — e.g. Active Record validation messages, time and date formats — **has been internationalized**, so _localization_ of a Rails application means "over-riding" these defaults. +As part of this solution, **every static string in the Rails framework** - e.g. Active Record validation messages, time and date formats - **has been internationalized**, so _localization_ of a Rails application means "over-riding" these defaults. ### The Overall Architecture of the Library Thus, the Ruby I18n gem is split into two parts: -* The public API of the i18n framework — a Ruby module with public methods that define how the library works +* The public API of the i18n framework - a Ruby module with public methods that define how the library works * A default backend (which is intentionally named _Simple_ backend) that implements these methods As a user you should always only access the public methods on the I18n module, but it is useful to know about the capabilities of the backend. @@ -267,7 +267,7 @@ NOTE: Have a look at two plugins which simplify work with routes in this way: Sv ### Setting the Locale from the Client Supplied Information -In specific cases, it would make sense to set the locale from client-supplied information, i.e. not from the URL. This information may come for example from the users' preferred language (set in their browser), can be based on the users' geographical location inferred from their IP, or users can provide it simply by choosing the locale in your application interface and saving it to their profile. This approach is more suitable for web-based applications or services, not for websites — see the box about _sessions_, _cookies_ and RESTful architecture above. +In specific cases, it would make sense to set the locale from client-supplied information, i.e. not from the URL. This information may come for example from the users' preferred language (set in their browser), can be based on the users' geographical location inferred from their IP, or users can provide it simply by choosing the locale in your application interface and saving it to their profile. This approach is more suitable for web-based applications or services, not for websites - see the box about _sessions_, _cookies_ and RESTful architecture above. #### Using `Accept-Language` @@ -292,11 +292,11 @@ Of course, in a production environment you would need much more robust code, and #### Using GeoIP (or Similar) Database -Another way of choosing the locale from client information would be to use a database for mapping the client IP to the region, such as [GeoIP Lite Country](http://www.maxmind.com/app/geolitecountry). The mechanics of the code would be very similar to the code above — you would need to query the database for the user's IP, and look up your preferred locale for the country/region/city returned. +Another way of choosing the locale from client information would be to use a database for mapping the client IP to the region, such as [GeoIP Lite Country](http://www.maxmind.com/app/geolitecountry). The mechanics of the code would be very similar to the code above - you would need to query the database for the user's IP, and look up your preferred locale for the country/region/city returned. #### User Profile -You can also provide users of your application with means to set (and possibly over-ride) the locale in your application interface, as well. Again, mechanics for this approach would be very similar to the code above — you'd probably let users choose a locale from a dropdown list and save it to their profile in the database. Then you'd set the locale to this value. +You can also provide users of your application with means to set (and possibly over-ride) the locale in your application interface, as well. Again, mechanics for this approach would be very similar to the code above - you'd probably let users choose a locale from a dropdown list and save it to their profile in the database. Then you'd set the locale to this value. Internationalizing your Application ----------------------------------- @@ -399,7 +399,7 @@ en: ### Adding Date/Time Formats -OK! Now let's add a timestamp to the view, so we can demo the **date/time localization** feature as well. To localize the time format you pass the Time object to `I18n.l` or (preferably) use Rails' `#l` helper. You can pick a format by passing the `:format` option — by default the `:default` format is used. +OK! Now let's add a timestamp to the view, so we can demo the **date/time localization** feature as well. To localize the time format you pass the Time object to `I18n.l` or (preferably) use Rails' `#l` helper. You can pick a format by passing the `:format` option - by default the `:default` format is used. ```erb # app/views/home/index.html.erb @@ -499,7 +499,7 @@ I18n.t :message I18n.t 'message' ``` -The `translate` method also takes a `:scope` option which can contain one or more additional keys that will be used to specify a “namespace” or scope for a translation key: +The `translate` method also takes a `:scope` option which can contain one or more additional keys that will be used to specify a "namespace" or scope for a translation key: ```ruby I18n.t :record_invalid, scope: [:activerecord, :errors, :messages] @@ -933,7 +933,7 @@ ReservedInterpolationKey # the translation contains a reserved interpolation UnknownFileType # the backend does not know how to handle a file type that was added to I18n.load_path ``` -The I18n API will catch all of these exceptions when they are thrown in the backend and pass them to the default_exception_handler method. This method will re-raise all exceptions except for `MissingTranslationData` exceptions. When a `MissingTranslationData` exception has been caught, it will return the exception’s error message string containing the missing key/scope. +The I18n API will catch all of these exceptions when they are thrown in the backend and pass them to the default_exception_handler method. This method will re-raise all exceptions except for `MissingTranslationData` exceptions. When a `MissingTranslationData` exception has been caught, it will return the exception's error message string containing the missing key/scope. The reason for this is that during development you'd usually want your views to still render even though a translation is missing. diff --git a/guides/source/nested_model_forms.md b/guides/source/nested_model_forms.md index b90b3bb5fc..855fab18e3 100644 --- a/guides/source/nested_model_forms.md +++ b/guides/source/nested_model_forms.md @@ -9,7 +9,7 @@ After reading this guide, you will know: -------------------------------------------------------------------------------- -NOTE: This guide assumes the user knows how to use the [Rails form helpers](form_helpers.html) in general. Also, it’s **not** an API reference. For a complete reference please visit [the Rails API documentation](http://api.rubyonrails.org/). +NOTE: This guide assumes the user knows how to use the [Rails form helpers](form_helpers.html) in general. Also, it's **not** an API reference. For a complete reference please visit [the Rails API documentation](http://api.rubyonrails.org/). Model setup @@ -56,7 +56,7 @@ end ### Custom model -As you might have inflected from this explanation, you _don’t_ necessarily need an ActiveRecord::Base model to use this functionality. The following examples are sufficient to enable the nested model form behavior: +As you might have inflected from this explanation, you _don't_ necessarily need an ActiveRecord::Base model to use this functionality. The following examples are sufficient to enable the nested model form behavior: #### Single associated object @@ -177,7 +177,7 @@ When this form is posted the Rails parameter parser will construct a hash like t } ``` -That’s it. The controller will simply pass this hash on to the model from the `create` action. The model will then handle building the `address` association for you and automatically save it when the parent (`person`) is saved. +That's it. The controller will simply pass this hash on to the model from the `create` action. The model will then handle building the `address` association for you and automatically save it when the parent (`person`) is saved. #### Nested form for a collection of associated objects diff --git a/guides/source/plugins.md b/guides/source/plugins.md index 9077e424c8..b52504b104 100644 --- a/guides/source/plugins.md +++ b/guides/source/plugins.md @@ -5,7 +5,7 @@ A Rails plugin is either an extension or a modification of the core framework. P * a way for developers to share bleeding-edge ideas without hurting the stable code base * a segmented architecture so that units of code can be fixed or updated on their own release schedule -* an outlet for the core developers so that they don’t have to include every cool new feature under the sun +* an outlet for the core developers so that they don't have to include every cool new feature under the sun After reading this guide, you will know: diff --git a/guides/source/rails_application_templates.md b/guides/source/rails_application_templates.md index 0c70f379be..711d910184 100644 --- a/guides/source/rails_application_templates.md +++ b/guides/source/rails_application_templates.md @@ -47,7 +47,7 @@ The following sections outline the primary methods provided by the API: ### gem(*args) -Adds a `gem` entry for the supplied gem to the generated application’s `Gemfile`. +Adds a `gem` entry for the supplied gem to the generated application's `Gemfile`. For example, if your application depends on the gems `bj` and `nokogiri`: @@ -98,7 +98,7 @@ A block can be used in place of the `data` argument. ### vendor/lib/file/initializer(filename, data = nil, &block) -Adds an initializer to the generated application’s `config/initializers` directory. +Adds an initializer to the generated application's `config/initializers` directory. Let's say you like using `Object#not_nil?` and `Object#not_blank?`: @@ -127,7 +127,7 @@ file 'app/components/foo.rb', <<-CODE CODE ``` -That’ll create the `app/components` directory and put `foo.rb` in there. +That'll create the `app/components` directory and put `foo.rb` in there. ### rakefile(filename, data = nil, &block) @@ -197,7 +197,7 @@ end ### ask(question) -`ask()` gives you a chance to get some feedback from the user and use it in your templates. Let's say you want your user to name the new shiny library you’re adding: +`ask()` gives you a chance to get some feedback from the user and use it in your templates. Let's say you want your user to name the new shiny library you're adding: ```ruby lib_name = ask("What do you want to call the shiny library ?") @@ -211,7 +211,7 @@ CODE ### yes?(question) or no?(question) -These methods let you ask questions from templates and decide the flow based on the user’s answer. Let's say you want to freeze rails only if the user wants to: +These methods let you ask questions from templates and decide the flow based on the user's answer. Let's say you want to freeze rails only if the user wants to: ```ruby rake("rails:freeze:gems") if yes?("Freeze rails gems?") diff --git a/guides/source/security.md b/guides/source/security.md index e4db26c64e..97b7355771 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -58,7 +58,7 @@ WARNING: _Stealing a user's session id lets an attacker use the web application Many web applications have an authentication system: a user provides a user name and password, the web application checks them and stores the corresponding user id in the session hash. From now on, the session is valid. On every request the application will load the user, identified by the user id in the session, without the need for new authentication. The session id in the cookie identifies the session. -Hence, the cookie serves as temporary authentication for the web application. Anyone who seizes a cookie from someone else, may use the web application as this user – with possibly severe consequences. Here are some ways to hijack a session, and their countermeasures: +Hence, the cookie serves as temporary authentication for the web application. Anyone who seizes a cookie from someone else, may use the web application as this user - with possibly severe consequences. Here are some ways to hijack a session, and their countermeasures: * Sniff the cookie in an insecure network. A wireless LAN can be an example of such a network. In an unencrypted wireless LAN it is especially easy to listen to the traffic of all connected clients. This is one more reason not to work from a coffee shop. For the web application builder this means to _provide a secure connection over SSL_. In Rails 3.1 and later, this could be accomplished by always forcing SSL connection in your application config file: @@ -72,7 +72,7 @@ Hence, the cookie serves as temporary authentication for the web application. An * Instead of stealing a cookie unknown to the attacker, he fixes a user's session identifier (in the cookie) known to him. Read more about this so-called session fixation later. -The main objective of most attackers is to make money. The underground prices for stolen bank login accounts range from $10–$1000 (depending on the available amount of funds), $0.40–$20 for credit card numbers, $1–$8 for online auction site accounts and $4–$30 for email passwords, according to the [Symantec Global Internet Security Threat Report](http://eval.symantec.com/mktginfo/enterprise/white_papers/b-whitepaper_internet_security_threat_report_xiii_04-2008.en-us.pdf). +The main objective of most attackers is to make money. The underground prices for stolen bank login accounts range from $10-$1000 (depending on the available amount of funds), $0.40-$20 for credit card numbers, $1-$8 for online auction site accounts and $4-$30 for email passwords, according to the [Symantec Global Internet Security Threat Report](http://eval.symantec.com/mktginfo/enterprise/white_papers/b-whitepaper_internet_security_threat_report_xiii_04-2008.en-us.pdf). ### Session Guidelines @@ -134,7 +134,7 @@ This attack focuses on fixing a user's session id known to the attacker, and for * As the new trap session is unused, the web application will require the user to authenticate. * From now on, the victim and the attacker will co-use the web application with the same session: The session became valid and the victim didn't notice the attack. -### Session Fixation – Countermeasures +### Session Fixation - Countermeasures TIP: _One line of code will protect you from session fixation._ @@ -187,11 +187,11 @@ In the session chapter you have learned that most Rails * Bob's session at www.webapp.com is still alive, because he didn't log out a few minutes ago. * By viewing the post, the browser finds an image tag. It tries to load the suspected image from www.webapp.com. As explained before, it will also send along the cookie with the valid session id. * The web application at www.webapp.com verifies the user information in the corresponding session hash and destroys the project with the ID 1. It then returns a result page which is an unexpected result for the browser, so it will not display the image. -* Bob doesn't notice the attack — but a few days later he finds out that project number one is gone. +* Bob doesn't notice the attack - but a few days later he finds out that project number one is gone. -It is important to notice that the actual crafted image or link doesn't necessarily have to be situated in the web application's domain, it can be anywhere – in a forum, blog post or email. +It is important to notice that the actual crafted image or link doesn't necessarily have to be situated in the web application's domain, it can be anywhere - in a forum, blog post or email. -CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) — less than 0.1% in 2006 — but it really is a 'sleeping giant' [Grossman]. This is in stark contrast to the results in my (and others) security contract work – _CSRF is an important security issue_. +CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) - less than 0.1% in 2006 - but it really is a 'sleeping giant' [Grossman]. This is in stark contrast to the results in my (and others) security contract work - _CSRF is an important security issue_. ### CSRF Countermeasures @@ -288,9 +288,9 @@ This example is a Base64 encoded JavaScript which displays a simple message box. NOTE: _Make sure file uploads don't overwrite important files, and process media files asynchronously._ -Many web applications allow users to upload files. _File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like “../../../etc/passwd”, it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so – one more reason to run web servers, database servers and other programs as a less privileged Unix user. +Many web applications allow users to upload files. _File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like "../../../etc/passwd", it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so - one more reason to run web servers, database servers and other programs as a less privileged Unix user. -When filtering user input file names, _don't try to remove malicious parts_. Think of a situation where the web application removes all “../” in a file name and an attacker uses a string such as “....//” - the result will be “../”. It is best to use a whitelist approach, which _checks for the validity of a file name with a set of accepted characters_. This is opposed to a blacklist approach which attempts to remove not allowed characters. In case it isn't a valid file name, reject it (or replace not accepted characters), but don't remove them. Here is the file name sanitizer from the [attachment_fu plugin](https://github.com/technoweenie/attachment_fu/tree/master:) +When filtering user input file names, _don't try to remove malicious parts_. Think of a situation where the web application removes all "../" in a file name and an attacker uses a string such as "....//" - the result will be "../". It is best to use a whitelist approach, which _checks for the validity of a file name with a set of accepted characters_. This is opposed to a blacklist approach which attempts to remove not allowed characters. In case it isn't a valid file name, reject it (or replace not accepted characters), but don't remove them. Here is the file name sanitizer from the [attachment_fu plugin](https://github.com/technoweenie/attachment_fu/tree/master:) ```ruby def sanitize_filename(filename) @@ -313,7 +313,7 @@ The solution to this is best to _process media files asynchronously_: Save the m WARNING: _Source code in uploaded files may be executed when placed in specific directories. Do not place file uploads in Rails' /public directory if it is Apache's home directory._ -The popular Apache web server has an option called DocumentRoot. This is the home directory of the web site, everything in this directory tree will be served by the web server. If there are files with a certain file name extension, the code in it will be executed when requested (might require some options to be set). Examples for this are PHP and CGI files. Now think of a situation where an attacker uploads a file “file.cgi” with code in it, which will be executed when someone downloads the file. +The popular Apache web server has an option called DocumentRoot. This is the home directory of the web site, everything in this directory tree will be served by the web server. If there are files with a certain file name extension, the code in it will be executed when requested (might require some options to be set). Examples for this are PHP and CGI files. Now think of a situation where an attacker uploads a file "file.cgi" with code in it, which will be executed when someone downloads the file. _If your Apache DocumentRoot points to Rails' /public directory, do not put file uploads in it_, store files at least one level downwards. @@ -327,7 +327,7 @@ Just as you have to filter file names for uploads, you have to do so for downloa send_file('/var/www/uploads/' + params[:filename]) ``` -Simply pass a file name like “../../../etc/passwd” to download the server's login information. A simple solution against this, is to _check that the requested file is in the expected directory_: +Simply pass a file name like "../../../etc/passwd" to download the server's login information. A simple solution against this, is to _check that the requested file is in the expected directory_: ```ruby basename = File.expand_path(File.join(File.dirname(__FILE__), '../../files')) @@ -406,7 +406,7 @@ NOTE: _Brute-force attacks on accounts are trial and error attacks on the login A list of user names for your web application may be misused to brute-force the corresponding passwords, because most people don't use sophisticated passwords. Most passwords are a combination of dictionary words and possibly numbers. So armed with a list of user names and a dictionary, an automatic program may find the correct password in a matter of minutes. -Because of this, most web applications will display a generic error message “user name or password not correct”, if one of these are not correct. If it said “the user name you entered has not been found”, an attacker could automatically compile a list of user names. +Because of this, most web applications will display a generic error message "user name or password not correct", if one of these are not correct. If it said "the user name you entered has not been found", an attacker could automatically compile a list of user names. However, what most web application designers neglect, are the forgot-password pages. These pages often admit that the entered user name or e-mail address has (not) been found. This allows an attacker to compile a list of user names and brute-force the accounts. @@ -495,7 +495,7 @@ http://hi.com */ ``` -This URL passes the filter because the regular expression matches – the second line, the rest does not matter. Now imagine we had a view that showed the URL like this: +This URL passes the filter because the regular expression matches - the second line, the rest does not matter. Now imagine we had a view that showed the URL like this: ```ruby link_to "Homepage", @user.homepage @@ -646,7 +646,7 @@ INFO: _The most widespread, and one of the most devastating security vulnerabili An entry point is a vulnerable URL and its parameters where an attacker can start an attack. -The most common entry points are message posts, user comments, and guest books, but project titles, document names and search result pages have also been vulnerable - just about everywhere where the user can input data. But the input does not necessarily have to come from input boxes on web sites, it can be in any URL parameter – obvious, hidden or internal. Remember that the user may intercept any traffic. Applications, such as the [Live HTTP Headers Firefox plugin](http://livehttpheaders.mozdev.org/), or client-site proxies make it easy to change requests. +The most common entry points are message posts, user comments, and guest books, but project titles, document names and search result pages have also been vulnerable - just about everywhere where the user can input data. But the input does not necessarily have to come from input boxes on web sites, it can be in any URL parameter - obvious, hidden or internal. Remember that the user may intercept any traffic. Applications, such as the [Live HTTP Headers Firefox plugin](http://livehttpheaders.mozdev.org/), or client-site proxies make it easy to change requests. XSS attacks work like this: An attacker injects some code, the web application saves it and displays it on a page, later presented to a victim. Most XSS examples simply display an alert box, but it is more powerful than that. XSS can steal the cookie, hijack the session, redirect the victim to a fake website, display advertisements for the benefit of the attacker, change elements on the web site to get confidential information or install malicious software through security holes in the web browser. @@ -698,10 +698,10 @@ You can mitigate these attacks (in the obvious way) by adding the [httpOnly](htt With web page defacement an attacker can do a lot of things, for example, present false information or lure the victim on the attackers web site to steal the cookie, login credentials or other sensitive data. The most popular way is to include code from external sources by iframes: ```html - + ``` -This loads arbitrary HTML and/or JavaScript from an external source and embeds it as part of the site. This iframe is taken from an actual attack on legitimate Italian sites using the [Mpack attack framework](http://isc.sans.org/diary.html?storyid=3015). Mpack tries to install malicious software through security holes in the web browser – very successfully, 50% of the attacks succeed. +This loads arbitrary HTML and/or JavaScript from an external source and embeds it as part of the site. This iframe is taken from an actual attack on legitimate Italian sites using the [Mpack attack framework](http://isc.sans.org/diary.html?storyid=3015). Mpack tries to install malicious software through security holes in the web browser - very successfully, 50% of the attacks succeed. A more specialized attack could overlap the entire web site or display a login form, which looks the same as the site's original, but transmits the user name and password to the attacker's site. Or it could use CSS and/or JavaScript to hide a legitimate link in the web application, and display another one at its place which redirects to a fake web site. @@ -718,7 +718,7 @@ _It is very important to filter malicious input, but it is also important to esc Especially for XSS, it is important to do _whitelist input filtering instead of blacklist_. Whitelist filtering states the values allowed as opposed to the values not allowed. Blacklists are never complete. -Imagine a blacklist deletes “script” from the user input. Now the attacker injects “<scrscriptipt>”, and after the filter, “<script>” remains. Earlier versions of Rails used a blacklist approach for the strip_tags(), strip_links() and sanitize() method. So this kind of injection was possible: +Imagine a blacklist deletes "script" from the user input. Now the attacker injects "<scrscriptipt>", and after the filter, "<script>" remains. Earlier versions of Rails used a blacklist approach for the strip_tags(), strip_links() and sanitize() method. So this kind of injection was possible: ```ruby strip_tags("some<script>alert('hello')</script>") @@ -744,7 +744,7 @@ Network traffic is mostly based on the limited Western alphabet, so new characte lert('XSS')> ``` -This example pops up a message box. It will be recognized by the above sanitize() filter, though. A great tool to obfuscate and encode strings, and thus “get to know your enemy”, is the [Hackvertor](https://hackvertor.co.uk/public). Rails' sanitize() method does a good job to fend off encoding attacks. +This example pops up a message box. It will be recognized by the above sanitize() filter, though. A great tool to obfuscate and encode strings, and thus "get to know your enemy", is the [Hackvertor](https://hackvertor.co.uk/public). Rails' sanitize() method does a good job to fend off encoding attacks. #### Examples from the Underground @@ -762,7 +762,7 @@ The worms exploits a hole in Yahoo's HTML/JavaScript filter, which usually filte Another proof-of-concept webmail worm is Nduja, a cross-domain worm for four Italian webmail services. Find more details on [Rosario Valotta's paper](http://www.xssed.com/article/9/Paper_A_PoC_of_a_cross_webmail_worm_XWW_called_Njuda_connection/). Both webmail worms have the goal to harvest email addresses, something a criminal hacker could make money with. -In December 2006, 34,000 actual user names and passwords were stolen in a [MySpace phishing attack](http://news.netcraft.com/archives/2006/10/27/myspace_accounts_compromised_by_phishers.html). The idea of the attack was to create a profile page named “login_home_index_html”, so the URL looked very convincing. Specially-crafted HTML and CSS was used to hide the genuine MySpace content from the page and instead display its own login form. +In December 2006, 34,000 actual user names and passwords were stolen in a [MySpace phishing attack](http://news.netcraft.com/archives/2006/10/27/myspace_accounts_compromised_by_phishers.html). The idea of the attack was to create a profile page named "login_home_index_html", so the URL looked very convincing. Specially-crafted HTML and CSS was used to hide the genuine MySpace content from the page and instead display its own login form. The MySpace Samy worm will be discussed in the CSS Injection section. @@ -784,13 +784,13 @@ So the payload is in the style attribute. But there are no quotes allowed in the
``` -The eval() function is a nightmare for blacklist input filters, as it allows the style attribute to hide the word “innerHTML”: +The eval() function is a nightmare for blacklist input filters, as it allows the style attribute to hide the word "innerHTML": ``` alert(eval('document.body.inne' + 'rHTML')); ``` -The next problem was MySpace filtering the word “javascript”, so the author used “java<NEWLINE>script" to get around this: +The next problem was MySpace filtering the word "javascript", so the author used "java<NEWLINE>script" to get around this: ```html
@@ -837,7 +837,7 @@ It is recommended to _use RedCloth in combination with a whitelist input filter_ ### Ajax Injection -NOTE: _The same security precautions have to be taken for Ajax actions as for “normal” ones. There is at least one exception, however: The output has to be escaped in the controller already, if the action doesn't render a view._ +NOTE: _The same security precautions have to be taken for Ajax actions as for "normal" ones. There is at least one exception, however: The output has to be escaped in the controller already, if the action doesn't render a view._ If you use the [in_place_editor plugin](http://dev.rubyonrails.org/browser/plugins/in_place_editing), or actions that return a string, rather than rendering a view, _you have to escape the return value in the action_. Otherwise, if the return value contains a XSS string, the malicious code will be executed upon return to the browser. Escape any input value using the h() method. @@ -861,7 +861,7 @@ WARNING: _HTTP headers are dynamically generated and under certain circumstances HTTP request headers have a Referer, User-Agent (client software), and Cookie field, among others. Response headers for example have a status code, Cookie and Location (redirection target URL) field. All of them are user-supplied and may be manipulated with more or less effort. _Remember to escape these header fields, too._ For example when you display the user agent in an administration area. -Besides that, it is _important to know what you are doing when building response headers partly based on user input._ For example you want to redirect the user back to a specific page. To do that you introduced a “referer“ field in a form to redirect to the given address: +Besides that, it is _important to know what you are doing when building response headers partly based on user input._ For example you want to redirect the user back to a specific page. To do that you introduced a "referer" field in a form to redirect to the given address: ```ruby redirect_to params[:referer] diff --git a/guides/source/testing.md b/guides/source/testing.md index 0258202c18..1b0a0abf9a 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -912,7 +912,7 @@ Testing mailer classes requires some specific tools to do a thorough job. ### Keeping the Postman in Check -Your mailer classes — like every other part of your Rails application — should be tested to ensure that it is working as expected. +Your mailer classes - like every other part of your Rails application - should be tested to ensure that it is working as expected. The goals of testing your mailer classes are to ensure that: -- cgit v1.2.3 From 92b0ce942f995de0988b998d1780fb8844fda1c9 Mon Sep 17 00:00:00 2001 From: wangjohn Date: Fri, 23 Aug 2013 12:31:29 -0400 Subject: Deprecating passing strings as class name in fixtures. --- activerecord/lib/active_record/fixtures.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index b2a81a184a..eb89e3875f 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -507,6 +507,7 @@ module ActiveRecord if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any? @model_class = class_name else + ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name will be removed in Rails 4.1, consider using the class itself instead.") @model_class = class_name.constantize rescue nil end @@ -743,13 +744,6 @@ module ActiveRecord # 'namespaced/fixture' => Another::Model # # The keys must be the fixture names, that coincide with the short paths to the fixture files. - #-- - # It is also possible to pass the class name instead of the class: - # set_fixture_class 'some_fixture' => 'SomeModel' - # I think this option is redundant, i propose to deprecate it. - # Isn't it easier to always pass the class itself? - # (2011-12-20 alexeymuranov) - #++ def set_fixture_class(class_names = {}) self.fixture_class_names = self.fixture_class_names.merge(class_names.stringify_keys) end -- cgit v1.2.3 From dc54dbe8f00138e8652438fe247f8c5792da7e24 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 23 Aug 2013 23:12:31 +0200 Subject: typo [ci skip] --- guides/source/2_3_release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md index 911d8d2eef..c2002fb8fa 100644 --- a/guides/source/2_3_release_notes.md +++ b/guides/source/2_3_release_notes.md @@ -237,7 +237,7 @@ If you're one of the people who has always been bothered by the special-case nam ### HTTP Digest Authentication Support -Rails now has built-in support for HTTP digest authentication. To use it, you call `authenticate_or_request_with_http_digest` with a block that returns the uses's password (which is then hashed and compared against the transmitted credentials): +Rails now has built-in support for HTTP digest authentication. To use it, you call `authenticate_or_request_with_http_digest` with a block that returns the user's password (which is then hashed and compared against the transmitted credentials): ```ruby class PostsController < ApplicationController -- cgit v1.2.3 From 16bc2d0e7ba61d7572829104c157534c69623fb1 Mon Sep 17 00:00:00 2001 From: wangjohn Date: Sat, 24 Aug 2013 04:20:47 -0400 Subject: Adding deprecation assertions for proper_table_name. This prevents deprecation warnings from popping up. --- activerecord/test/cases/migration_test.rb | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index cbc9e96473..931caff727 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -322,11 +322,19 @@ class MigrationTest < ActiveRecord::TestCase end def test_proper_table_name_on_migrator - assert_equal "table", ActiveRecord::Migrator.proper_table_name('table') - assert_equal "table", ActiveRecord::Migrator.proper_table_name(:table) - assert_equal "reminders", ActiveRecord::Migrator.proper_table_name(Reminder) + assert_deprecated do + assert_equal "table", ActiveRecord::Migrator.proper_table_name('table') + end + assert_deprecated do + assert_equal "table", ActiveRecord::Migrator.proper_table_name(:table) + end + assert_deprecated do + assert_equal "reminders", ActiveRecord::Migrator.proper_table_name(Reminder) + end Reminder.reset_table_name - assert_equal Reminder.table_name, ActiveRecord::Migrator.proper_table_name(Reminder) + assert_deprecated do + assert_equal Reminder.table_name, ActiveRecord::Migrator.proper_table_name(Reminder) + end # Use the model's own prefix/suffix if a model is given ActiveRecord::Base.table_name_prefix = "ARprefix_" @@ -334,7 +342,9 @@ class MigrationTest < ActiveRecord::TestCase Reminder.table_name_prefix = 'prefix_' Reminder.table_name_suffix = '_suffix' Reminder.reset_table_name - assert_equal "prefix_reminders_suffix", ActiveRecord::Migrator.proper_table_name(Reminder) + assert_deprecated do + assert_equal "prefix_reminders_suffix", ActiveRecord::Migrator.proper_table_name(Reminder) + end Reminder.table_name_prefix = '' Reminder.table_name_suffix = '' Reminder.reset_table_name @@ -343,8 +353,12 @@ class MigrationTest < ActiveRecord::TestCase ActiveRecord::Base.table_name_prefix = "prefix_" ActiveRecord::Base.table_name_suffix = "_suffix" Reminder.reset_table_name - assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name('table') - assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name(:table) + assert_deprecated do + assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name('table') + end + assert_deprecated do + assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name(:table) + end end def test_proper_table_name_on_migration -- cgit v1.2.3 From bac384e85f6c4232a2ffcd9829d18896fc422e89 Mon Sep 17 00:00:00 2001 From: wangjohn Date: Sat, 24 Aug 2013 04:11:18 -0400 Subject: Removing instances of string class_names in fixtures. Also, constantizing the default_fixture_model_name when it gets loaded in from the file. Later, when the class_name is passed to a new FixtureSet, a deprecation warning will occur if the class_name is a string. --- activerecord/lib/active_record/fixtures.rb | 9 ++++++--- activerecord/test/cases/fixtures_test.rb | 14 +++++++------- guides/source/active_record_basics.md | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index eb89e3875f..a7a40ca72b 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -455,7 +455,7 @@ module ActiveRecord fixtures_map[fs_name] = new( # ActiveRecord::FixtureSet.new connection, fs_name, - class_names[fs_name] || default_fixture_model_name(fs_name), + class_names[fs_name] || (default_fixture_model_name(fs_name).safe_constantize), ::File.join(fixtures_directory, fs_name)) end @@ -504,11 +504,14 @@ module ActiveRecord @name = name @path = path + if class_name.is_a?(String) + ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name will be removed in Rails 4.2, consider using the class itself instead.") + end + if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any? @model_class = class_name else - ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name will be removed in Rails 4.1, consider using the class itself instead.") - @model_class = class_name.constantize rescue nil + @model_class = class_name.safe_constantize if class_name end @connection = ( model_class.respond_to?(:connection) ? diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index c07c9c3b74..afbe65062d 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -190,11 +190,11 @@ class FixturesTest < ActiveRecord::TestCase end def test_empty_yaml_fixture - assert_not_nil ActiveRecord::FixtureSet.new( Account.connection, "accounts", 'Account', FIXTURES_ROOT + "/naked/yml/accounts") + assert_not_nil ActiveRecord::FixtureSet.new( Account.connection, "accounts", Account, FIXTURES_ROOT + "/naked/yml/accounts") end def test_empty_yaml_fixture_with_a_comment_in_it - assert_not_nil ActiveRecord::FixtureSet.new( Account.connection, "companies", 'Company', FIXTURES_ROOT + "/naked/yml/companies") + assert_not_nil ActiveRecord::FixtureSet.new( Account.connection, "companies", Company, FIXTURES_ROOT + "/naked/yml/companies") end def test_nonexistent_fixture_file @@ -204,19 +204,19 @@ class FixturesTest < ActiveRecord::TestCase assert Dir[nonexistent_fixture_path+"*"].empty? assert_raise(Errno::ENOENT) do - ActiveRecord::FixtureSet.new( Account.connection, "companies", 'Company', nonexistent_fixture_path) + ActiveRecord::FixtureSet.new( Account.connection, "companies", Company, nonexistent_fixture_path) end end def test_dirty_dirty_yaml_file assert_raise(ActiveRecord::Fixture::FormatError) do - ActiveRecord::FixtureSet.new( Account.connection, "courses", 'Course', FIXTURES_ROOT + "/naked/yml/courses") + ActiveRecord::FixtureSet.new( Account.connection, "courses", Course, FIXTURES_ROOT + "/naked/yml/courses") end end def test_omap_fixtures assert_nothing_raised do - fixtures = ActiveRecord::FixtureSet.new(Account.connection, 'categories', 'Category', FIXTURES_ROOT + "/categories_ordered") + fixtures = ActiveRecord::FixtureSet.new(Account.connection, 'categories', Category, FIXTURES_ROOT + "/categories_ordered") fixtures.each.with_index do |(name, fixture), i| assert_equal "fixture_no_#{i}", name @@ -449,7 +449,7 @@ class OverRideFixtureMethodTest < ActiveRecord::TestCase end class CheckSetTableNameFixturesTest < ActiveRecord::TestCase - set_fixture_class :funny_jokes => 'Joke' + set_fixture_class :funny_jokes => Joke fixtures :funny_jokes # Set to false to blow away fixtures cache and ensure our fixtures are loaded # and thus takes into account our set_fixture_class @@ -532,7 +532,7 @@ class InvalidTableNameFixturesTest < ActiveRecord::TestCase end class CheckEscapedYamlFixturesTest < ActiveRecord::TestCase - set_fixture_class :funny_jokes => 'Joke' + set_fixture_class :funny_jokes => Joke fixtures :funny_jokes # Set to false to blow away fixtures cache and ensure our fixtures are loaded # and thus takes into account our set_fixture_class diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md index bff60efc33..a80c3b6c8e 100644 --- a/guides/source/active_record_basics.md +++ b/guides/source/active_record_basics.md @@ -181,7 +181,7 @@ definition: ```ruby class FunnyJoke < ActiveSupport::TestCase - set_fixture_class funny_jokes: 'Joke' + set_fixture_class funny_jokes: Joke fixtures :funny_jokes ... end -- cgit v1.2.3 From 3fd134c5594a4c05934a41bb66db4048ab5e3cb9 Mon Sep 17 00:00:00 2001 From: wangjohn Date: Sat, 24 Aug 2013 23:33:56 -0400 Subject: Changing deprecation_horizon to be Rails 4.2 Also, +ActiveRecord::Migrator.proper_table_name+ should actually have a deprecation horizon of Rails 4.2 (not 4.1). --- activerecord/lib/active_record/migration.rb | 2 +- activesupport/lib/active_support/deprecation.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 888e8771ce..a1ad4f6255 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -828,7 +828,7 @@ module ActiveRecord end def proper_table_name(name, options = {}) - ActiveSupport::Deprecation.warn "ActiveRecord::Migrator.proper_table_name is deprecated and will be removed in Rails 4.1. Use the proper_table_name instance method on ActiveRecord::Migration instead" + ActiveSupport::Deprecation.warn "ActiveRecord::Migrator.proper_table_name is deprecated and will be removed in Rails 4.2. Use the proper_table_name instance method on ActiveRecord::Migration instead" options = { table_name_prefix: ActiveRecord::Base.table_name_prefix, table_name_suffix: ActiveRecord::Base.table_name_suffix diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb index 0281c9222e..ab16977bda 100644 --- a/activesupport/lib/active_support/deprecation.rb +++ b/activesupport/lib/active_support/deprecation.rb @@ -32,7 +32,7 @@ module ActiveSupport # and the second is a library name # # ActiveSupport::Deprecation.new('2.0', 'MyLibrary') - def initialize(deprecation_horizon = '4.1', gem_name = 'Rails') + def initialize(deprecation_horizon = '4.2', gem_name = 'Rails') self.gem_name = gem_name self.deprecation_horizon = deprecation_horizon # By default, warnings are not silenced and debugging is off. -- cgit v1.2.3 From 1b446d06dddd2e14b4725eb896d046d4218941c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 25 Jun 2013 14:58:29 +0200 Subject: Move view_paths from AP to AV --- actionpack/lib/abstract_controller.rb | 1 - actionpack/lib/abstract_controller/view_paths.rb | 96 ------------ actionpack/test/controller/view_paths_test.rb | 174 --------------------- .../test/fixtures/override/test/hello_world.erb | 1 - .../test/fixtures/override2/layouts/test/sub.erb | 1 - actionview/lib/action_view.rb | 1 + actionview/lib/action_view/view_paths.rb | 96 ++++++++++++ .../test/fixtures/override/test/hello_world.erb | 1 + .../test/fixtures/override2/layouts/test/sub.erb | 1 + actionview/test/lib/controller/view_paths_test.rb | 174 +++++++++++++++++++++ 10 files changed, 273 insertions(+), 273 deletions(-) delete mode 100644 actionpack/lib/abstract_controller/view_paths.rb delete mode 100644 actionpack/test/controller/view_paths_test.rb delete mode 100644 actionpack/test/fixtures/override/test/hello_world.erb delete mode 100644 actionpack/test/fixtures/override2/layouts/test/sub.erb create mode 100644 actionview/lib/action_view/view_paths.rb create mode 100644 actionview/test/fixtures/override/test/hello_world.erb create mode 100644 actionview/test/fixtures/override2/layouts/test/sub.erb create mode 100644 actionview/test/lib/controller/view_paths_test.rb diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index 867a7954e0..ab311ec3bc 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -16,6 +16,5 @@ module AbstractController autoload :Rendering autoload :Translation autoload :AssetPaths - autoload :ViewPaths autoload :UrlFor end diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb deleted file mode 100644 index c08b3a0e2a..0000000000 --- a/actionpack/lib/abstract_controller/view_paths.rb +++ /dev/null @@ -1,96 +0,0 @@ -require 'action_view/base' - -module AbstractController - module ViewPaths - extend ActiveSupport::Concern - - included do - class_attribute :_view_paths - self._view_paths = ActionView::PathSet.new - self._view_paths.freeze - end - - delegate :template_exists?, :view_paths, :formats, :formats=, - :locale, :locale=, :to => :lookup_context - - module ClassMethods - def parent_prefixes - @parent_prefixes ||= begin - parent_controller = superclass - prefixes = [] - - until parent_controller.abstract? - prefixes << parent_controller.controller_path - parent_controller = parent_controller.superclass - end - - prefixes - end - end - end - - # The prefixes used in render "foo" shortcuts. - def _prefixes - @_prefixes ||= begin - parent_prefixes = self.class.parent_prefixes - parent_prefixes.dup.unshift(controller_path) - end - end - - # LookupContext is the object responsible to hold all information required to lookup - # templates, i.e. view paths and details. Check ActionView::LookupContext for more - # information. - def lookup_context - @_lookup_context ||= - ActionView::LookupContext.new(self.class._view_paths, details_for_lookup, _prefixes) - end - - def details_for_lookup - { } - end - - def append_view_path(path) - lookup_context.view_paths.push(*path) - end - - def prepend_view_path(path) - lookup_context.view_paths.unshift(*path) - end - - module ClassMethods - # Append a path to the list of view paths for this controller. - # - # ==== Parameters - # * path - If a String is provided, it gets converted into - # the default view path. You may also provide a custom view path - # (see ActionView::PathSet for more information) - def append_view_path(path) - self._view_paths = view_paths + Array(path) - end - - # Prepend a path to the list of view paths for this controller. - # - # ==== Parameters - # * path - If a String is provided, it gets converted into - # the default view path. You may also provide a custom view path - # (see ActionView::PathSet for more information) - def prepend_view_path(path) - self._view_paths = ActionView::PathSet.new(Array(path) + view_paths) - end - - # A list of all of the default view paths for this controller. - def view_paths - _view_paths - end - - # Set the view paths. - # - # ==== Parameters - # * paths - If a PathSet is provided, use that; - # otherwise, process the parameter into a PathSet. - def view_paths=(paths) - self._view_paths = ActionView::PathSet.new(Array(paths)) - end - end - end -end diff --git a/actionpack/test/controller/view_paths_test.rb b/actionpack/test/controller/view_paths_test.rb deleted file mode 100644 index c6e7a523b9..0000000000 --- a/actionpack/test/controller/view_paths_test.rb +++ /dev/null @@ -1,174 +0,0 @@ -require 'abstract_unit' - -class ViewLoadPathsTest < ActionController::TestCase - class TestController < ActionController::Base - def self.controller_path() "test" end - - before_action :add_view_path, only: :hello_world_at_request_time - - def hello_world() end - def hello_world_at_request_time() render(:action => 'hello_world') end - - private - def add_view_path - prepend_view_path "#{FIXTURE_LOAD_PATH}/override" - end - end - - module Test - class SubController < ActionController::Base - layout 'test/sub' - def hello_world; render(:template => 'test/hello_world'); end - end - end - - def setup - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - @controller = TestController.new - @paths = TestController.view_paths - end - - def teardown - TestController.view_paths = @paths - end - - def expand(array) - array.map {|x| File.expand_path(x.to_s)} - end - - def assert_paths(*paths) - controller = paths.first.is_a?(Class) ? paths.shift : @controller - assert_equal expand(paths), controller.view_paths.map { |p| p.to_s } - end - - def test_template_load_path_was_set_correctly - assert_paths FIXTURE_LOAD_PATH - end - - def test_controller_appends_view_path_correctly - @controller.append_view_path 'foo' - assert_paths(FIXTURE_LOAD_PATH, "foo") - - @controller.append_view_path(%w(bar baz)) - assert_paths(FIXTURE_LOAD_PATH, "foo", "bar", "baz") - - @controller.append_view_path(FIXTURE_LOAD_PATH) - assert_paths(FIXTURE_LOAD_PATH, "foo", "bar", "baz", FIXTURE_LOAD_PATH) - end - - def test_controller_prepends_view_path_correctly - @controller.prepend_view_path 'baz' - assert_paths("baz", FIXTURE_LOAD_PATH) - - @controller.prepend_view_path(%w(foo bar)) - assert_paths "foo", "bar", "baz", FIXTURE_LOAD_PATH - - @controller.prepend_view_path(FIXTURE_LOAD_PATH) - assert_paths FIXTURE_LOAD_PATH, "foo", "bar", "baz", FIXTURE_LOAD_PATH - end - - def test_template_appends_view_path_correctly - @controller.instance_variable_set :@template, ActionView::Base.new(TestController.view_paths, {}, @controller) - class_view_paths = TestController.view_paths - - @controller.append_view_path 'foo' - assert_paths FIXTURE_LOAD_PATH, "foo" - - @controller.append_view_path(%w(bar baz)) - assert_paths FIXTURE_LOAD_PATH, "foo", "bar", "baz" - assert_paths TestController, *class_view_paths - end - - def test_template_prepends_view_path_correctly - @controller.instance_variable_set :@template, ActionView::Base.new(TestController.view_paths, {}, @controller) - class_view_paths = TestController.view_paths - - @controller.prepend_view_path 'baz' - assert_paths "baz", FIXTURE_LOAD_PATH - - @controller.prepend_view_path(%w(foo bar)) - assert_paths "foo", "bar", "baz", FIXTURE_LOAD_PATH - assert_paths TestController, *class_view_paths - end - - def test_view_paths - get :hello_world - assert_response :success - assert_equal "Hello world!", @response.body - end - - def test_view_paths_override - TestController.prepend_view_path "#{FIXTURE_LOAD_PATH}/override" - get :hello_world - assert_response :success - assert_equal "Hello overridden world!", @response.body - end - - def test_view_paths_override_for_layouts_in_controllers_with_a_module - @controller = Test::SubController.new - Test::SubController.view_paths = [ "#{FIXTURE_LOAD_PATH}/override", FIXTURE_LOAD_PATH, "#{FIXTURE_LOAD_PATH}/override2" ] - get :hello_world - assert_response :success - assert_equal "layout: Hello overridden world!", @response.body - end - - def test_view_paths_override_at_request_time - get :hello_world_at_request_time - assert_response :success - assert_equal "Hello overridden world!", @response.body - end - - def test_decorate_view_paths_with_custom_resolver - decorator_class = Class.new(ActionView::PathResolver) do - def initialize(path_set) - @path_set = path_set - end - - def find_all(*args) - @path_set.find_all(*args).collect do |template| - ::ActionView::Template.new( - "Decorated body", - template.identifier, - template.handler, - { - :virtual_path => template.virtual_path, - :format => template.formats - } - ) - end - end - end - - decorator = decorator_class.new(TestController.view_paths) - TestController.view_paths = ActionView::PathSet.new.push(decorator) - - get :hello_world - assert_response :success - assert_equal "Decorated body", @response.body - end - - def test_inheritance - original_load_paths = ActionController::Base.view_paths - - self.class.class_eval %{ - class A < ActionController::Base; end - class B < A; end - class C < ActionController::Base; end - } - - A.view_paths = ['a/path'] - - assert_paths A, "a/path" - assert_paths A, *B.view_paths - assert_paths C, *original_load_paths - - C.view_paths = [] - assert_nothing_raised { C.append_view_path 'c/path' } - assert_paths C, "c/path" - end - - def test_lookup_context_accessor - assert_equal ["test"], TestController.new.lookup_context.prefixes - end -end diff --git a/actionpack/test/fixtures/override/test/hello_world.erb b/actionpack/test/fixtures/override/test/hello_world.erb deleted file mode 100644 index 3e308d3d86..0000000000 --- a/actionpack/test/fixtures/override/test/hello_world.erb +++ /dev/null @@ -1 +0,0 @@ -Hello overridden world! \ No newline at end of file diff --git a/actionpack/test/fixtures/override2/layouts/test/sub.erb b/actionpack/test/fixtures/override2/layouts/test/sub.erb deleted file mode 100644 index 3863d5a8ef..0000000000 --- a/actionpack/test/fixtures/override2/layouts/test/sub.erb +++ /dev/null @@ -1 +0,0 @@ -layout: <%= yield %> \ No newline at end of file diff --git a/actionview/lib/action_view.rb b/actionview/lib/action_view.rb index 8def4ba7c5..7adf19cc7a 100644 --- a/actionview/lib/action_view.rb +++ b/actionview/lib/action_view.rb @@ -38,6 +38,7 @@ module ActionView autoload :RecordIdentifier autoload :RoutingUrlFor autoload :Template + autoload :ViewPaths autoload_under "renderer" do autoload :Renderer diff --git a/actionview/lib/action_view/view_paths.rb b/actionview/lib/action_view/view_paths.rb new file mode 100644 index 0000000000..6c349feb1d --- /dev/null +++ b/actionview/lib/action_view/view_paths.rb @@ -0,0 +1,96 @@ +require 'action_view/base' + +module ActionView + module ViewPaths + extend ActiveSupport::Concern + + included do + class_attribute :_view_paths + self._view_paths = ActionView::PathSet.new + self._view_paths.freeze + end + + delegate :template_exists?, :view_paths, :formats, :formats=, + :locale, :locale=, :to => :lookup_context + + module ClassMethods + def parent_prefixes + @parent_prefixes ||= begin + parent_controller = superclass + prefixes = [] + + until parent_controller.abstract? + prefixes << parent_controller.controller_path + parent_controller = parent_controller.superclass + end + + prefixes + end + end + end + + # The prefixes used in render "foo" shortcuts. + def _prefixes + @_prefixes ||= begin + parent_prefixes = self.class.parent_prefixes + parent_prefixes.dup.unshift(controller_path) + end + end + + # LookupContext is the object responsible to hold all information required to lookup + # templates, i.e. view paths and details. Check ActionView::LookupContext for more + # information. + def lookup_context + @_lookup_context ||= + ActionView::LookupContext.new(self.class._view_paths, details_for_lookup, _prefixes) + end + + def details_for_lookup + { } + end + + def append_view_path(path) + lookup_context.view_paths.push(*path) + end + + def prepend_view_path(path) + lookup_context.view_paths.unshift(*path) + end + + module ClassMethods + # Append a path to the list of view paths for this controller. + # + # ==== Parameters + # * path - If a String is provided, it gets converted into + # the default view path. You may also provide a custom view path + # (see ActionView::PathSet for more information) + def append_view_path(path) + self._view_paths = view_paths + Array(path) + end + + # Prepend a path to the list of view paths for this controller. + # + # ==== Parameters + # * path - If a String is provided, it gets converted into + # the default view path. You may also provide a custom view path + # (see ActionView::PathSet for more information) + def prepend_view_path(path) + self._view_paths = ActionView::PathSet.new(Array(path) + view_paths) + end + + # A list of all of the default view paths for this controller. + def view_paths + _view_paths + end + + # Set the view paths. + # + # ==== Parameters + # * paths - If a PathSet is provided, use that; + # otherwise, process the parameter into a PathSet. + def view_paths=(paths) + self._view_paths = ActionView::PathSet.new(Array(paths)) + end + end + end +end diff --git a/actionview/test/fixtures/override/test/hello_world.erb b/actionview/test/fixtures/override/test/hello_world.erb new file mode 100644 index 0000000000..3e308d3d86 --- /dev/null +++ b/actionview/test/fixtures/override/test/hello_world.erb @@ -0,0 +1 @@ +Hello overridden world! \ No newline at end of file diff --git a/actionview/test/fixtures/override2/layouts/test/sub.erb b/actionview/test/fixtures/override2/layouts/test/sub.erb new file mode 100644 index 0000000000..3863d5a8ef --- /dev/null +++ b/actionview/test/fixtures/override2/layouts/test/sub.erb @@ -0,0 +1 @@ +layout: <%= yield %> \ No newline at end of file diff --git a/actionview/test/lib/controller/view_paths_test.rb b/actionview/test/lib/controller/view_paths_test.rb new file mode 100644 index 0000000000..c6e7a523b9 --- /dev/null +++ b/actionview/test/lib/controller/view_paths_test.rb @@ -0,0 +1,174 @@ +require 'abstract_unit' + +class ViewLoadPathsTest < ActionController::TestCase + class TestController < ActionController::Base + def self.controller_path() "test" end + + before_action :add_view_path, only: :hello_world_at_request_time + + def hello_world() end + def hello_world_at_request_time() render(:action => 'hello_world') end + + private + def add_view_path + prepend_view_path "#{FIXTURE_LOAD_PATH}/override" + end + end + + module Test + class SubController < ActionController::Base + layout 'test/sub' + def hello_world; render(:template => 'test/hello_world'); end + end + end + + def setup + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + @controller = TestController.new + @paths = TestController.view_paths + end + + def teardown + TestController.view_paths = @paths + end + + def expand(array) + array.map {|x| File.expand_path(x.to_s)} + end + + def assert_paths(*paths) + controller = paths.first.is_a?(Class) ? paths.shift : @controller + assert_equal expand(paths), controller.view_paths.map { |p| p.to_s } + end + + def test_template_load_path_was_set_correctly + assert_paths FIXTURE_LOAD_PATH + end + + def test_controller_appends_view_path_correctly + @controller.append_view_path 'foo' + assert_paths(FIXTURE_LOAD_PATH, "foo") + + @controller.append_view_path(%w(bar baz)) + assert_paths(FIXTURE_LOAD_PATH, "foo", "bar", "baz") + + @controller.append_view_path(FIXTURE_LOAD_PATH) + assert_paths(FIXTURE_LOAD_PATH, "foo", "bar", "baz", FIXTURE_LOAD_PATH) + end + + def test_controller_prepends_view_path_correctly + @controller.prepend_view_path 'baz' + assert_paths("baz", FIXTURE_LOAD_PATH) + + @controller.prepend_view_path(%w(foo bar)) + assert_paths "foo", "bar", "baz", FIXTURE_LOAD_PATH + + @controller.prepend_view_path(FIXTURE_LOAD_PATH) + assert_paths FIXTURE_LOAD_PATH, "foo", "bar", "baz", FIXTURE_LOAD_PATH + end + + def test_template_appends_view_path_correctly + @controller.instance_variable_set :@template, ActionView::Base.new(TestController.view_paths, {}, @controller) + class_view_paths = TestController.view_paths + + @controller.append_view_path 'foo' + assert_paths FIXTURE_LOAD_PATH, "foo" + + @controller.append_view_path(%w(bar baz)) + assert_paths FIXTURE_LOAD_PATH, "foo", "bar", "baz" + assert_paths TestController, *class_view_paths + end + + def test_template_prepends_view_path_correctly + @controller.instance_variable_set :@template, ActionView::Base.new(TestController.view_paths, {}, @controller) + class_view_paths = TestController.view_paths + + @controller.prepend_view_path 'baz' + assert_paths "baz", FIXTURE_LOAD_PATH + + @controller.prepend_view_path(%w(foo bar)) + assert_paths "foo", "bar", "baz", FIXTURE_LOAD_PATH + assert_paths TestController, *class_view_paths + end + + def test_view_paths + get :hello_world + assert_response :success + assert_equal "Hello world!", @response.body + end + + def test_view_paths_override + TestController.prepend_view_path "#{FIXTURE_LOAD_PATH}/override" + get :hello_world + assert_response :success + assert_equal "Hello overridden world!", @response.body + end + + def test_view_paths_override_for_layouts_in_controllers_with_a_module + @controller = Test::SubController.new + Test::SubController.view_paths = [ "#{FIXTURE_LOAD_PATH}/override", FIXTURE_LOAD_PATH, "#{FIXTURE_LOAD_PATH}/override2" ] + get :hello_world + assert_response :success + assert_equal "layout: Hello overridden world!", @response.body + end + + def test_view_paths_override_at_request_time + get :hello_world_at_request_time + assert_response :success + assert_equal "Hello overridden world!", @response.body + end + + def test_decorate_view_paths_with_custom_resolver + decorator_class = Class.new(ActionView::PathResolver) do + def initialize(path_set) + @path_set = path_set + end + + def find_all(*args) + @path_set.find_all(*args).collect do |template| + ::ActionView::Template.new( + "Decorated body", + template.identifier, + template.handler, + { + :virtual_path => template.virtual_path, + :format => template.formats + } + ) + end + end + end + + decorator = decorator_class.new(TestController.view_paths) + TestController.view_paths = ActionView::PathSet.new.push(decorator) + + get :hello_world + assert_response :success + assert_equal "Decorated body", @response.body + end + + def test_inheritance + original_load_paths = ActionController::Base.view_paths + + self.class.class_eval %{ + class A < ActionController::Base; end + class B < A; end + class C < ActionController::Base; end + } + + A.view_paths = ['a/path'] + + assert_paths A, "a/path" + assert_paths A, *B.view_paths + assert_paths C, *original_load_paths + + C.view_paths = [] + assert_nothing_raised { C.append_view_path 'c/path' } + assert_paths C, "c/path" + end + + def test_lookup_context_accessor + assert_equal ["test"], TestController.new.lookup_context.prefixes + end +end -- cgit v1.2.3 From e772b098edce2a4ac6a51edb6758e1ef08c4a176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Wed, 26 Jun 2013 12:12:57 +0200 Subject: Require only path_set && lookup_context instead of whole base --- actionview/lib/action_view/view_paths.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/actionview/lib/action_view/view_paths.rb b/actionview/lib/action_view/view_paths.rb index 6c349feb1d..49adc1134f 100644 --- a/actionview/lib/action_view/view_paths.rb +++ b/actionview/lib/action_view/view_paths.rb @@ -1,4 +1,5 @@ -require 'action_view/base' +require 'action_view/path_set' +require 'action_view/lookup_context' module ActionView module ViewPaths -- cgit v1.2.3 From 5759531a951ce495e2ac7dd8de79fa36ea798bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Wed, 26 Jun 2013 13:40:46 +0200 Subject: Move rendering from AP to AV --- actionpack/lib/abstract_controller.rb | 1 - actionpack/lib/abstract_controller/layouts.rb | 423 --------------------- actionpack/lib/abstract_controller/rendering.rb | 187 --------- .../lib/action_controller/metal/rendering.rb | 2 +- .../lib/action_controller/metal/streaming.rb | 2 +- actionview/lib/action_view.rb | 1 + actionview/lib/action_view/rendering.rb | 186 +++++++++ 7 files changed, 189 insertions(+), 613 deletions(-) delete mode 100644 actionpack/lib/abstract_controller/layouts.rb create mode 100644 actionview/lib/action_view/rendering.rb diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index ab311ec3bc..7ab5af00c3 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -13,7 +13,6 @@ module AbstractController autoload :Helpers autoload :Layouts autoload :Logger - autoload :Rendering autoload :Translation autoload :AssetPaths autoload :UrlFor diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb deleted file mode 100644 index 8e7bdf620e..0000000000 --- a/actionpack/lib/abstract_controller/layouts.rb +++ /dev/null @@ -1,423 +0,0 @@ -require "active_support/core_ext/module/remove_method" - -module AbstractController - # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in - # repeated setups. The inclusion pattern has pages that look like this: - # - # <%= render "shared/header" %> - # Hello World - # <%= render "shared/footer" %> - # - # This approach is a decent way of keeping common structures isolated from the changing content, but it's verbose - # and if you ever want to change the structure of these two includes, you'll have to change all the templates. - # - # With layouts, you can flip it around and have the common structure know where to insert changing content. This means - # that the header and footer are only mentioned in one place, like this: - # - # // The header part of this layout - # <%= yield %> - # // The footer part of this layout - # - # And then you have content pages that look like this: - # - # hello world - # - # At rendering time, the content page is computed and then inserted in the layout, like this: - # - # // The header part of this layout - # hello world - # // The footer part of this layout - # - # == Accessing shared variables - # - # Layouts have access to variables specified in the content pages and vice versa. This allows you to have layouts with - # references that won't materialize before rendering time: - # - #

<%= @page_title %>

- # <%= yield %> - # - # ...and content pages that fulfill these references _at_ rendering time: - # - # <% @page_title = "Welcome" %> - # Off-world colonies offers you a chance to start a new life - # - # The result after rendering is: - # - #

Welcome

- # Off-world colonies offers you a chance to start a new life - # - # == Layout assignment - # - # You can either specify a layout declaratively (using the #layout class method) or give - # it the same name as your controller, and place it in app/views/layouts. - # If a subclass does not have a layout specified, it inherits its layout using normal Ruby inheritance. - # - # For instance, if you have PostsController and a template named app/views/layouts/posts.html.erb, - # that template will be used for all actions in PostsController and controllers inheriting - # from PostsController. - # - # If you use a module, for instance Weblog::PostsController, you will need a template named - # app/views/layouts/weblog/posts.html.erb. - # - # Since all your controllers inherit from ApplicationController, they will use - # app/views/layouts/application.html.erb if no other layout is specified - # or provided. - # - # == Inheritance Examples - # - # class BankController < ActionController::Base - # # bank.html.erb exists - # - # class ExchangeController < BankController - # # exchange.html.erb exists - # - # class CurrencyController < BankController - # - # class InformationController < BankController - # layout "information" - # - # class TellerController < InformationController - # # teller.html.erb exists - # - # class EmployeeController < InformationController - # # employee.html.erb exists - # layout nil - # - # class VaultController < BankController - # layout :access_level_layout - # - # class TillController < BankController - # layout false - # - # In these examples, we have three implicit lookup scenarios: - # * The BankController uses the "bank" layout. - # * The ExchangeController uses the "exchange" layout. - # * The CurrencyController inherits the layout from BankController. - # - # However, when a layout is explicitly set, the explicitly set layout wins: - # * The InformationController uses the "information" layout, explicitly set. - # * The TellerController also uses the "information" layout, because the parent explicitly set it. - # * The EmployeeController uses the "employee" layout, because it set the layout to nil, resetting the parent configuration. - # * The VaultController chooses a layout dynamically by calling the access_level_layout method. - # * The TillController does not use a layout at all. - # - # == Types of layouts - # - # Layouts are basically just regular templates, but the name of this template needs not be specified statically. Sometimes - # you want to alternate layouts depending on runtime information, such as whether someone is logged in or not. This can - # be done either by specifying a method reference as a symbol or using an inline method (as a proc). - # - # The method reference is the preferred approach to variable layouts and is used like this: - # - # class WeblogController < ActionController::Base - # layout :writers_and_readers - # - # def index - # # fetching posts - # end - # - # private - # def writers_and_readers - # logged_in? ? "writer_layout" : "reader_layout" - # end - # end - # - # Now when a new request for the index action is processed, the layout will vary depending on whether the person accessing - # is logged in or not. - # - # If you want to use an inline method, such as a proc, do something like this: - # - # class WeblogController < ActionController::Base - # layout proc { |controller| controller.logged_in? ? "writer_layout" : "reader_layout" } - # end - # - # If an argument isn't given to the proc, it's evaluated in the context of - # the current controller anyway. - # - # class WeblogController < ActionController::Base - # layout proc { logged_in? ? "writer_layout" : "reader_layout" } - # end - # - # Of course, the most common way of specifying a layout is still just as a plain template name: - # - # class WeblogController < ActionController::Base - # layout "weblog_standard" - # end - # - # The template will be looked always in app/views/layouts/ folder. But you can point - # layouts folder direct also. layout "layouts/demo" is the same as layout "demo". - # - # Setting the layout to nil forces it to be looked up in the filesystem and fallbacks to the parent behavior if none exists. - # Setting it to nil is useful to re-enable template lookup overriding a previous configuration set in the parent: - # - # class ApplicationController < ActionController::Base - # layout "application" - # end - # - # class PostsController < ApplicationController - # # Will use "application" layout - # end - # - # class CommentsController < ApplicationController - # # Will search for "comments" layout and fallback "application" layout - # layout nil - # end - # - # == Conditional layouts - # - # If you have a layout that by default is applied to all the actions of a controller, you still have the option of rendering - # a given action or set of actions without a layout, or restricting a layout to only a single action or a set of actions. The - # :only and :except options can be passed to the layout call. For example: - # - # class WeblogController < ActionController::Base - # layout "weblog_standard", except: :rss - # - # # ... - # - # end - # - # This will assign "weblog_standard" as the WeblogController's layout for all actions except for the +rss+ action, which will - # be rendered directly, without wrapping a layout around the rendered view. - # - # Both the :only and :except condition can accept an arbitrary number of method references, so - # #except: [ :rss, :text_only ] is valid, as is except: :rss. - # - # == Using a different layout in the action render call - # - # If most of your actions use the same layout, it makes perfect sense to define a controller-wide layout as described above. - # Sometimes you'll have exceptions where one action wants to use a different layout than the rest of the controller. - # You can do this by passing a :layout option to the render call. For example: - # - # class WeblogController < ActionController::Base - # layout "weblog_standard" - # - # def help - # render action: "help", layout: "help" - # end - # end - # - # This will override the controller-wide "weblog_standard" layout, and will render the help action with the "help" layout instead. - module Layouts - extend ActiveSupport::Concern - - include Rendering - - included do - class_attribute :_layout, :_layout_conditions, :instance_accessor => false - self._layout = nil - self._layout_conditions = {} - _write_layout_method - end - - delegate :_layout_conditions, to: :class - - module ClassMethods - def inherited(klass) # :nodoc: - super - klass._write_layout_method - end - - # This module is mixed in if layout conditions are provided. This means - # that if no layout conditions are used, this method is not used - module LayoutConditions # :nodoc: - private - - # Determines whether the current action has a layout definition by - # checking the action name against the :only and :except conditions - # set by the layout method. - # - # ==== Returns - # * Boolean - True if the action has a layout definition, false otherwise. - def _conditional_layout? - return unless super - - conditions = _layout_conditions - - if only = conditions[:only] - only.include?(action_name) - elsif except = conditions[:except] - !except.include?(action_name) - else - true - end - end - end - - # Specify the layout to use for this class. - # - # If the specified layout is a: - # String:: the String is the template name - # Symbol:: call the method specified by the symbol, which will return the template name - # false:: There is no layout - # true:: raise an ArgumentError - # nil:: Force default layout behavior with inheritance - # - # ==== Parameters - # * layout - The layout to use. - # - # ==== Options (conditions) - # * :only - A list of actions to apply this layout to. - # * :except - Apply this layout to all actions but this one. - def layout(layout, conditions = {}) - include LayoutConditions unless conditions.empty? - - conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} } - self._layout_conditions = conditions - - self._layout = layout - _write_layout_method - end - - # If no layout is supplied, look for a template named the return - # value of this method. - # - # ==== Returns - # * String - A template name - def _implied_layout_name # :nodoc: - controller_path - end - - # Creates a _layout method to be called by _default_layout . - # - # If a layout is not explicitly mentioned then look for a layout with the controller's name. - # if nothing is found then try same procedure to find super class's layout. - def _write_layout_method # :nodoc: - remove_possible_method(:_layout) - - prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"] - default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}).first || super" - name_clause = if name - default_behavior - else - <<-RUBY - super - RUBY - end - - layout_definition = case _layout - when String - _layout.inspect - when Symbol - <<-RUBY - #{_layout}.tap do |layout| - return #{default_behavior} if layout.nil? - unless layout.is_a?(String) || !layout - raise ArgumentError, "Your layout method :#{_layout} returned \#{layout}. It " \ - "should have returned a String, false, or nil" - end - end - RUBY - when Proc - define_method :_layout_from_proc, &_layout - protected :_layout_from_proc - <<-RUBY - result = _layout_from_proc(#{_layout.arity == 0 ? '' : 'self'}) - return #{default_behavior} if result.nil? - result - RUBY - when false - nil - when true - raise ArgumentError, "Layouts must be specified as a String, Symbol, Proc, false, or nil" - when nil - name_clause - end - - self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def _layout - if _conditional_layout? - #{layout_definition} - else - #{name_clause} - end - end - private :_layout - RUBY - end - end - - def _normalize_options(options) # :nodoc: - super - - if _include_layout?(options) - layout = options.delete(:layout) { :default } - options[:layout] = _layout_for_option(layout) - end - end - - attr_internal_writer :action_has_layout - - def initialize(*) # :nodoc: - @_action_has_layout = true - super - end - - # Controls whether an action should be rendered using a layout. - # If you want to disable any layout settings for the - # current action so that it is rendered without a layout then - # either override this method in your controller to return false - # for that action or set the action_has_layout attribute - # to false before rendering. - def action_has_layout? - @_action_has_layout - end - - private - - def _conditional_layout? - true - end - - # This will be overwritten by _write_layout_method - def _layout; end - - # Determine the layout for a given name, taking into account the name type. - # - # ==== Parameters - # * name - The name of the template - def _layout_for_option(name) - case name - when String then _normalize_layout(name) - when Proc then name - when true then Proc.new { _default_layout(true) } - when :default then Proc.new { _default_layout(false) } - when false, nil then nil - else - raise ArgumentError, - "String, Proc, :default, true, or false, expected for `layout'; you passed #{name.inspect}" - end - end - - def _normalize_layout(value) - value.is_a?(String) && value !~ /\blayouts/ ? "layouts/#{value}" : value - end - - # Returns the default layout for this controller. - # Optionally raises an exception if the layout could not be found. - # - # ==== Parameters - # * require_layout - If set to true and layout is not found, - # an ArgumentError exception is raised (defaults to false) - # - # ==== Returns - # * template - The template object for the default layout (or nil) - def _default_layout(require_layout = false) - begin - value = _layout if action_has_layout? - rescue NameError => e - raise e, "Could not render layout: #{e.message}" - end - - if require_layout && action_has_layout? && !value - raise ArgumentError, - "There was no default layout for #{self.class} in #{view_paths.inspect}" - end - - _normalize_layout(value) - end - - def _include_layout?(options) - (options.keys & [:text, :inline, :partial]).empty? || options.key?(:layout) - end - end -end diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 3f34add790..8997207550 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -1,6 +1,3 @@ -require "abstract_controller/base" -require "action_view" - module AbstractController class DoubleRenderError < Error DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." @@ -9,188 +6,4 @@ module AbstractController super(message || DEFAULT_MESSAGE) end end - - # This is a class to fix I18n global state. Whenever you provide I18n.locale during a request, - # it will trigger the lookup_context and consequently expire the cache. - class I18nProxy < ::I18n::Config #:nodoc: - attr_reader :original_config, :lookup_context - - def initialize(original_config, lookup_context) - original_config = original_config.original_config if original_config.respond_to?(:original_config) - @original_config, @lookup_context = original_config, lookup_context - end - - def locale - @original_config.locale - end - - def locale=(value) - @lookup_context.locale = value - end - end - - module Rendering - extend ActiveSupport::Concern - include AbstractController::ViewPaths - - included do - class_attribute :protected_instance_variables - self.protected_instance_variables = [] - end - - # Overwrite process to setup I18n proxy. - def process(*) #:nodoc: - old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context) - super - ensure - I18n.config = old_config - end - - module ClassMethods - def view_context_class - @view_context_class ||= begin - routes = respond_to?(:_routes) && _routes - helpers = respond_to?(:_helpers) && _helpers - - Class.new(ActionView::Base) do - if routes - include routes.url_helpers - include routes.mounted_helpers - end - - if helpers - include helpers - end - end - end - end - end - - attr_internal_writer :view_context_class - - def view_context_class - @_view_context_class ||= self.class.view_context_class - end - - # An instance of a view class. The default view class is ActionView::Base - # - # The view class must have the following methods: - # View.new[lookup_context, assigns, controller] - # Create a new ActionView instance for a controller - # View#render[options] - # Returns String with the rendered template - # - # Override this method in a module to change the default behavior. - def view_context - view_context_class.new(view_renderer, view_assigns, self) - end - - # Returns an object that is able to render templates. - def view_renderer - @_view_renderer ||= ActionView::Renderer.new(lookup_context) - end - - # Normalize arguments, options and then delegates render_to_body and - # sticks the result in self.response_body. - def render(*args, &block) - options = _normalize_render(*args, &block) - self.response_body = render_to_body(options) - end - - # Raw rendering of a template to a string. - # - # It is similar to render, except that it does not - # set the response_body and it should be guaranteed - # to always return a string. - # - # If a component extends the semantics of response_body - # (as Action Controller extends it to be anything that - # responds to the method each), this method needs to be - # overridden in order to still return a string. - # :api: plugin - def render_to_string(*args, &block) - options = _normalize_render(*args, &block) - render_to_body(options) - end - - # Raw rendering of a template. - # :api: plugin - def render_to_body(options = {}) - _process_options(options) - _render_template(options) - end - - # Find and renders a template based on the options given. - # :api: private - def _render_template(options) #:nodoc: - lookup_context.rendered_format = nil if options[:formats] - view_renderer.render(view_context, options) - end - - DEFAULT_PROTECTED_INSTANCE_VARIABLES = [ - :@_action_name, :@_response_body, :@_formats, :@_prefixes, :@_config, - :@_view_context_class, :@_view_renderer, :@_lookup_context - ] - - # This method should return a hash with assigns. - # You can overwrite this configuration per controller. - # :api: public - def view_assigns - hash = {} - variables = instance_variables - variables -= protected_instance_variables - variables -= DEFAULT_PROTECTED_INSTANCE_VARIABLES - variables.each { |name| hash[name[1..-1]] = instance_variable_get(name) } - hash - end - - private - - # Normalize args and options. - # :api: private - def _normalize_render(*args, &block) - options = _normalize_args(*args, &block) - _normalize_options(options) - options - end - - # Normalize args by converting render "foo" to render :action => "foo" and - # render "foo/bar" to render :file => "foo/bar". - # :api: plugin - def _normalize_args(action=nil, options={}) - case action - when NilClass - when Hash - options = action - when String, Symbol - action = action.to_s - key = action.include?(?/) ? :file : :action - options[key] = action - else - options[:partial] = action - end - - options - end - - # Normalize options. - # :api: plugin - def _normalize_options(options) - if options[:partial] == true - options[:partial] = action_name - end - - if (options.keys & [:partial, :file, :template]).empty? - options[:prefixes] ||= _prefixes - end - - options[:template] ||= (options[:action] || action_name).to_s - options - end - - # Process extra options. - # :api: plugin - def _process_options(options) - end - end end diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index bea6b88f91..e89542f9f9 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -2,7 +2,7 @@ module ActionController module Rendering extend ActiveSupport::Concern - include AbstractController::Rendering + include ActionView::Rendering # Before processing, set the request formats in current controller formats. def process_action(*) #:nodoc: diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb index 73e9b5660d..2c86d7136c 100644 --- a/actionpack/lib/action_controller/metal/streaming.rb +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -193,7 +193,7 @@ module ActionController #:nodoc: module Streaming extend ActiveSupport::Concern - include AbstractController::Rendering + include ActionView::Rendering protected diff --git a/actionview/lib/action_view.rb b/actionview/lib/action_view.rb index 7adf19cc7a..65cdefe057 100644 --- a/actionview/lib/action_view.rb +++ b/actionview/lib/action_view.rb @@ -36,6 +36,7 @@ module ActionView autoload :LookupContext autoload :PathSet autoload :RecordIdentifier + autoload :Rendering autoload :RoutingUrlFor autoload :Template autoload :ViewPaths diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb new file mode 100644 index 0000000000..9bade857be --- /dev/null +++ b/actionview/lib/action_view/rendering.rb @@ -0,0 +1,186 @@ + +module ActionView + # This is a class to fix I18n global state. Whenever you provide I18n.locale during a request, + # it will trigger the lookup_context and consequently expire the cache. + class I18nProxy < ::I18n::Config #:nodoc: + attr_reader :original_config, :lookup_context + + def initialize(original_config, lookup_context) + original_config = original_config.original_config if original_config.respond_to?(:original_config) + @original_config, @lookup_context = original_config, lookup_context + end + + def locale + @original_config.locale + end + + def locale=(value) + @lookup_context.locale = value + end + end + + module Rendering + extend ActiveSupport::Concern + include ActionView::ViewPaths + + included do + class_attribute :protected_instance_variables + self.protected_instance_variables = [] + end + + # Overwrite process to setup I18n proxy. + def process(*) #:nodoc: + old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context) + super + ensure + I18n.config = old_config + end + + module ClassMethods + def view_context_class + @view_context_class ||= begin + routes = respond_to?(:_routes) && _routes + helpers = respond_to?(:_helpers) && _helpers + + Class.new(ActionView::Base) do + if routes + include routes.url_helpers + include routes.mounted_helpers + end + + if helpers + include helpers + end + end + end + end + end + + attr_internal_writer :view_context_class + + def view_context_class + @_view_context_class ||= self.class.view_context_class + end + + # An instance of a view class. The default view class is ActionView::Base + # + # The view class must have the following methods: + # View.new[lookup_context, assigns, controller] + # Create a new ActionView instance for a controller + # View#render[options] + # Returns String with the rendered template + # + # Override this method in a module to change the default behavior. + def view_context + view_context_class.new(view_renderer, view_assigns, self) + end + + # Returns an object that is able to render templates. + def view_renderer + @_view_renderer ||= ActionView::Renderer.new(lookup_context) + end + + # Normalize arguments, options and then delegates render_to_body and + # sticks the result in self.response_body. + def render(*args, &block) + options = _normalize_render(*args, &block) + self.response_body = render_to_body(options) + end + + # Raw rendering of a template to a string. + # + # It is similar to render, except that it does not + # set the response_body and it should be guaranteed + # to always return a string. + # + # If a component extends the semantics of response_body + # (as Action Controller extends it to be anything that + # responds to the method each), this method needs to be + # overridden in order to still return a string. + # :api: plugin + def render_to_string(*args, &block) + options = _normalize_render(*args, &block) + render_to_body(options) + end + + # Raw rendering of a template. + # :api: plugin + def render_to_body(options = {}) + _process_options(options) + _render_template(options) + end + + # Find and renders a template based on the options given. + # :api: private + def _render_template(options) #:nodoc: + lookup_context.rendered_format = nil if options[:formats] + view_renderer.render(view_context, options) + end + + DEFAULT_PROTECTED_INSTANCE_VARIABLES = [ + :@_action_name, :@_response_body, :@_formats, :@_prefixes, :@_config, + :@_view_context_class, :@_view_renderer, :@_lookup_context + ] + + # This method should return a hash with assigns. + # You can overwrite this configuration per controller. + # :api: public + def view_assigns + hash = {} + variables = instance_variables + variables -= protected_instance_variables + variables -= DEFAULT_PROTECTED_INSTANCE_VARIABLES + variables.each { |name| hash[name[1..-1]] = instance_variable_get(name) } + hash + end + + private + + # Normalize args and options. + # :api: private + def _normalize_render(*args, &block) + options = _normalize_args(*args, &block) + _normalize_options(options) + options + end + + # Normalize args by converting render "foo" to render :action => "foo" and + # render "foo/bar" to render :file => "foo/bar". + # :api: plugin + def _normalize_args(action=nil, options={}) + case action + when NilClass + when Hash + options = action + when String, Symbol + action = action.to_s + key = action.include?(?/) ? :file : :action + options[key] = action + else + options[:partial] = action + end + + options + end + + # Normalize options. + # :api: plugin + def _normalize_options(options) + if options[:partial] == true + options[:partial] = action_name + end + + if (options.keys & [:partial, :file, :template]).empty? + options[:prefixes] ||= _prefixes + end + + options[:template] ||= (options[:action] || action_name).to_s + options + end + + # Process extra options. + # :api: plugin + def _process_options(options) + end + end +end -- cgit v1.2.3 From b2ae1fae5d332569df6e1beb94cbfd4f4892b9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Wed, 26 Jun 2013 14:48:08 +0200 Subject: Add loading 'action_view' as part of rails/all --- railties/lib/rails/all.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/railties/lib/rails/all.rb b/railties/lib/rails/all.rb index 6c9c53fc69..2e83c0fe14 100644 --- a/railties/lib/rails/all.rb +++ b/railties/lib/rails/all.rb @@ -3,6 +3,7 @@ require "rails" %w( active_record action_controller + action_view action_mailer rails/test_unit sprockets -- cgit v1.2.3 From c48ce6e73d1f0765902779adab3242b5f4a893c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Wed, 26 Jun 2013 14:48:40 +0200 Subject: Move layouts to AV --- actionpack/lib/abstract_controller.rb | 1 - actionpack/lib/action_controller/base.rb | 2 +- actionview/lib/action_view.rb | 1 + actionview/lib/action_view/layouts.rb | 424 +++++++++++++++++++++++++++++++ actionview/lib/action_view/railtie.rb | 6 + 5 files changed, 432 insertions(+), 2 deletions(-) create mode 100644 actionview/lib/action_view/layouts.rb diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index 7ab5af00c3..c905c45b40 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -11,7 +11,6 @@ module AbstractController autoload :Callbacks autoload :Collector autoload :Helpers - autoload :Layouts autoload :Logger autoload :Translation autoload :AssetPaths diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 67d261db77..1f7ce468b3 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -1,3 +1,4 @@ +require "action_view/layouts" require "action_controller/log_subscriber" require "action_controller/metal/params_wrapper" @@ -200,7 +201,6 @@ module ActionController end MODULES = [ - AbstractController::Layouts, AbstractController::Translation, AbstractController::AssetPaths, diff --git a/actionview/lib/action_view.rb b/actionview/lib/action_view.rb index 65cdefe057..c93ef43594 100644 --- a/actionview/lib/action_view.rb +++ b/actionview/lib/action_view.rb @@ -34,6 +34,7 @@ module ActionView autoload :Digestor autoload :Helpers autoload :LookupContext + autoload :Layout autoload :PathSet autoload :RecordIdentifier autoload :Rendering diff --git a/actionview/lib/action_view/layouts.rb b/actionview/lib/action_view/layouts.rb new file mode 100644 index 0000000000..f12aa62124 --- /dev/null +++ b/actionview/lib/action_view/layouts.rb @@ -0,0 +1,424 @@ +require "active_support/core_ext/module/remove_method" + + +module ActionView + # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in + # repeated setups. The inclusion pattern has pages that look like this: + # + # <%= render "shared/header" %> + # Hello World + # <%= render "shared/footer" %> + # + # This approach is a decent way of keeping common structures isolated from the changing content, but it's verbose + # and if you ever want to change the structure of these two includes, you'll have to change all the templates. + # + # With layouts, you can flip it around and have the common structure know where to insert changing content. This means + # that the header and footer are only mentioned in one place, like this: + # + # // The header part of this layout + # <%= yield %> + # // The footer part of this layout + # + # And then you have content pages that look like this: + # + # hello world + # + # At rendering time, the content page is computed and then inserted in the layout, like this: + # + # // The header part of this layout + # hello world + # // The footer part of this layout + # + # == Accessing shared variables + # + # Layouts have access to variables specified in the content pages and vice versa. This allows you to have layouts with + # references that won't materialize before rendering time: + # + #

<%= @page_title %>

+ # <%= yield %> + # + # ...and content pages that fulfill these references _at_ rendering time: + # + # <% @page_title = "Welcome" %> + # Off-world colonies offers you a chance to start a new life + # + # The result after rendering is: + # + #

Welcome

+ # Off-world colonies offers you a chance to start a new life + # + # == Layout assignment + # + # You can either specify a layout declaratively (using the #layout class method) or give + # it the same name as your controller, and place it in app/views/layouts. + # If a subclass does not have a layout specified, it inherits its layout using normal Ruby inheritance. + # + # For instance, if you have PostsController and a template named app/views/layouts/posts.html.erb, + # that template will be used for all actions in PostsController and controllers inheriting + # from PostsController. + # + # If you use a module, for instance Weblog::PostsController, you will need a template named + # app/views/layouts/weblog/posts.html.erb. + # + # Since all your controllers inherit from ApplicationController, they will use + # app/views/layouts/application.html.erb if no other layout is specified + # or provided. + # + # == Inheritance Examples + # + # class BankController < ActionController::Base + # # bank.html.erb exists + # + # class ExchangeController < BankController + # # exchange.html.erb exists + # + # class CurrencyController < BankController + # + # class InformationController < BankController + # layout "information" + # + # class TellerController < InformationController + # # teller.html.erb exists + # + # class EmployeeController < InformationController + # # employee.html.erb exists + # layout nil + # + # class VaultController < BankController + # layout :access_level_layout + # + # class TillController < BankController + # layout false + # + # In these examples, we have three implicit lookup scenarios: + # * The BankController uses the "bank" layout. + # * The ExchangeController uses the "exchange" layout. + # * The CurrencyController inherits the layout from BankController. + # + # However, when a layout is explicitly set, the explicitly set layout wins: + # * The InformationController uses the "information" layout, explicitly set. + # * The TellerController also uses the "information" layout, because the parent explicitly set it. + # * The EmployeeController uses the "employee" layout, because it set the layout to nil, resetting the parent configuration. + # * The VaultController chooses a layout dynamically by calling the access_level_layout method. + # * The TillController does not use a layout at all. + # + # == Types of layouts + # + # Layouts are basically just regular templates, but the name of this template needs not be specified statically. Sometimes + # you want to alternate layouts depending on runtime information, such as whether someone is logged in or not. This can + # be done either by specifying a method reference as a symbol or using an inline method (as a proc). + # + # The method reference is the preferred approach to variable layouts and is used like this: + # + # class WeblogController < ActionController::Base + # layout :writers_and_readers + # + # def index + # # fetching posts + # end + # + # private + # def writers_and_readers + # logged_in? ? "writer_layout" : "reader_layout" + # end + # end + # + # Now when a new request for the index action is processed, the layout will vary depending on whether the person accessing + # is logged in or not. + # + # If you want to use an inline method, such as a proc, do something like this: + # + # class WeblogController < ActionController::Base + # layout proc { |controller| controller.logged_in? ? "writer_layout" : "reader_layout" } + # end + # + # If an argument isn't given to the proc, it's evaluated in the context of + # the current controller anyway. + # + # class WeblogController < ActionController::Base + # layout proc { logged_in? ? "writer_layout" : "reader_layout" } + # end + # + # Of course, the most common way of specifying a layout is still just as a plain template name: + # + # class WeblogController < ActionController::Base + # layout "weblog_standard" + # end + # + # The template will be looked always in app/views/layouts/ folder. But you can point + # layouts folder direct also. layout "layouts/demo" is the same as layout "demo". + # + # Setting the layout to nil forces it to be looked up in the filesystem and fallbacks to the parent behavior if none exists. + # Setting it to nil is useful to re-enable template lookup overriding a previous configuration set in the parent: + # + # class ApplicationController < ActionController::Base + # layout "application" + # end + # + # class PostsController < ApplicationController + # # Will use "application" layout + # end + # + # class CommentsController < ApplicationController + # # Will search for "comments" layout and fallback "application" layout + # layout nil + # end + # + # == Conditional layouts + # + # If you have a layout that by default is applied to all the actions of a controller, you still have the option of rendering + # a given action or set of actions without a layout, or restricting a layout to only a single action or a set of actions. The + # :only and :except options can be passed to the layout call. For example: + # + # class WeblogController < ActionController::Base + # layout "weblog_standard", except: :rss + # + # # ... + # + # end + # + # This will assign "weblog_standard" as the WeblogController's layout for all actions except for the +rss+ action, which will + # be rendered directly, without wrapping a layout around the rendered view. + # + # Both the :only and :except condition can accept an arbitrary number of method references, so + # #except: [ :rss, :text_only ] is valid, as is except: :rss. + # + # == Using a different layout in the action render call + # + # If most of your actions use the same layout, it makes perfect sense to define a controller-wide layout as described above. + # Sometimes you'll have exceptions where one action wants to use a different layout than the rest of the controller. + # You can do this by passing a :layout option to the render call. For example: + # + # class WeblogController < ActionController::Base + # layout "weblog_standard" + # + # def help + # render action: "help", layout: "help" + # end + # end + # + # This will override the controller-wide "weblog_standard" layout, and will render the help action with the "help" layout instead. + module Layouts + extend ActiveSupport::Concern + + include ActionView::Rendering + + included do + class_attribute :_layout, :_layout_conditions, :instance_accessor => false + self._layout = nil + self._layout_conditions = {} + _write_layout_method + end + + delegate :_layout_conditions, to: :class + + module ClassMethods + def inherited(klass) # :nodoc: + super + klass._write_layout_method + end + + # This module is mixed in if layout conditions are provided. This means + # that if no layout conditions are used, this method is not used + module LayoutConditions # :nodoc: + private + + # Determines whether the current action has a layout definition by + # checking the action name against the :only and :except conditions + # set by the layout method. + # + # ==== Returns + # * Boolean - True if the action has a layout definition, false otherwise. + def _conditional_layout? + return unless super + + conditions = _layout_conditions + + if only = conditions[:only] + only.include?(action_name) + elsif except = conditions[:except] + !except.include?(action_name) + else + true + end + end + end + + # Specify the layout to use for this class. + # + # If the specified layout is a: + # String:: the String is the template name + # Symbol:: call the method specified by the symbol, which will return the template name + # false:: There is no layout + # true:: raise an ArgumentError + # nil:: Force default layout behavior with inheritance + # + # ==== Parameters + # * layout - The layout to use. + # + # ==== Options (conditions) + # * :only - A list of actions to apply this layout to. + # * :except - Apply this layout to all actions but this one. + def layout(layout, conditions = {}) + include LayoutConditions unless conditions.empty? + + conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} } + self._layout_conditions = conditions + + self._layout = layout + _write_layout_method + end + + # If no layout is supplied, look for a template named the return + # value of this method. + # + # ==== Returns + # * String - A template name + def _implied_layout_name # :nodoc: + controller_path + end + + # Creates a _layout method to be called by _default_layout . + # + # If a layout is not explicitly mentioned then look for a layout with the controller's name. + # if nothing is found then try same procedure to find super class's layout. + def _write_layout_method # :nodoc: + remove_possible_method(:_layout) + + prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"] + default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}).first || super" + name_clause = if name + default_behavior + else + <<-RUBY + super + RUBY + end + + layout_definition = case _layout + when String + _layout.inspect + when Symbol + <<-RUBY + #{_layout}.tap do |layout| + return #{default_behavior} if layout.nil? + unless layout.is_a?(String) || !layout + raise ArgumentError, "Your layout method :#{_layout} returned \#{layout}. It " \ + "should have returned a String, false, or nil" + end + end + RUBY + when Proc + define_method :_layout_from_proc, &_layout + protected :_layout_from_proc + <<-RUBY + result = _layout_from_proc(#{_layout.arity == 0 ? '' : 'self'}) + return #{default_behavior} if result.nil? + result + RUBY + when false + nil + when true + raise ArgumentError, "Layouts must be specified as a String, Symbol, Proc, false, or nil" + when nil + name_clause + end + + self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def _layout + if _conditional_layout? + #{layout_definition} + else + #{name_clause} + end + end + private :_layout + RUBY + end + end + + def _normalize_options(options) # :nodoc: + super + + if _include_layout?(options) + layout = options.delete(:layout) { :default } + options[:layout] = _layout_for_option(layout) + end + end + + attr_internal_writer :action_has_layout + + def initialize(*) # :nodoc: + @_action_has_layout = true + super + end + + # Controls whether an action should be rendered using a layout. + # If you want to disable any layout settings for the + # current action so that it is rendered without a layout then + # either override this method in your controller to return false + # for that action or set the action_has_layout attribute + # to false before rendering. + def action_has_layout? + @_action_has_layout + end + + private + + def _conditional_layout? + true + end + + # This will be overwritten by _write_layout_method + def _layout; end + + # Determine the layout for a given name, taking into account the name type. + # + # ==== Parameters + # * name - The name of the template + def _layout_for_option(name) + case name + when String then _normalize_layout(name) + when Proc then name + when true then Proc.new { _default_layout(true) } + when :default then Proc.new { _default_layout(false) } + when false, nil then nil + else + raise ArgumentError, + "String, Proc, :default, true, or false, expected for `layout'; you passed #{name.inspect}" + end + end + + def _normalize_layout(value) + value.is_a?(String) && value !~ /\blayouts/ ? "layouts/#{value}" : value + end + + # Returns the default layout for this controller. + # Optionally raises an exception if the layout could not be found. + # + # ==== Parameters + # * require_layout - If set to true and layout is not found, + # an ArgumentError exception is raised (defaults to false) + # + # ==== Returns + # * template - The template object for the default layout (or nil) + def _default_layout(require_layout = false) + begin + value = _layout if action_has_layout? + rescue NameError => e + raise e, "Could not render layout: #{e.message}" + end + + if require_layout && action_has_layout? && !value + raise ArgumentError, + "There was no default layout for #{self.class} in #{view_paths.inspect}" + end + + _normalize_layout(value) + end + + def _include_layout?(options) + (options.keys & [:text, :inline, :partial]).empty? || options.key?(:layout) + end + end +end diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index e80e0ed9b0..a9b33f2ca2 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -35,5 +35,11 @@ module ActionView end end end + + initializer "action_view.setup_action_controller" do |app| + ActiveSupport.on_load(:action_controller) do + ActionController::Base.send(:include, ActionView::Layouts) + end + end end end -- cgit v1.2.3 From 766fa97b457fb2f9903f80aaec640cd1d08a1bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Wed, 26 Jun 2013 15:54:29 +0200 Subject: Hook up AV::Rendering on AV intialization --- actionpack/lib/abstract_controller/base.rb | 2 ++ actionpack/lib/action_controller/metal/rendering.rb | 2 -- actionview/lib/action_view/railtie.rb | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index af5de815bb..8949a9fc78 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -163,6 +163,8 @@ module AbstractController method_for_action(action_name).present? end + ActiveSupport.run_load_hooks(:abstract_controller, self) + private # Returns true if the name can be considered an action because diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index e89542f9f9..f0e8945f11 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -2,8 +2,6 @@ module ActionController module Rendering extend ActiveSupport::Concern - include ActionView::Rendering - # Before processing, set the request formats in current controller formats. def process_action(*) #:nodoc: self.formats = request.formats.map(&:ref).compact diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index a9b33f2ca2..d349af3748 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -36,10 +36,14 @@ module ActionView end end - initializer "action_view.setup_action_controller" do |app| + initializer "action_view.setup_action_pack" do |app| ActiveSupport.on_load(:action_controller) do ActionController::Base.send(:include, ActionView::Layouts) end + + ActiveSupport.on_load(:abstract_controller) do + AbstractController::Base.send(:include, ActionView::Rendering) + end end end end -- cgit v1.2.3 From 769d6dc423d76a6fb1946aab9b717bfa13ffe7f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 27 Jun 2013 14:14:13 +0200 Subject: Revert "Require only path_set && lookup_context instead of whole base" This reverts commit 77bb03df2ca3687b290e9fe77d21007642f0329c. --- actionview/lib/action_view/view_paths.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/actionview/lib/action_view/view_paths.rb b/actionview/lib/action_view/view_paths.rb index 49adc1134f..6c349feb1d 100644 --- a/actionview/lib/action_view/view_paths.rb +++ b/actionview/lib/action_view/view_paths.rb @@ -1,5 +1,4 @@ -require 'action_view/path_set' -require 'action_view/lookup_context' +require 'action_view/base' module ActionView module ViewPaths -- cgit v1.2.3 From 58b338677aa037dc2ba60d9951aaab238abff41c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 27 Jun 2013 14:15:43 +0200 Subject: Fix AV tests, I18nProxy was moved to AV --- actionview/test/template/lookup_context_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionview/test/template/lookup_context_test.rb b/actionview/test/template/lookup_context_test.rb index 073bd14783..203ad6d910 100644 --- a/actionview/test/template/lookup_context_test.rb +++ b/actionview/test/template/lookup_context_test.rb @@ -68,7 +68,7 @@ class LookupContextTest < ActiveSupport::TestCase test "delegates changing the locale to the I18n configuration object if it contains a lookup_context object" do begin - I18n.config = AbstractController::I18nProxy.new(I18n.config, @lookup_context) + I18n.config = ActionView::I18nProxy.new(I18n.config, @lookup_context) @lookup_context.locale = :pt assert_equal :pt, I18n.locale assert_equal :pt, @lookup_context.locale -- cgit v1.2.3 From 757170dca4d2c6e198f4ccc04e3d5de60c614097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 27 Jun 2013 14:44:29 +0200 Subject: Fix eager_autoload for layouts Name was singular, should be plural --- actionview/lib/action_view.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionview/lib/action_view.rb b/actionview/lib/action_view.rb index c93ef43594..a0ba61dd07 100644 --- a/actionview/lib/action_view.rb +++ b/actionview/lib/action_view.rb @@ -34,7 +34,7 @@ module ActionView autoload :Digestor autoload :Helpers autoload :LookupContext - autoload :Layout + autoload :Layouts autoload :PathSet autoload :RecordIdentifier autoload :Rendering -- cgit v1.2.3 From 8e5a7243a1d408476e89a0fe4fd50bfde732e9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 27 Jun 2013 14:45:29 +0200 Subject: Integrate ActionMailer with ActionView --- actionmailer/actionmailer.gemspec | 1 + actionmailer/lib/action_mailer/base.rb | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index c56b6979ef..9b25feaf75 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -20,6 +20,7 @@ Gem::Specification.new do |s| s.requirements << 'none' s.add_dependency 'actionpack', version + s.add_dependency 'actionview', version s.add_dependency 'mail', '~> 2.5.4' end diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index cc3a412221..0928d3a639 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -1,4 +1,5 @@ require 'mail' +require 'action_view/base' require 'action_mailer/collector' require 'active_support/core_ext/string/inflections' require 'active_support/core_ext/hash/except' @@ -361,11 +362,13 @@ module ActionMailer # delivery_method :test. Most useful for unit and functional testing. class Base < AbstractController::Base include DeliveryMethods + abstract! + include ActionView::Rendering + include ActionView::Layouts + include AbstractController::Logger - include AbstractController::Rendering - include AbstractController::Layouts include AbstractController::Helpers include AbstractController::Translation include AbstractController::AssetPaths -- cgit v1.2.3 From 75d38e4364a292d8fddb89ff9959c88ab00ad7e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 27 Jun 2013 14:47:52 +0200 Subject: Do not include AV::Rendering It's already included in Layouts, makes no sense to doubly include it --- actionmailer/lib/action_mailer/base.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 0928d3a639..af4f3cf94b 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -365,7 +365,6 @@ module ActionMailer abstract! - include ActionView::Rendering include ActionView::Layouts include AbstractController::Logger -- cgit v1.2.3 From 8c2c95e5d22d5e1ebade26f6eeaeda5089e4f658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Fri, 28 Jun 2013 16:46:10 +0200 Subject: Fix AP test suite after moving stuff to AV --- actionpack/lib/abstract_controller.rb | 1 + actionpack/lib/action_controller/base.rb | 1 + actionpack/test/abstract/abstract_controller_test.rb | 4 ++-- actionpack/test/abstract/helper_test.rb | 2 +- actionpack/test/abstract/layouts_test.rb | 4 ++-- actionpack/test/abstract/render_test.rb | 2 +- actionpack/test/abstract_unit.rb | 1 + 7 files changed, 9 insertions(+), 6 deletions(-) diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index c905c45b40..909b438a41 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -10,6 +10,7 @@ module AbstractController autoload :Base autoload :Callbacks autoload :Collector + autoload :DoubleRenderError, "abstract_controller/rendering.rb" autoload :Helpers autoload :Logger autoload :Translation diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 1f7ce468b3..ebb7cc2a64 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -201,6 +201,7 @@ module ActionController end MODULES = [ + ActionView::Layouts, AbstractController::Translation, AbstractController::AssetPaths, diff --git a/actionpack/test/abstract/abstract_controller_test.rb b/actionpack/test/abstract/abstract_controller_test.rb index eb9143c8f6..a161188b8e 100644 --- a/actionpack/test/abstract/abstract_controller_test.rb +++ b/actionpack/test/abstract/abstract_controller_test.rb @@ -29,7 +29,7 @@ module AbstractController # Test Render mixin # ==== class RenderingController < AbstractController::Base - include AbstractController::Rendering + include ActionView::Rendering def _prefixes [] @@ -153,7 +153,7 @@ module AbstractController # ==== # self._layout is used when defined class WithLayouts < PrefixedViews - include AbstractController::Layouts + include ActionView::Layouts private def self.layout(formats) diff --git a/actionpack/test/abstract/helper_test.rb b/actionpack/test/abstract/helper_test.rb index bc3e34684c..555669efa5 100644 --- a/actionpack/test/abstract/helper_test.rb +++ b/actionpack/test/abstract/helper_test.rb @@ -6,7 +6,7 @@ module AbstractController module Testing class ControllerWithHelpers < AbstractController::Base - include AbstractController::Rendering + include ActionView::Rendering include AbstractController::Helpers def with_module diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb index 4a05c00f8b..168e40c610 100644 --- a/actionpack/test/abstract/layouts_test.rb +++ b/actionpack/test/abstract/layouts_test.rb @@ -5,8 +5,8 @@ module AbstractControllerTests # Base controller for these tests class Base < AbstractController::Base - include AbstractController::Rendering - include AbstractController::Layouts + include ActionView::Rendering + include ActionView::Layouts abstract! diff --git a/actionpack/test/abstract/render_test.rb b/actionpack/test/abstract/render_test.rb index b9293d1241..56e5f48825 100644 --- a/actionpack/test/abstract/render_test.rb +++ b/actionpack/test/abstract/render_test.rb @@ -4,7 +4,7 @@ module AbstractController module Testing class ControllerRenderer < AbstractController::Base - include AbstractController::Rendering + include ActionView::Rendering def _prefixes %w[renderer] diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 8213997f4e..d4e984f998 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -271,6 +271,7 @@ end module ActionController class Base include ActionController::Testing + include ActionView::Layouts # This stub emulates the Railtie including the URL helpers from a Rails application include SharedTestRoutes.url_helpers include SharedTestRoutes.mounted_helpers -- cgit v1.2.3 From cad8a2018752050dcd536c255f3865c2a8bb30c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Wed, 3 Jul 2013 14:38:20 +0200 Subject: Rename abstract_controller/rendering. to errors.rb Since all rendering stuff was extracted to AV, the only thing that left was single class with error so file name wasn't relevant anymore --- actionpack/lib/abstract_controller.rb | 2 +- actionpack/lib/abstract_controller/errors.rb | 9 +++++++++ actionpack/lib/abstract_controller/rendering.rb | 9 --------- 3 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 actionpack/lib/abstract_controller/errors.rb delete mode 100644 actionpack/lib/abstract_controller/rendering.rb diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index 909b438a41..5c07753075 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -10,7 +10,7 @@ module AbstractController autoload :Base autoload :Callbacks autoload :Collector - autoload :DoubleRenderError, "abstract_controller/rendering.rb" + autoload :DoubleRenderError, "abstract_controller/errors.rb" autoload :Helpers autoload :Logger autoload :Translation diff --git a/actionpack/lib/abstract_controller/errors.rb b/actionpack/lib/abstract_controller/errors.rb new file mode 100644 index 0000000000..8997207550 --- /dev/null +++ b/actionpack/lib/abstract_controller/errors.rb @@ -0,0 +1,9 @@ +module AbstractController + class DoubleRenderError < Error + DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." + + def initialize(message = nil) + super(message || DEFAULT_MESSAGE) + end + end +end diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb deleted file mode 100644 index 8997207550..0000000000 --- a/actionpack/lib/abstract_controller/rendering.rb +++ /dev/null @@ -1,9 +0,0 @@ -module AbstractController - class DoubleRenderError < Error - DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." - - def initialize(message = nil) - super(message || DEFAULT_MESSAGE) - end - end -end -- cgit v1.2.3 From c90971644a90372cfa56dac8b9b2ce709a6e7267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Fri, 5 Jul 2013 13:30:22 +0200 Subject: Revert "Rename abstract_controller/rendering. to errors.rb" This reverts commit 6fe91ec5008838338e54ab8570f7c95ee0cdd8e8. --- actionpack/lib/abstract_controller.rb | 2 +- actionpack/lib/abstract_controller/errors.rb | 9 --------- actionpack/lib/abstract_controller/rendering.rb | 9 +++++++++ 3 files changed, 10 insertions(+), 10 deletions(-) delete mode 100644 actionpack/lib/abstract_controller/errors.rb create mode 100644 actionpack/lib/abstract_controller/rendering.rb diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index 5c07753075..909b438a41 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -10,7 +10,7 @@ module AbstractController autoload :Base autoload :Callbacks autoload :Collector - autoload :DoubleRenderError, "abstract_controller/errors.rb" + autoload :DoubleRenderError, "abstract_controller/rendering.rb" autoload :Helpers autoload :Logger autoload :Translation diff --git a/actionpack/lib/abstract_controller/errors.rb b/actionpack/lib/abstract_controller/errors.rb deleted file mode 100644 index 8997207550..0000000000 --- a/actionpack/lib/abstract_controller/errors.rb +++ /dev/null @@ -1,9 +0,0 @@ -module AbstractController - class DoubleRenderError < Error - DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." - - def initialize(message = nil) - super(message || DEFAULT_MESSAGE) - end - end -end diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb new file mode 100644 index 0000000000..8997207550 --- /dev/null +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -0,0 +1,9 @@ +module AbstractController + class DoubleRenderError < Error + DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." + + def initialize(message = nil) + super(message || DEFAULT_MESSAGE) + end + end +end -- cgit v1.2.3 From 8e3413d41098eca3806ef0bed978d71397e3b1da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Fri, 5 Jul 2013 14:34:39 +0200 Subject: Create AbstractController::Rendering interface This interface should be use when implementing renderers. --- actionpack/lib/abstract_controller.rb | 1 + actionpack/lib/abstract_controller/rendering.rb | 50 ++++++++++++++++++++++ actionpack/lib/action_controller/base.rb | 6 ++- .../test/abstract/abstract_controller_test.rb | 1 + actionpack/test/abstract/helper_test.rb | 3 +- actionpack/test/abstract/layouts_test.rb | 1 + actionpack/test/abstract/render_test.rb | 1 + actionpack/test/abstract_unit.rb | 2 +- .../test/controller/mime/respond_with_test.rb | 1 + actionpack/test/controller/render_test.rb | 2 + actionview/lib/action_view/rendering.rb | 21 ++------- 11 files changed, 69 insertions(+), 20 deletions(-) diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index 909b438a41..52f16b7bec 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -13,6 +13,7 @@ module AbstractController autoload :DoubleRenderError, "abstract_controller/rendering.rb" autoload :Helpers autoload :Logger + autoload :Rendering autoload :Translation autoload :AssetPaths autoload :UrlFor diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 8997207550..6e5b172203 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -6,4 +6,54 @@ module AbstractController super(message || DEFAULT_MESSAGE) end end + + module Rendering + # Raw rendering of a template to a string. + # + # It is similar to render, except that it does not + # set the response_body and it should be guaranteed + # to always return a string. + # + # If a component extends the semantics of response_body + # (as Action Controller extends it to be anything that + # responds to the method each), this method needs to be + # overridden in order to still return a string. + # :api: plugin + def render_to_string(*args, &block) + end + + # Raw rendering of a template. + # :api: plugin + def render_to_body(options = {}) + end + + def render(*args, &block) + end + + # This method should return a hash with assigns. + # You can overwrite this configuration per controller. + # :api: public + def view_assigns + {} + end + + # Normalize args by converting render "foo" to render :action => "foo" and + # render "foo/bar" to render :file => "foo/bar". + # :api: plugin + def _normalize_args(action=nil, options={}) + options + end + + # Normalize options. + # :api: plugin + def _normalize_options(options) + options + end + + # Process extra options. + # :api: plugin + def _process_options(options) + options + end + end end diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index ebb7cc2a64..82a7366f6b 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -161,7 +161,11 @@ module ActionController # render action: "overthere" # won't be called if monkeys is nil # end # - class Base < Metal + metal = Class.new(Metal) do + include AbstractController::Rendering + end + + class Base < metal abstract! # We document the request and response methods here because albeit they are diff --git a/actionpack/test/abstract/abstract_controller_test.rb b/actionpack/test/abstract/abstract_controller_test.rb index a161188b8e..40d3b17131 100644 --- a/actionpack/test/abstract/abstract_controller_test.rb +++ b/actionpack/test/abstract/abstract_controller_test.rb @@ -29,6 +29,7 @@ module AbstractController # Test Render mixin # ==== class RenderingController < AbstractController::Base + include AbstractController::Rendering include ActionView::Rendering def _prefixes diff --git a/actionpack/test/abstract/helper_test.rb b/actionpack/test/abstract/helper_test.rb index 555669efa5..a596ebe6f7 100644 --- a/actionpack/test/abstract/helper_test.rb +++ b/actionpack/test/abstract/helper_test.rb @@ -6,8 +6,9 @@ module AbstractController module Testing class ControllerWithHelpers < AbstractController::Base - include ActionView::Rendering include AbstractController::Helpers + include AbstractController::Rendering + include ActionView::Rendering def with_module render :inline => "Module <%= included_method %>" diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb index 168e40c610..c79cb50fd7 100644 --- a/actionpack/test/abstract/layouts_test.rb +++ b/actionpack/test/abstract/layouts_test.rb @@ -5,6 +5,7 @@ module AbstractControllerTests # Base controller for these tests class Base < AbstractController::Base + include AbstractController::Rendering include ActionView::Rendering include ActionView::Layouts diff --git a/actionpack/test/abstract/render_test.rb b/actionpack/test/abstract/render_test.rb index 56e5f48825..f9d8c916d9 100644 --- a/actionpack/test/abstract/render_test.rb +++ b/actionpack/test/abstract/render_test.rb @@ -4,6 +4,7 @@ module AbstractController module Testing class ControllerRenderer < AbstractController::Base + include AbstractController::Rendering include ActionView::Rendering def _prefixes diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index d4e984f998..49dd891e4c 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -271,7 +271,6 @@ end module ActionController class Base include ActionController::Testing - include ActionView::Layouts # This stub emulates the Railtie including the URL helpers from a Rails application include SharedTestRoutes.url_helpers include SharedTestRoutes.mounted_helpers @@ -291,6 +290,7 @@ module ActionController end end + class ::ApplicationController < ActionController::Base end diff --git a/actionpack/test/controller/mime/respond_with_test.rb b/actionpack/test/controller/mime/respond_with_test.rb index 29ddbff8d4..76af9e3414 100644 --- a/actionpack/test/controller/mime/respond_with_test.rb +++ b/actionpack/test/controller/mime/respond_with_test.rb @@ -337,6 +337,7 @@ class RespondWithControllerTest < ActionController::TestCase errors = { :name => :invalid } Customer.any_instance.stubs(:errors).returns(errors) put :using_resource + assert_equal "text/html", @response.content_type assert_equal 200, @response.status assert_equal "Edit world!\n", @response.body diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index fd835795c0..bacc93a936 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -755,6 +755,8 @@ class TestController < ActionController::Base end class MetalTestController < ActionController::Metal + include AbstractController::Rendering + include ActionView::Rendering include ActionController::Rendering def accessing_logger_in_template diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index 9bade857be..6453b0543a 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -83,21 +83,11 @@ module ActionView # Normalize arguments, options and then delegates render_to_body and # sticks the result in self.response_body. def render(*args, &block) + super options = _normalize_render(*args, &block) self.response_body = render_to_body(options) end - # Raw rendering of a template to a string. - # - # It is similar to render, except that it does not - # set the response_body and it should be guaranteed - # to always return a string. - # - # If a component extends the semantics of response_body - # (as Action Controller extends it to be anything that - # responds to the method each), this method needs to be - # overridden in order to still return a string. - # :api: plugin def render_to_string(*args, &block) options = _normalize_render(*args, &block) render_to_body(options) @@ -126,7 +116,7 @@ module ActionView # You can overwrite this configuration per controller. # :api: public def view_assigns - hash = {} + hash = super variables = instance_variables variables -= protected_instance_variables variables -= DEFAULT_PROTECTED_INSTANCE_VARIABLES @@ -148,6 +138,7 @@ module ActionView # render "foo/bar" to render :file => "foo/bar". # :api: plugin def _normalize_args(action=nil, options={}) + options = super(action, options) case action when NilClass when Hash @@ -166,6 +157,7 @@ module ActionView # Normalize options. # :api: plugin def _normalize_options(options) + options = super(options) if options[:partial] == true options[:partial] = action_name end @@ -177,10 +169,5 @@ module ActionView options[:template] ||= (options[:action] || action_name).to_s options end - - # Process extra options. - # :api: plugin - def _process_options(options) - end end end -- cgit v1.2.3 From 8b8111aeeab1f9537b07d8e344a420ed6ab01b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 11 Jul 2013 00:11:33 +0200 Subject: Remove 'api plugin' from docs AbstractController::Rendering is module which defines thie api --- actionview/lib/action_view/rendering.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index 6453b0543a..925ae14925 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -94,7 +94,6 @@ module ActionView end # Raw rendering of a template. - # :api: plugin def render_to_body(options = {}) _process_options(options) _render_template(options) @@ -136,7 +135,6 @@ module ActionView # Normalize args by converting render "foo" to render :action => "foo" and # render "foo/bar" to render :file => "foo/bar". - # :api: plugin def _normalize_args(action=nil, options={}) options = super(action, options) case action @@ -155,7 +153,6 @@ module ActionView end # Normalize options. - # :api: plugin def _normalize_options(options) options = super(options) if options[:partial] == true -- cgit v1.2.3 From 80b91610f8462e4a347d602204cb4be9f1c37cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 11 Jul 2013 00:23:44 +0200 Subject: No need for .rb extension --- actionpack/lib/abstract_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index 52f16b7bec..fe9802e395 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -10,7 +10,7 @@ module AbstractController autoload :Base autoload :Callbacks autoload :Collector - autoload :DoubleRenderError, "abstract_controller/rendering.rb" + autoload :DoubleRenderError, "abstract_controller/rendering" autoload :Helpers autoload :Logger autoload :Rendering -- cgit v1.2.3 From 3419ac26e97e38c6356c29672f5054ad072c01af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 11 Jul 2013 14:15:52 +0200 Subject: Include AbsC::Rendering interface in ActionMailer --- actionmailer/lib/action_mailer/base.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index af4f3cf94b..9f3dbe794a 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -4,6 +4,7 @@ require 'action_mailer/collector' require 'active_support/core_ext/string/inflections' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/module/anonymous' + require 'action_mailer/log_subscriber' module ActionMailer @@ -365,6 +366,8 @@ module ActionMailer abstract! + include AbstractController::Rendering + include ActionView::Layouts include AbstractController::Logger -- cgit v1.2.3 From 49608f7b81314fea0487311f57b41b721c375339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 11 Jul 2013 14:18:06 +0200 Subject: Move protected_instance_variables & view_assigns to AbstractController --- actionpack/lib/abstract_controller/rendering.rb | 21 ++++++++++++++++++++- actionview/lib/action_view/rendering.rb | 19 ++++--------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 6e5b172203..bdecc37063 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -1,3 +1,6 @@ +require 'active_support/concern' +require 'active_support/core_ext/class/attribute' + module AbstractController class DoubleRenderError < Error DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." @@ -8,6 +11,17 @@ module AbstractController end module Rendering + extend ActiveSupport::Concern + + included do + class_attribute :protected_instance_variables + self.protected_instance_variables = [] + end + + def default_protected_instance_vars + [:@_action_name, :@_response_body, :@_formats, :@_prefixes, :@_config] + end + # Raw rendering of a template to a string. # # It is similar to render, except that it does not @@ -34,7 +48,12 @@ module AbstractController # You can overwrite this configuration per controller. # :api: public def view_assigns - {} + hash = {} + variables = instance_variables + variables -= protected_instance_variables + variables -= default_protected_instance_vars + variables.each { |name| hash[name[1..-1]] = instance_variable_get(name) } + hash end # Normalize args by converting render "foo" to render :action => "foo" and diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index 925ae14925..f4afb63d5f 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -23,11 +23,6 @@ module ActionView extend ActiveSupport::Concern include ActionView::ViewPaths - included do - class_attribute :protected_instance_variables - self.protected_instance_variables = [] - end - # Overwrite process to setup I18n proxy. def process(*) #:nodoc: old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context) @@ -106,21 +101,15 @@ module ActionView view_renderer.render(view_context, options) end - DEFAULT_PROTECTED_INSTANCE_VARIABLES = [ - :@_action_name, :@_response_body, :@_formats, :@_prefixes, :@_config, - :@_view_context_class, :@_view_renderer, :@_lookup_context - ] + def default_protected_instance_vars + super + [:@_view_context_class, :@_view_renderer, :@_lookup_context] + end # This method should return a hash with assigns. # You can overwrite this configuration per controller. # :api: public def view_assigns - hash = super - variables = instance_variables - variables -= protected_instance_variables - variables -= DEFAULT_PROTECTED_INSTANCE_VARIABLES - variables.each { |name| hash[name[1..-1]] = instance_variable_get(name) } - hash + super end private -- cgit v1.2.3 From b9b48c780649c40dbec0758e2ff3e9f14b2bf3f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 11 Jul 2013 16:35:36 +0200 Subject: Remove abstract_controller load hooks --- actionpack/lib/abstract_controller/base.rb | 2 -- actionview/lib/action_view/railtie.rb | 4 ---- 2 files changed, 6 deletions(-) diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index 8949a9fc78..af5de815bb 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -163,8 +163,6 @@ module AbstractController method_for_action(action_name).present? end - ActiveSupport.run_load_hooks(:abstract_controller, self) - private # Returns true if the name can be considered an action because diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index d349af3748..e94f71ae74 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -40,10 +40,6 @@ module ActionView ActiveSupport.on_load(:action_controller) do ActionController::Base.send(:include, ActionView::Layouts) end - - ActiveSupport.on_load(:abstract_controller) do - AbstractController::Base.send(:include, ActionView::Rendering) - end end end end -- cgit v1.2.3 From fae8f72076c7feef271176636aef9e2dca3930fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Fri, 12 Jul 2013 09:31:12 +0200 Subject: Move anonymous class to the top, add documentation --- actionpack/lib/action_controller/base.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 82a7366f6b..b785d52832 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -3,6 +3,15 @@ require "action_controller/log_subscriber" require "action_controller/metal/params_wrapper" module ActionController + # The metal anonymous class is simple workaround the ordering issues there are with modules. + # They need to be included in specyfic order which makes it impossible for 3rd party libs (like ActiveRecord) + # to hook up with its own functionality. Having anonymous super class type of Metal with AbstractController::Rendering + # included, allows us to include ActionView::Rendering (which implements AbstractController::Rendering interface) + # after the AbstractController::Rendering and before ActionController::Rendering. + metal = Class.new(Metal) do + include AbstractController::Rendering + end + # Action Controllers are the core of a web request in \Rails. They are made up of one or more actions that are executed # on request and then either it renders a template or redirects to another action. An action is defined as a public method # on the controller, which will automatically be made accessible to the web-server through \Rails Routes. @@ -161,10 +170,6 @@ module ActionController # render action: "overthere" # won't be called if monkeys is nil # end # - metal = Class.new(Metal) do - include AbstractController::Rendering - end - class Base < metal abstract! -- cgit v1.2.3 From d6363aa1805bed920e404035aae7138421902d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Fri, 12 Jul 2013 13:01:10 +0200 Subject: Code formatting & typo fixes --- actionpack/lib/abstract_controller/rendering.rb | 2 +- actionpack/lib/action_controller/base.rb | 2 +- actionview/lib/action_view/rendering.rb | 70 ++++++++++++------------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index bdecc37063..6bfe0a361f 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -11,7 +11,7 @@ module AbstractController end module Rendering - extend ActiveSupport::Concern + extend ActiveSupport::Concern included do class_attribute :protected_instance_variables diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index b785d52832..80b5f118ff 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -4,7 +4,7 @@ require "action_controller/metal/params_wrapper" module ActionController # The metal anonymous class is simple workaround the ordering issues there are with modules. - # They need to be included in specyfic order which makes it impossible for 3rd party libs (like ActiveRecord) + # They need to be included in specific order which makes it impossible for 3rd party libs (like ActiveRecord) # to hook up with its own functionality. Having anonymous super class type of Metal with AbstractController::Rendering # included, allows us to include ActionView::Rendering (which implements AbstractController::Rendering interface) # after the AbstractController::Rendering and before ActionController::Rendering. diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index f4afb63d5f..0ec0c0f0d3 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -114,46 +114,46 @@ module ActionView private - # Normalize args and options. - # :api: private - def _normalize_render(*args, &block) - options = _normalize_args(*args, &block) - _normalize_options(options) - options - end - - # Normalize args by converting render "foo" to render :action => "foo" and - # render "foo/bar" to render :file => "foo/bar". - def _normalize_args(action=nil, options={}) - options = super(action, options) - case action - when NilClass - when Hash - options = action - when String, Symbol - action = action.to_s - key = action.include?(?/) ? :file : :action - options[key] = action - else - options[:partial] = action + # Normalize args and options. + # :api: private + def _normalize_render(*args, &block) + options = _normalize_args(*args, &block) + _normalize_options(options) + options end - options - end + # Normalize args by converting render "foo" to render :action => "foo" and + # render "foo/bar" to render :file => "foo/bar". + def _normalize_args(action=nil, options={}) + options = super(action, options) + case action + when NilClass + when Hash + options = action + when String, Symbol + action = action.to_s + key = action.include?(?/) ? :file : :action + options[key] = action + else + options[:partial] = action + end - # Normalize options. - def _normalize_options(options) - options = super(options) - if options[:partial] == true - options[:partial] = action_name + options end - if (options.keys & [:partial, :file, :template]).empty? - options[:prefixes] ||= _prefixes - end + # Normalize options. + def _normalize_options(options) + options = super(options) + if options[:partial] == true + options[:partial] = action_name + end - options[:template] ||= (options[:action] || action_name).to_s - options - end + if (options.keys & [:partial, :file, :template]).empty? + options[:prefixes] ||= _prefixes + end + + options[:template] ||= (options[:action] || action_name).to_s + options + end end end -- cgit v1.2.3 From 3fd2e724770810b5d5e8941b2f3861c4e859c517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 16 Jul 2013 15:25:25 +0200 Subject: Load AV::Layouts dynamicly via railties --- actionpack/lib/action_controller/base.rb | 1 - actionpack/lib/action_controller/metal/streaming.rb | 2 -- actionpack/test/abstract_unit.rb | 2 ++ actionview/lib/action_view/railtie.rb | 2 +- actionview/test/abstract_unit.rb | 2 ++ 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 80b5f118ff..ff0a7bf6ce 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -210,7 +210,6 @@ module ActionController end MODULES = [ - ActionView::Layouts, AbstractController::Translation, AbstractController::AssetPaths, diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb index 2c86d7136c..b017415486 100644 --- a/actionpack/lib/action_controller/metal/streaming.rb +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -193,8 +193,6 @@ module ActionController #:nodoc: module Streaming extend ActiveSupport::Concern - include ActionView::Rendering - protected # Set proper cache control and transfer encoding when streaming diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 49dd891e4c..5b2264de14 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -268,6 +268,8 @@ class Rack::TestCase < ActionDispatch::IntegrationTest end end +ActionController::Base.superclass.send(:include, ActionView::Layouts) + module ActionController class Base include ActionController::Testing diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index e94f71ae74..d05c2e4c67 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -38,7 +38,7 @@ module ActionView initializer "action_view.setup_action_pack" do |app| ActiveSupport.on_load(:action_controller) do - ActionController::Base.send(:include, ActionView::Layouts) + ActionController::Base.superclass.send(:include, ActionView::Layouts) end end end diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb index 8213997f4e..dc1b29482b 100644 --- a/actionview/test/abstract_unit.rb +++ b/actionview/test/abstract_unit.rb @@ -268,6 +268,8 @@ class Rack::TestCase < ActionDispatch::IntegrationTest end end +ActionController::Base.superclass.send(:include, ActionView::Layouts) + module ActionController class Base include ActionController::Testing -- cgit v1.2.3 From 977c60eeeaaeec694d71d2b3baadd372f19f0b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 16 Jul 2013 11:39:13 +0200 Subject: Remove view_assigns from AV It wasn't adding anything, just invoking super --- actionview/lib/action_view/rendering.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index 0ec0c0f0d3..ee7cc4e470 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -105,13 +105,6 @@ module ActionView super + [:@_view_context_class, :@_view_renderer, :@_lookup_context] end - # This method should return a hash with assigns. - # You can overwrite this configuration per controller. - # :api: public - def view_assigns - super - end - private # Normalize args and options. -- cgit v1.2.3 From e33fc9288e4204f6726225951134427326bf1c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 16 Jul 2013 15:58:22 +0200 Subject: Indent protected methods [ci skip] --- .../lib/action_controller/metal/streaming.rb | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb index b017415486..62d5931b45 100644 --- a/actionpack/lib/action_controller/metal/streaming.rb +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -195,27 +195,27 @@ module ActionController #:nodoc: protected - # Set proper cache control and transfer encoding when streaming - def _process_options(options) #:nodoc: - super - if options[:stream] - if env["HTTP_VERSION"] == "HTTP/1.0" - options.delete(:stream) - else - headers["Cache-Control"] ||= "no-cache" - headers["Transfer-Encoding"] = "chunked" - headers.delete("Content-Length") + # Set proper cache control and transfer encoding when streaming + def _process_options(options) #:nodoc: + super + if options[:stream] + if env["HTTP_VERSION"] == "HTTP/1.0" + options.delete(:stream) + else + headers["Cache-Control"] ||= "no-cache" + headers["Transfer-Encoding"] = "chunked" + headers.delete("Content-Length") + end end end - end - # Call render_body if we are streaming instead of usual +render+. - def _render_template(options) #:nodoc: - if options.delete(:stream) - Rack::Chunked::Body.new view_renderer.render_body(view_context, options) - else - super + # Call render_body if we are streaming instead of usual +render+. + def _render_template(options) #:nodoc: + if options.delete(:stream) + Rack::Chunked::Body.new view_renderer.render_body(view_context, options) + else + super + end end - end end end -- cgit v1.2.3 From 81e5be0692205bfee2bb87fc5f3377602c72fb70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 16 Jul 2013 15:58:50 +0200 Subject: Remove unused in AV fixture-controllers --- actionview/test/abstract_unit.rb | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb index dc1b29482b..40642bf705 100644 --- a/actionview/test/abstract_unit.rb +++ b/actionview/test/abstract_unit.rb @@ -353,32 +353,3 @@ module RoutingTestHelpers end end -class ResourcesController < ActionController::Base - def index() render :nothing => true end - alias_method :show, :index -end - -class ThreadsController < ResourcesController; end -class MessagesController < ResourcesController; end -class CommentsController < ResourcesController; end -class ReviewsController < ResourcesController; end -class AuthorsController < ResourcesController; end -class LogosController < ResourcesController; end - -class AccountsController < ResourcesController; end -class AdminController < ResourcesController; end -class ProductsController < ResourcesController; end -class ImagesController < ResourcesController; end -class PreferencesController < ResourcesController; end - -module Backoffice - class ProductsController < ResourcesController; end - class TagsController < ResourcesController; end - class ManufacturersController < ResourcesController; end - class ImagesController < ResourcesController; end - - module Admin - class ProductsController < ResourcesController; end - class ImagesController < ResourcesController; end - end -end -- cgit v1.2.3 From fc118d0b41ecb6b7c900554822ffdcbf149d75b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 16 Jul 2013 16:07:38 +0200 Subject: Remove unused ActionDispatch::RoutingVerbs --- actionview/test/abstract_unit.rb | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb index 40642bf705..149a253818 100644 --- a/actionview/test/abstract_unit.rb +++ b/actionview/test/abstract_unit.rb @@ -268,6 +268,7 @@ class Rack::TestCase < ActionDispatch::IntegrationTest end end +# Emulate AV railtie. ActionController::Base.superclass.send(:include, ActionView::Layouts) module ActionController @@ -332,21 +333,6 @@ module ActionDispatch end end -module ActionDispatch - module RoutingVerbs - def get(uri_or_host, path = nil) - host = uri_or_host.host unless path - path ||= uri_or_host.path - - params = {'PATH_INFO' => path, - 'REQUEST_METHOD' => 'GET', - 'HTTP_HOST' => host} - - routes.call(params)[2].join - end - end -end - module RoutingTestHelpers def url_for(set, options, recall = nil) set.send(:url_for, options.merge(:only_path => true, :_recall => recall)) -- cgit v1.2.3 From 087c66d18337415d0ff5e46f63a9e1fd32afb13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 16 Jul 2013 16:11:43 +0200 Subject: Remove ApplicationController & RoutingTestHelpers --- actionview/test/abstract_unit.rb | 9 --------- 1 file changed, 9 deletions(-) diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb index 149a253818..04598e4080 100644 --- a/actionview/test/abstract_unit.rb +++ b/actionview/test/abstract_unit.rb @@ -293,9 +293,6 @@ module ActionController end end -class ::ApplicationController < ActionController::Base -end - module ActionView class TestCase # Must repeat the setup because AV::TestCase is a duplication @@ -333,9 +330,3 @@ module ActionDispatch end end -module RoutingTestHelpers - def url_for(set, options, recall = nil) - set.send(:url_for, options.merge(:only_path => true, :_recall => recall)) - end -end - -- cgit v1.2.3 From 37d77f6b9ddc989f4ad9a0b4be5e2143efafcf9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 16 Jul 2013 16:15:13 +0200 Subject: Remove AV::TestCase from AP --- actionpack/test/abstract_unit.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 5b2264de14..c3496a8b6f 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -296,14 +296,6 @@ end class ::ApplicationController < ActionController::Base end -module ActionView - class TestCase - # Must repeat the setup because AV::TestCase is a duplication - # of AC::TestCase - include ActionDispatch::SharedRoutes - end -end - class Workshop extend ActiveModel::Naming include ActiveModel::Conversion -- cgit v1.2.3 From 21c5f2845de42fb2f5feee47d4270c18a4a4d5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 16 Jul 2013 16:25:13 +0200 Subject: Remove RenderERBUtils from AP (only AV use it) --- actionpack/test/abstract_unit.rb | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index c3496a8b6f..a0d90f7eee 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -64,28 +64,6 @@ module RackTestUtils extend self end -module RenderERBUtils - def view - @view ||= begin - path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH) - view_paths = ActionView::PathSet.new([path]) - ActionView::Base.new(view_paths) - end - end - - def render_erb(string) - @virtual_path = nil - - template = ActionView::Template.new( - string.strip, - "test template", - ActionView::Template::Handlers::ERB, - {}) - - template.render(self, {}).strip - end -end - SharedTestRoutes = ActionDispatch::Routing::RouteSet.new module ActionDispatch -- cgit v1.2.3 From 43ce8265a18381a5dcea39fbdf612b9b2b9922e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Wed, 17 Jul 2013 14:53:57 +0200 Subject: Don not require AC::Caching --- actionview/test/abstract_unit.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb index 04598e4080..e4d0b53b59 100644 --- a/actionview/test/abstract_unit.rb +++ b/actionview/test/abstract_unit.rb @@ -24,7 +24,6 @@ require 'action_dispatch' require 'active_support/dependencies' require 'active_model' require 'active_record' -require 'action_controller/caching' require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late -- cgit v1.2.3 From 2a25c4ce6da6ea23ebdf44e7eb2d2441dbea20a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Wed, 17 Jul 2013 15:08:10 +0200 Subject: Do not silance mail gem warnings. I doesn't have any at the moment --- actionmailer/test/abstract_unit.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb index ed8cf72cd0..bfa1302d79 100644 --- a/actionmailer/test/abstract_unit.rb +++ b/actionmailer/test/abstract_unit.rb @@ -11,11 +11,7 @@ end require 'active_support/testing/autorun' require 'action_mailer' require 'action_mailer/test_case' - -silence_warnings do - # These external dependencies have warnings :/ - require 'mail' -end +require 'mail' # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true -- cgit v1.2.3 From d1760253f5a5c26b8b1d0f38f4f288d759fbb306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Wed, 17 Jul 2013 15:13:16 +0200 Subject: Load AV::Layout to AM::Base in railties --- actionmailer/lib/action_mailer/base.rb | 2 -- actionmailer/test/abstract_unit.rb | 3 +++ actionmailer/test/i18n_with_controller_test.rb | 4 ++++ actionpack/test/controller/assert_select_test.rb | 3 +++ actionview/lib/action_view/railtie.rb | 6 ++++++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 9f3dbe794a..fba2e00166 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -368,8 +368,6 @@ module ActionMailer include AbstractController::Rendering - include ActionView::Layouts - include AbstractController::Logger include AbstractController::Helpers include AbstractController::Translation diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb index bfa1302d79..1890853952 100644 --- a/actionmailer/test/abstract_unit.rb +++ b/actionmailer/test/abstract_unit.rb @@ -13,6 +13,9 @@ require 'action_mailer' require 'action_mailer/test_case' require 'mail' +# Emulate AV railtie +ActionMailer::Base.send(:include, ActionView::Layouts) + # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true diff --git a/actionmailer/test/i18n_with_controller_test.rb b/actionmailer/test/i18n_with_controller_test.rb index a3e93c9c31..ab5eaaa9d5 100644 --- a/actionmailer/test/i18n_with_controller_test.rb +++ b/actionmailer/test/i18n_with_controller_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'action_view' require 'action_controller' class I18nTestMailer < ActionMailer::Base @@ -14,6 +15,9 @@ class I18nTestMailer < ActionMailer::Base end end +# Emulate AV railtie +ActionController::Base.superclass.send(:include, ActionView::Layouts) + class TestController < ActionController::Base def send_mail I18nTestMailer.mail_with_i18n_subject("test@localhost").deliver diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb index 3d667f0a2f..114bbf3c22 100644 --- a/actionpack/test/controller/assert_select_test.rb +++ b/actionpack/test/controller/assert_select_test.rb @@ -8,6 +8,9 @@ require 'abstract_unit' require 'controller/fake_controllers' require 'action_mailer' +require 'action_view' + +ActionMailer::Base.send(:include, ActionView::Layouts) ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH class AssertSelectTest < ActionController::TestCase diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index d05c2e4c67..d9704b59c1 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -41,5 +41,11 @@ module ActionView ActionController::Base.superclass.send(:include, ActionView::Layouts) end end + + initializer "action_view.setup_action_mailer" do |app| + ActiveSupport.on_load(:action_mailer) do + ActionMailer::Base.send(:include, ActionView::Layouts) + end + end end end -- cgit v1.2.3 From b068e20b35797aa6deaa377a48c990759734f515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Wed, 17 Jul 2013 18:02:26 +0200 Subject: Include AV::Layouts before setting view_paths --- actionview/lib/action_view/railtie.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index d9704b59c1..8382023e06 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -36,13 +36,13 @@ module ActionView end end - initializer "action_view.setup_action_pack" do |app| + initializer "action_view.setup_action_pack", before: :add_view_paths do |app| ActiveSupport.on_load(:action_controller) do ActionController::Base.superclass.send(:include, ActionView::Layouts) end end - initializer "action_view.setup_action_mailer" do |app| + initializer "action_view.setup_action_mailer", before: :add_view_paths do |app| ActiveSupport.on_load(:action_mailer) do ActionMailer::Base.send(:include, ActionView::Layouts) end -- cgit v1.2.3 From 718332536c4f6c715a7b77f68749e4c75f8a6eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 18 Jul 2013 17:07:28 +0200 Subject: Fix railtie tests --- railties/test/rails_info_controller_test.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb index a9b237d0a5..e45a5228a1 100644 --- a/railties/test/rails_info_controller_test.rb +++ b/railties/test/rails_info_controller_test.rb @@ -1,5 +1,7 @@ require 'abstract_unit' +ActionController::Base.superclass.send(:include, ActionView::Layouts) + module ActionController class Base include ActionController::Testing -- cgit v1.2.3 From 1656f58f073582e56184d40584f2ce893ab57497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Fri, 19 Jul 2013 12:02:09 +0200 Subject: Improve AV::Rendering docs --- actionpack/lib/abstract_controller/rendering.rb | 3 +++ actionview/lib/action_view/rendering.rb | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 6bfe0a361f..93ded404d6 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -41,6 +41,9 @@ module AbstractController def render_to_body(options = {}) end + # Normalize arguments, options and then delegates render_to_body and + # sticks the result in self.response_body. + # :api: public def render(*args, &block) end diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index ee7cc4e470..9d8f316a11 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -71,24 +71,28 @@ module ActionView end # Returns an object that is able to render templates. + # :api: private def view_renderer @_view_renderer ||= ActionView::Renderer.new(lookup_context) end - # Normalize arguments, options and then delegates render_to_body and - # sticks the result in self.response_body. + # Render template to response_body + # :api: public def render(*args, &block) super options = _normalize_render(*args, &block) self.response_body = render_to_body(options) end + # Raw rendering of a template to a string. + # :api: public def render_to_string(*args, &block) options = _normalize_render(*args, &block) render_to_body(options) end # Raw rendering of a template. + # :api: public def render_to_body(options = {}) _process_options(options) _render_template(options) @@ -117,6 +121,7 @@ module ActionView # Normalize args by converting render "foo" to render :action => "foo" and # render "foo/bar" to render :file => "foo/bar". + # :api: private def _normalize_args(action=nil, options={}) options = super(action, options) case action @@ -135,6 +140,7 @@ module ActionView end # Normalize options. + # :api: private def _normalize_options(options) options = super(options) if options[:partial] == true -- cgit v1.2.3 From 98ec4ebfe730438024b95bca904fe324740396ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Fri, 19 Jul 2013 12:03:20 +0200 Subject: Pass args to render's super method --- actionview/lib/action_view/rendering.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index 9d8f316a11..ce43d1a180 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -79,7 +79,8 @@ module ActionView # Render template to response_body # :api: public def render(*args, &block) - super + super(*args, &block) + options = _normalize_render(*args, &block) self.response_body = render_to_body(options) end -- cgit v1.2.3 From 0b4507a26f7c4807ea14ce70c41033c9868f83e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 23 Jul 2013 15:06:29 +0200 Subject: Use concat to avoid allocating additional array --- actionview/lib/action_view/rendering.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index ce43d1a180..e3d0beade3 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -107,7 +107,7 @@ module ActionView end def default_protected_instance_vars - super + [:@_view_context_class, :@_view_renderer, :@_lookup_context] + super.concat([:@_view_context_class, :@_view_renderer, :@_lookup_context]) end private -- cgit v1.2.3 From cb2d671cb884a7cfeb991ce5af5d7e1047685dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 23 Jul 2013 18:50:22 +0200 Subject: Move setting content_type to AV --- actionpack/lib/action_controller/metal/rendering.rb | 1 - actionview/lib/action_view/railtie.rb | 2 +- actionview/lib/action_view/rendering.rb | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index f0e8945f11..cdc63d67a3 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -12,7 +12,6 @@ module ActionController def render(*args) #:nodoc: raise ::AbstractController::DoubleRenderError if response_body super - self.content_type ||= Mime[lookup_context.rendered_format].to_s response_body end diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index 8382023e06..441bdccd84 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -38,7 +38,7 @@ module ActionView initializer "action_view.setup_action_pack", before: :add_view_paths do |app| ActiveSupport.on_load(:action_controller) do - ActionController::Base.superclass.send(:include, ActionView::Layouts) + #ActionController::Base.superclass.send(:include, ActionView::Layouts) end end diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index e3d0beade3..0db469766c 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -82,6 +82,8 @@ module ActionView super(*args, &block) options = _normalize_render(*args, &block) + + self.content_type ||= Mime[lookup_context.rendered_format].to_s self.response_body = render_to_body(options) end -- cgit v1.2.3 From e9f06b2ac151be1957395076f55cbfa9979bf2a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 25 Jul 2013 14:02:17 +0200 Subject: Change documentation of metal anonymous class Make it clearer [ci skip] --- actionpack/lib/action_controller/base.rb | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index ff0a7bf6ce..dc880cd866 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -3,11 +3,16 @@ require "action_controller/log_subscriber" require "action_controller/metal/params_wrapper" module ActionController - # The metal anonymous class is simple workaround the ordering issues there are with modules. - # They need to be included in specific order which makes it impossible for 3rd party libs (like ActiveRecord) - # to hook up with its own functionality. Having anonymous super class type of Metal with AbstractController::Rendering - # included, allows us to include ActionView::Rendering (which implements AbstractController::Rendering interface) - # after the AbstractController::Rendering and before ActionController::Rendering. + # The metal anonymous class was introduced to solve issue with including modules in ActionController::Base. + # Modules needes to be included in particluar order. First wee need to have AbstractController::Rendering included, + # next we should include actuall implementation which would be for example ActionView::Rendering and after that + # ActionController::Rendering. This order must be preserved and as we want to have middle module included dynamicaly + # metal class was introduced. It has AbstractController::Rendering included and is parent class of + # ActionController::Base which includes ActionController::Rendering. If we include ActionView::Rendering + # beetween them to perserve the required order, we can simply do this by: + # + # ActionController::Base.superclass.send(:include, ActionView::Rendering) + # metal = Class.new(Metal) do include AbstractController::Rendering end -- cgit v1.2.3 From 839938e3deaa4b0f3c1f5e6b46e398a1a46ecf5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 25 Jul 2013 14:04:52 +0200 Subject: Revert "Move setting content_type to AV" This reverts commit f4d602aff6cec80304b131ecfcc2676d0304f0cc. --- actionpack/lib/action_controller/metal/rendering.rb | 1 + actionview/lib/action_view/railtie.rb | 2 +- actionview/lib/action_view/rendering.rb | 2 -- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index cdc63d67a3..f0e8945f11 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -12,6 +12,7 @@ module ActionController def render(*args) #:nodoc: raise ::AbstractController::DoubleRenderError if response_body super + self.content_type ||= Mime[lookup_context.rendered_format].to_s response_body end diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index 441bdccd84..8382023e06 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -38,7 +38,7 @@ module ActionView initializer "action_view.setup_action_pack", before: :add_view_paths do |app| ActiveSupport.on_load(:action_controller) do - #ActionController::Base.superclass.send(:include, ActionView::Layouts) + ActionController::Base.superclass.send(:include, ActionView::Layouts) end end diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index 0db469766c..e3d0beade3 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -82,8 +82,6 @@ module ActionView super(*args, &block) options = _normalize_render(*args, &block) - - self.content_type ||= Mime[lookup_context.rendered_format].to_s self.response_body = render_to_body(options) end -- cgit v1.2.3 From 7c8817aeefac2d1a8fa3af5128de1923c788f520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 25 Jul 2013 16:05:22 +0200 Subject: Add missing require --- actionview/lib/action_view/log_subscriber.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actionview/lib/action_view/log_subscriber.rb b/actionview/lib/action_view/log_subscriber.rb index fd9a543e0a..354a136894 100644 --- a/actionview/lib/action_view/log_subscriber.rb +++ b/actionview/lib/action_view/log_subscriber.rb @@ -1,3 +1,5 @@ +require 'active_support/log_subscriber' + module ActionView # = Action View Log Subscriber # -- cgit v1.2.3 From e29c1b3103cd70c5448c8113a58798a8a924f510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Thu, 25 Jul 2013 16:43:13 +0200 Subject: Remove dependency on AV --- actionmailer/actionmailer.gemspec | 2 +- actionpack/actionpack.gemspec | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index 9b25feaf75..9ee8121d24 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -20,7 +20,7 @@ Gem::Specification.new do |s| s.requirements << 'none' s.add_dependency 'actionpack', version - s.add_dependency 'actionview', version + s.add_development_dependency 'actionview', version s.add_dependency 'mail', '~> 2.5.4' end diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index e3aa84ba0f..b4315c1f57 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -20,11 +20,11 @@ Gem::Specification.new do |s| s.requirements << 'none' s.add_dependency 'activesupport', version - s.add_dependency 'actionview', version s.add_dependency 'rack', '~> 1.5.2' s.add_dependency 'rack-test', '~> 0.6.2' - s.add_development_dependency 'activemodel', version - s.add_development_dependency 'tzinfo', '~> 0.3.37' + s.add_development_dependency 'actionview', version + s.add_development_dependency 'activemodel', version + s.add_development_dependency 'tzinfo', '~> 0.3.37' end -- cgit v1.2.3 From 9e6a1439d1a0ad7f7098f1eca0bb8f6fa9482c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 30 Jul 2013 00:26:24 +0200 Subject: Require log_subscriber --- actionmailer/lib/action_mailer/log_subscriber.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actionmailer/lib/action_mailer/log_subscriber.rb b/actionmailer/lib/action_mailer/log_subscriber.rb index c108156792..8467d45986 100644 --- a/actionmailer/lib/action_mailer/log_subscriber.rb +++ b/actionmailer/lib/action_mailer/log_subscriber.rb @@ -1,3 +1,5 @@ +require 'active_support/log_subscriber' + module ActionMailer # Implements the ActiveSupport::LogSubscriber for logging notifications when # email is delivered and received. -- cgit v1.2.3 From 6c7d895ddae5a7a696a9a047e025e9e4e305f790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 30 Jul 2013 00:34:19 +0200 Subject: Do not load AV inside AP Move that part to AV railtie --- actionpack/lib/action_controller.rb | 8 -------- actionpack/lib/action_controller/railtie.rb | 1 - actionview/lib/action_view/railtie.rb | 1 + actionview/test/abstract_unit.rb | 1 + 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index cc03da4904..d08e3c4e8e 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -50,14 +50,6 @@ module ActionController end end -# All of these simply register additional autoloads -require 'action_view' -require 'action_view/vendor/html-scanner' - -ActiveSupport.on_load(:action_view) do - ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor) -end - # Common Active Support usage in Action Controller require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/load_error' diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 5379547c57..0833e65d23 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -1,7 +1,6 @@ require "rails" require "action_controller" require "action_dispatch/railtie" -require "action_view/railtie" require "abstract_controller/railties/routes_helpers" require "action_controller/railties/helpers" diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index 8382023e06..4113448af0 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -39,6 +39,7 @@ module ActionView initializer "action_view.setup_action_pack", before: :add_view_paths do |app| ActiveSupport.on_load(:action_controller) do ActionController::Base.superclass.send(:include, ActionView::Layouts) + ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor) end end diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb index e4d0b53b59..6623b47e83 100644 --- a/actionview/test/abstract_unit.rb +++ b/actionview/test/abstract_unit.rb @@ -269,6 +269,7 @@ end # Emulate AV railtie. ActionController::Base.superclass.send(:include, ActionView::Layouts) +ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor) module ActionController class Base -- cgit v1.2.3 From e868441896b17ec1ae1a3b7640ff8b302c31a983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 30 Jul 2013 00:50:24 +0200 Subject: Remove hard require to ActionView from ActionMailer --- actionmailer/lib/action_mailer.rb | 1 - actionmailer/lib/action_mailer/base.rb | 1 - actionmailer/test/abstract_unit.rb | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb index c45124be80..5b6960c8fc 100644 --- a/actionmailer/lib/action_mailer.rb +++ b/actionmailer/lib/action_mailer.rb @@ -22,7 +22,6 @@ #++ require 'abstract_controller' -require 'action_view' require 'action_mailer/version' # Common Active Support usage in Action Mailer diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index fba2e00166..ada86fbc4f 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -1,5 +1,4 @@ require 'mail' -require 'action_view/base' require 'action_mailer/collector' require 'active_support/core_ext/string/inflections' require 'active_support/core_ext/hash/except' diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb index 1890853952..aa18c512c7 100644 --- a/actionmailer/test/abstract_unit.rb +++ b/actionmailer/test/abstract_unit.rb @@ -14,6 +14,7 @@ require 'action_mailer/test_case' require 'mail' # Emulate AV railtie +require 'action_view' ActionMailer::Base.send(:include, ActionView::Layouts) # Show backtraces for deprecated behavior for quicker cleanup. -- cgit v1.2.3 From d7d3e3417273945029cd049cb6b8f9ab25f466ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 30 Jul 2013 02:24:20 +0200 Subject: Add AV as development dependency for railties It's needed for tests --- railties/railties.gemspec | 2 ++ railties/test/abstract_unit.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/railties/railties.gemspec b/railties/railties.gemspec index 45968052a8..56b8736800 100644 --- a/railties/railties.gemspec +++ b/railties/railties.gemspec @@ -28,4 +28,6 @@ Gem::Specification.new do |s| s.add_dependency 'rake', '>= 0.8.7' s.add_dependency 'thor', '>= 0.18.1', '< 2.0' + + s.add_development_dependency 'actionview', version end diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb index 491faf4af9..643cc6b0ee 100644 --- a/railties/test/abstract_unit.rb +++ b/railties/test/abstract_unit.rb @@ -8,6 +8,7 @@ require 'fileutils' require 'active_support' require 'action_controller' +require 'action_view' require 'rails/all' module TestApp -- cgit v1.2.3 From 3f2ac795b8f49ad07ec30790fe716cbdac78642c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 30 Jul 2013 02:24:31 +0200 Subject: Add missing requires inside AV --- actionview/lib/action_view/base.rb | 4 ++++ actionview/lib/action_view/helpers/record_tag_helper.rb | 2 ++ actionview/lib/action_view/layouts.rb | 2 +- actionview/lib/action_view/rendering.rb | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/actionview/lib/action_view/base.rb b/actionview/lib/action_view/base.rb index 08253de3f4..caade8f43b 100644 --- a/actionview/lib/action_view/base.rb +++ b/actionview/lib/action_view/base.rb @@ -2,6 +2,10 @@ require 'active_support/core_ext/module/attr_internal' require 'active_support/core_ext/class/attribute_accessors' require 'active_support/ordered_options' require 'action_view/log_subscriber' +require 'action_view/helpers' +require 'action_view/context' +require 'action_view/template' +require 'action_view/lookup_context' module ActionView #:nodoc: # = Action View Base diff --git a/actionview/lib/action_view/helpers/record_tag_helper.rb b/actionview/lib/action_view/helpers/record_tag_helper.rb index f767957fa9..77c3e6d394 100644 --- a/actionview/lib/action_view/helpers/record_tag_helper.rb +++ b/actionview/lib/action_view/helpers/record_tag_helper.rb @@ -1,3 +1,5 @@ +require 'action_view/record_identifier' + module ActionView # = Action View Record Tag Helpers module Helpers diff --git a/actionview/lib/action_view/layouts.rb b/actionview/lib/action_view/layouts.rb index f12aa62124..d8de1d95df 100644 --- a/actionview/lib/action_view/layouts.rb +++ b/actionview/lib/action_view/layouts.rb @@ -1,6 +1,6 @@ +require "action_view/rendering" require "active_support/core_ext/module/remove_method" - module ActionView # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in # repeated setups. The inclusion pattern has pages that look like this: diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index e3d0beade3..fa1c984726 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -1,3 +1,4 @@ +require "action_view/view_paths" module ActionView # This is a class to fix I18n global state. Whenever you provide I18n.locale during a request, -- cgit v1.2.3 From e291e6a479d9942515251ab5d4f37f5f5125217a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 30 Jul 2013 10:22:39 +0200 Subject: Include AV railtie in railties isolation tests --- railties/test/isolation/abstract_unit.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index a3295a6e69..ab3ca106dc 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -135,6 +135,7 @@ module TestHelpers def make_basic_app require "rails" require "action_controller/railtie" + require "action_view/railtie" app = Class.new(Rails::Application) app.config.eager_load = false -- cgit v1.2.3 From ac036cc38c5af3bae436940d2f1c73316eeb726f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 30 Jul 2013 11:28:31 +0200 Subject: Missing AV requires in railties tests --- railties/test/application/url_generation_test.rb | 1 + railties/test/generators/generators_test_helper.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/railties/test/application/url_generation_test.rb b/railties/test/application/url_generation_test.rb index 2767779719..efbc853d7b 100644 --- a/railties/test/application/url_generation_test.rb +++ b/railties/test/application/url_generation_test.rb @@ -12,6 +12,7 @@ module ApplicationTests boot_rails require "rails" require "action_controller/railtie" + require "action_view/railtie" class MyApp < Rails::Application config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4" diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb index 7fdd54fc30..32a3d072c9 100644 --- a/railties/test/generators/generators_test_helper.rb +++ b/railties/test/generators/generators_test_helper.rb @@ -16,6 +16,7 @@ Rails.application.load_generators require 'active_record' require 'action_dispatch' +require 'action_view' module GeneratorsTestHelper def self.included(base) -- cgit v1.2.3 From c9ffd73968f98f04885370a7a075e0bacd213866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Tue, 30 Jul 2013 14:02:07 +0200 Subject: Include AV railtie when we're not loading full rails stack --- .../lib/rails/generators/rails/plugin/templates/rails/application.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb index 310c975262..b2aa82344a 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb @@ -7,6 +7,7 @@ require 'rails/all' <%= comment_if :skip_active_record %>require "active_record/railtie" require "action_controller/railtie" require "action_mailer/railtie" +require "action_view/railtie" <%= comment_if :skip_sprockets %>require "sprockets/railtie" <%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" <% end -%> -- cgit v1.2.3 From 1b1c23599bf0b4c16fec260ed993b27a8cc92724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Wed, 31 Jul 2013 17:10:10 +0200 Subject: Add --skip-action-view to app generator --- railties/lib/rails/generators/app_base.rb | 5 ++++- .../lib/rails/generators/rails/app/templates/config/application.rb | 1 + .../lib/rails/generators/rails/plugin/templates/rails/application.rb | 2 +- railties/test/generators/app_generator_test.rb | 5 +++++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 675ada7ed0..fb495c918c 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -37,6 +37,9 @@ module Rails class_option :skip_active_record, type: :boolean, aliases: '-O', default: false, desc: 'Skip Active Record files' + class_option :skip_action_view, type: :boolean, aliases: '-V', default: false, + desc: 'Skip Action View files' + class_option :skip_sprockets, type: :boolean, aliases: '-S', default: false, desc: 'Skip Sprockets files' @@ -123,7 +126,7 @@ module Rails end def include_all_railties? - !options[:skip_active_record] && !options[:skip_test_unit] && !options[:skip_sprockets] + !options[:skip_active_record] && !options[:skip_action_view] && !options[:skip_test_unit] && !options[:skip_sprockets] end def comment_if(value) 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 4d474d5267..ac41a0cadb 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -8,6 +8,7 @@ require "active_model/railtie" <%= comment_if :skip_active_record %>require "active_record/railtie" require "action_controller/railtie" require "action_mailer/railtie" +<%= comment_if :skip_action_view %>require "action_view/railtie" <%= comment_if :skip_sprockets %>require "sprockets/railtie" <%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" <% end -%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb index b2aa82344a..5508829f6b 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb @@ -7,7 +7,7 @@ require 'rails/all' <%= comment_if :skip_active_record %>require "active_record/railtie" require "action_controller/railtie" require "action_mailer/railtie" -require "action_view/railtie" +<%= comment_if :skip_action_view %>require "action_view/railtie" <%= comment_if :skip_sprockets %>require "sprockets/railtie" <%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" <% end -%> diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 42b6275932..2f0dfc7d3e 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -222,6 +222,11 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_generator_if_skip_action_view_is_given + run_generator [destination_root, "--skip-action-view"] + assert_file "config/application.rb", /#\s+require\s+["']action_view\/railtie["']/ + end + def test_generator_if_skip_sprockets_is_given run_generator [destination_root, "--skip-sprockets"] assert_file "config/application.rb" do |content| -- cgit v1.2.3 From 7d810049fe8905e3e96d0b2e989f562bb961e59e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Fri, 2 Aug 2013 02:27:28 +0200 Subject: Add #rendered_format method to controllers --- actionpack/lib/abstract_controller/rendering.rb | 5 +++++ actionpack/lib/action_controller/metal/rendering.rb | 8 ++++---- actionview/lib/action_view/rendering.rb | 4 ++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 93ded404d6..5a5c47eb3b 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -47,6 +47,11 @@ module AbstractController def render(*args, &block) end + # Return Content-Type of rendered content + # :api: public + def rendered_format + end + # This method should return a hash with assigns. # You can overwrite this configuration per controller. # :api: public diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index f0e8945f11..abcc9d4acf 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -10,17 +10,17 @@ module ActionController # Check for double render errors and set the content_type after rendering. def render(*args) #:nodoc: - raise ::AbstractController::DoubleRenderError if response_body + raise ::AbstractController::DoubleRenderError if self.response_body super - self.content_type ||= Mime[lookup_context.rendered_format].to_s - response_body + self.content_type ||= rendered_format.to_s + self.response_body end # Overwrite render_to_string because body can now be set to a rack body. def render_to_string(*) if self.response_body = super string = "" - response_body.each { |r| string << r } + self.response_body.each { |r| string << r } string end ensure diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index fa1c984726..88a3de4a45 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -107,6 +107,10 @@ module ActionView view_renderer.render(view_context, options) end + def rendered_format + Mime[lookup_context.rendered_format] + end + def default_protected_instance_vars super.concat([:@_view_context_class, :@_view_renderer, :@_lookup_context]) end -- cgit v1.2.3 From 2c395923491768c51c64ab2d5079448e4a9477d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Fri, 2 Aug 2013 14:57:42 +0200 Subject: Do not include action_view/layouts We don't need them. They'll be loaded automaticly if AV will be included --- actionpack/lib/action_controller/base.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index dc880cd866..3fd5fb90d2 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -1,4 +1,3 @@ -require "action_view/layouts" require "action_controller/log_subscriber" require "action_controller/metal/params_wrapper" -- cgit v1.2.3 From aa2d0038127f3b0d25e0f9dbb941c6dd0b2714c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Fri, 2 Aug 2013 15:47:39 +0200 Subject: Fist stab on basic rendering --- actionpack/lib/action_controller.rb | 1 + actionpack/lib/action_controller/base.rb | 1 + actionpack/lib/action_controller/metal/rendering.rb | 18 ++++++++++++++++++ actionview/lib/action_view/rendering.rb | 2 -- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index d08e3c4e8e..0233937a25 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -13,6 +13,7 @@ module ActionController autoload :Middleware autoload_under "metal" do + autoload :BasicRendering, 'action_controller/metal/rendering' autoload :Compatibility autoload :ConditionalGet autoload :Cookies diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 3fd5fb90d2..9941c06201 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -14,6 +14,7 @@ module ActionController # metal = Class.new(Metal) do include AbstractController::Rendering + include ActionController::BasicRendering end # Action Controllers are the core of a web request in \Rails. They are made up of one or more actions that are executed diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index abcc9d4acf..2d58e1440c 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -1,4 +1,22 @@ module ActionController + module BasicRendering + extend ActiveSupport::Concern + + # Render template to response_body + # :api: public + def render(*args, &block) + super(*args, &block) + text = args.first[:text] + if text.present? + self.response_body = text + end + end + + def rendered_format + Mime::TEXT + end + end + module Rendering extend ActiveSupport::Concern diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index 88a3de4a45..db9c4ef501 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -80,8 +80,6 @@ module ActionView # Render template to response_body # :api: public def render(*args, &block) - super(*args, &block) - options = _normalize_render(*args, &block) self.response_body = render_to_body(options) end -- cgit v1.2.3 From acc8e25902902a7123fb34aaf143f73a8ef729dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Strza=C5=82kowski?= Date: Mon, 5 Aug 2013 23:58:20 +0200 Subject: Move render_test to AV --- actionpack/test/controller/render_test.rb | 1648 +++----------------- actionview/test/actionpack/render_test.rb | 1572 +++++++++++++++++++ .../bad_customers/_bad_customer.html.erb | 1 + .../actionpack/customers/_customer.html.erb | 1 + .../test/fixtures/actionpack/fun/games/_form.erb | 1 + .../fixtures/actionpack/fun/games/hello_world.erb | 1 + .../good_customers/_good_customer.html.erb | 1 + actionview/test/fixtures/actionpack/hello.html | 1 + .../fixtures/actionpack/layouts/_customers.erb | 1 + .../actionpack/layouts/block_with_layout.erb | 3 + .../fixtures/actionpack/layouts/builder.builder | 3 + .../actionpack/layouts/partial_with_layout.erb | 3 + .../fixtures/actionpack/layouts/standard.html.erb | 1 + .../actionpack/layouts/talk_from_action.erb | 2 + .../actionpack/layouts/with_html_partial.html.erb | 1 + .../test/fixtures/actionpack/layouts/xhr.html.erb | 2 + .../test/fixtures/actionpack/layouts/yield.erb | 2 + .../actionpack/quiz/questions/_question.html.erb | 1 + .../test/fixtures/actionpack/shared.html.erb | 1 + .../actionpack/test/_changing_priority.html.erb | 1 + .../actionpack/test/_changing_priority.json.erb | 1 + .../fixtures/actionpack/test/_counter.html.erb | 1 + .../test/fixtures/actionpack/test/_customer.erb | 1 + .../fixtures/actionpack/test/_customer_counter.erb | 1 + .../actionpack/test/_customer_counter_with_as.erb | 1 + .../actionpack/test/_customer_greeting.erb | 1 + .../actionpack/test/_customer_with_var.erb | 1 + .../test/_directory/_partial_with_locales.html.erb | 1 + .../actionpack/test/_first_json_partial.json.erb | 1 + actionview/test/fixtures/actionpack/test/_form.erb | 1 + .../fixtures/actionpack/test/_hash_greeting.erb | 1 + .../test/fixtures/actionpack/test/_hash_object.erb | 2 + .../test/fixtures/actionpack/test/_hello.builder | 1 + .../actionpack/test/_json_change_priority.json.erb | 0 .../fixtures/actionpack/test/_labelling_form.erb | 1 + .../actionpack/test/_layout_for_partial.html.erb | 3 + .../test/fixtures/actionpack/test/_partial.erb | 1 + .../fixtures/actionpack/test/_partial.html.erb | 1 + .../test/fixtures/actionpack/test/_partial.js.erb | 1 + .../test/_partial_for_use_in_layout.html.erb | 1 + .../actionpack/test/_partial_html_erb.html.erb | 1 + .../test/_partial_name_local_variable.erb | 1 + .../fixtures/actionpack/test/_partial_only.erb | 1 + .../actionpack/test/_partial_only_html.html | 1 + .../actionpack/test/_partial_with_partial.erb | 2 + .../test/fixtures/actionpack/test/_person.erb | 2 + .../actionpack/test/_raise_indentation.html.erb | 13 + .../actionpack/test/_second_json_partial.json.erb | 1 + .../actionpack/test/action_talk_to_layout.erb | 2 + .../test/calling_partial_with_layout.html.erb | 1 + .../test/fixtures/actionpack/test/capturing.erb | 4 + .../actionpack/test/change_priority.html.erb | 2 + .../test/fixtures/actionpack/test/content_for.erb | 1 + .../actionpack/test/content_for_concatenated.erb | 3 + .../actionpack/test/content_for_with_parameter.erb | 2 + .../test/dot.directory/render_file_with_ivar.erb | 1 + .../actionpack/test/formatted_html_erb.html.erb | 1 + .../actionpack/test/formatted_xml_erb.builder | 1 + .../actionpack/test/formatted_xml_erb.html.erb | 1 + .../actionpack/test/formatted_xml_erb.xml.erb | 1 + .../fixtures/actionpack/test/greeting.html.erb | 1 + .../test/fixtures/actionpack/test/greeting.xml.erb | 1 + .../test/fixtures/actionpack/test/hello,world.erb | 1 + .../test/fixtures/actionpack/test/hello.builder | 4 + .../test/fixtures/actionpack/test/hello/hello.erb | 1 + .../test/fixtures/actionpack/test/hello_world.erb | 1 + .../actionpack/test/hello_world_container.builder | 3 + .../actionpack/test/hello_world_from_rxml.builder | 3 + .../test/hello_world_with_layout_false.erb | 1 + .../test/hello_world_with_partial.html.erb | 2 + .../actionpack/test/hello_xml_world.builder | 11 + .../actionpack/test/html_template.html.erb | 1 + .../test/fixtures/actionpack/test/hyphen-ated.erb | 1 + .../test/implicit_content_type.atom.builder | 2 + actionview/test/fixtures/actionpack/test/list.erb | 1 + .../test/non_erb_block_content_for.builder | 4 + .../actionpack/test/potential_conflicts.erb | 4 + .../actionpack/test/proper_block_detection.erb | 1 + .../test/render_file_from_template.html.erb | 1 + .../actionpack/test/render_file_with_ivar.erb | 1 + .../actionpack/test/render_file_with_locals.erb | 1 + .../test/render_file_with_locals_and_default.erb | 1 + ...icit_html_template_from_xhr_request.da.html.erb | 1 + ...mplicit_html_template_from_xhr_request.html.erb | 1 + ...nder_implicit_js_template_without_layout.js.erb | 1 + .../test/render_partial_inside_directory.html.erb | 1 + .../actionpack/test/render_to_string_test.erb | 1 + .../actionpack/test/render_two_partials.html.erb | 2 + .../test/using_layout_around_block.html.erb | 1 + .../actionpack/test/with_html_partial.html.erb | 1 + .../fixtures/actionpack/test/with_partial.html.erb | 1 + .../fixtures/actionpack/test/with_partial.text.erb | 1 + .../actionpack/test/with_xml_template.html.erb | 1 + 93 files changed, 1950 insertions(+), 1420 deletions(-) create mode 100644 actionview/test/actionpack/render_test.rb create mode 100644 actionview/test/fixtures/actionpack/bad_customers/_bad_customer.html.erb create mode 100644 actionview/test/fixtures/actionpack/customers/_customer.html.erb create mode 100644 actionview/test/fixtures/actionpack/fun/games/_form.erb create mode 100644 actionview/test/fixtures/actionpack/fun/games/hello_world.erb create mode 100644 actionview/test/fixtures/actionpack/good_customers/_good_customer.html.erb create mode 100644 actionview/test/fixtures/actionpack/hello.html create mode 100644 actionview/test/fixtures/actionpack/layouts/_customers.erb create mode 100644 actionview/test/fixtures/actionpack/layouts/block_with_layout.erb create mode 100644 actionview/test/fixtures/actionpack/layouts/builder.builder create mode 100644 actionview/test/fixtures/actionpack/layouts/partial_with_layout.erb create mode 100644 actionview/test/fixtures/actionpack/layouts/standard.html.erb create mode 100644 actionview/test/fixtures/actionpack/layouts/talk_from_action.erb create mode 100644 actionview/test/fixtures/actionpack/layouts/with_html_partial.html.erb create mode 100644 actionview/test/fixtures/actionpack/layouts/xhr.html.erb create mode 100644 actionview/test/fixtures/actionpack/layouts/yield.erb create mode 100644 actionview/test/fixtures/actionpack/quiz/questions/_question.html.erb create mode 100644 actionview/test/fixtures/actionpack/shared.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/_changing_priority.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/_changing_priority.json.erb create mode 100644 actionview/test/fixtures/actionpack/test/_counter.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/_customer.erb create mode 100644 actionview/test/fixtures/actionpack/test/_customer_counter.erb create mode 100644 actionview/test/fixtures/actionpack/test/_customer_counter_with_as.erb create mode 100644 actionview/test/fixtures/actionpack/test/_customer_greeting.erb create mode 100644 actionview/test/fixtures/actionpack/test/_customer_with_var.erb create mode 100644 actionview/test/fixtures/actionpack/test/_directory/_partial_with_locales.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/_first_json_partial.json.erb create mode 100644 actionview/test/fixtures/actionpack/test/_form.erb create mode 100644 actionview/test/fixtures/actionpack/test/_hash_greeting.erb create mode 100644 actionview/test/fixtures/actionpack/test/_hash_object.erb create mode 100644 actionview/test/fixtures/actionpack/test/_hello.builder create mode 100644 actionview/test/fixtures/actionpack/test/_json_change_priority.json.erb create mode 100644 actionview/test/fixtures/actionpack/test/_labelling_form.erb create mode 100644 actionview/test/fixtures/actionpack/test/_layout_for_partial.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/_partial.erb create mode 100644 actionview/test/fixtures/actionpack/test/_partial.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/_partial.js.erb create mode 100644 actionview/test/fixtures/actionpack/test/_partial_for_use_in_layout.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/_partial_html_erb.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/_partial_name_local_variable.erb create mode 100644 actionview/test/fixtures/actionpack/test/_partial_only.erb create mode 100644 actionview/test/fixtures/actionpack/test/_partial_only_html.html create mode 100644 actionview/test/fixtures/actionpack/test/_partial_with_partial.erb create mode 100644 actionview/test/fixtures/actionpack/test/_person.erb create mode 100644 actionview/test/fixtures/actionpack/test/_raise_indentation.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/_second_json_partial.json.erb create mode 100644 actionview/test/fixtures/actionpack/test/action_talk_to_layout.erb create mode 100644 actionview/test/fixtures/actionpack/test/calling_partial_with_layout.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/capturing.erb create mode 100644 actionview/test/fixtures/actionpack/test/change_priority.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/content_for.erb create mode 100644 actionview/test/fixtures/actionpack/test/content_for_concatenated.erb create mode 100644 actionview/test/fixtures/actionpack/test/content_for_with_parameter.erb create mode 100644 actionview/test/fixtures/actionpack/test/dot.directory/render_file_with_ivar.erb create mode 100644 actionview/test/fixtures/actionpack/test/formatted_html_erb.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/formatted_xml_erb.builder create mode 100644 actionview/test/fixtures/actionpack/test/formatted_xml_erb.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/formatted_xml_erb.xml.erb create mode 100644 actionview/test/fixtures/actionpack/test/greeting.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/greeting.xml.erb create mode 100644 actionview/test/fixtures/actionpack/test/hello,world.erb create mode 100644 actionview/test/fixtures/actionpack/test/hello.builder create mode 100644 actionview/test/fixtures/actionpack/test/hello/hello.erb create mode 100644 actionview/test/fixtures/actionpack/test/hello_world.erb create mode 100644 actionview/test/fixtures/actionpack/test/hello_world_container.builder create mode 100644 actionview/test/fixtures/actionpack/test/hello_world_from_rxml.builder create mode 100644 actionview/test/fixtures/actionpack/test/hello_world_with_layout_false.erb create mode 100644 actionview/test/fixtures/actionpack/test/hello_world_with_partial.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/hello_xml_world.builder create mode 100644 actionview/test/fixtures/actionpack/test/html_template.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/hyphen-ated.erb create mode 100644 actionview/test/fixtures/actionpack/test/implicit_content_type.atom.builder create mode 100644 actionview/test/fixtures/actionpack/test/list.erb create mode 100644 actionview/test/fixtures/actionpack/test/non_erb_block_content_for.builder create mode 100644 actionview/test/fixtures/actionpack/test/potential_conflicts.erb create mode 100644 actionview/test/fixtures/actionpack/test/proper_block_detection.erb create mode 100644 actionview/test/fixtures/actionpack/test/render_file_from_template.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/render_file_with_ivar.erb create mode 100644 actionview/test/fixtures/actionpack/test/render_file_with_locals.erb create mode 100644 actionview/test/fixtures/actionpack/test/render_file_with_locals_and_default.erb create mode 100644 actionview/test/fixtures/actionpack/test/render_implicit_html_template_from_xhr_request.da.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/render_implicit_html_template_from_xhr_request.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/render_implicit_js_template_without_layout.js.erb create mode 100644 actionview/test/fixtures/actionpack/test/render_partial_inside_directory.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/render_to_string_test.erb create mode 100644 actionview/test/fixtures/actionpack/test/render_two_partials.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/using_layout_around_block.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/with_html_partial.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/with_partial.html.erb create mode 100644 actionview/test/fixtures/actionpack/test/with_partial.text.erb create mode 100644 actionview/test/fixtures/actionpack/test/with_xml_template.html.erb diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index bacc93a936..f41287381a 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -2,26 +2,6 @@ require 'abstract_unit' require 'controller/fake_models' require 'pathname' -module Fun - class GamesController < ActionController::Base - # :ported: - def hello_world - end - - def nested_partial_with_form_builder - render :partial => ActionView::Helpers::FormBuilder.new(:post, nil, view_context, {}) - end - end -end - -module Quiz - class QuestionsController < ActionController::Base - def new - render :partial => Quiz::Question.new("Namespaced Partial") - end - end -end - class TestControllerWithExtraEtags < ActionController::Base etag { nil } etag { 'ab' } @@ -58,10 +38,6 @@ class TestController < ActionController::Base def hello_world end - def hello_world_file - render :file => File.expand_path("../../fixtures/hello", __FILE__), :formats => [:html] - end - def conditional_hello if stale?(:last_modified => Time.now.utc.beginning_of_day, :etag => [:foo, 123]) render :action => 'hello_world' @@ -72,1480 +48,209 @@ class TestController < ActionController::Base record = Struct.new(:updated_at, :cache_key).new(Time.now.utc.beginning_of_day, "foo/123") if stale?(record) - render :action => 'hello_world' - end - end - - def conditional_hello_with_public_header - if stale?(:last_modified => Time.now.utc.beginning_of_day, :etag => [:foo, 123], :public => true) - render :action => 'hello_world' - end - end - - def conditional_hello_with_public_header_with_record - record = Struct.new(:updated_at, :cache_key).new(Time.now.utc.beginning_of_day, "foo/123") - - if stale?(record, :public => true) - render :action => 'hello_world' - end - end - - def conditional_hello_with_public_header_and_expires_at - expires_in 1.minute - if stale?(:last_modified => Time.now.utc.beginning_of_day, :etag => [:foo, 123], :public => true) - render :action => 'hello_world' - end - end - - def conditional_hello_with_expires_in - expires_in 60.1.seconds - render :action => 'hello_world' - end - - def conditional_hello_with_expires_in_with_public - expires_in 1.minute, :public => true - render :action => 'hello_world' - end - - def conditional_hello_with_expires_in_with_must_revalidate - expires_in 1.minute, :must_revalidate => true - render :action => 'hello_world' - end - - def conditional_hello_with_expires_in_with_public_and_must_revalidate - expires_in 1.minute, :public => true, :must_revalidate => true - render :action => 'hello_world' - end - - def conditional_hello_with_expires_in_with_public_with_more_keys - expires_in 1.minute, :public => true, 's-maxage' => 5.hours - render :action => 'hello_world' - end - - def conditional_hello_with_expires_in_with_public_with_more_keys_old_syntax - expires_in 1.minute, :public => true, :private => nil, 's-maxage' => 5.hours - render :action => 'hello_world' - end - - def conditional_hello_with_expires_now - expires_now - render :action => 'hello_world' - end - - def conditional_hello_with_cache_control_headers - response.headers['Cache-Control'] = 'no-transform' - expires_now - render :action => 'hello_world' - end - - def conditional_hello_with_bangs - render :action => 'hello_world' - end - before_action :handle_last_modified_and_etags, :only=>:conditional_hello_with_bangs - - def handle_last_modified_and_etags - fresh_when(:last_modified => Time.now.utc.beginning_of_day, :etag => [ :foo, 123 ]) - end - - # :ported: - def render_hello_world - render :template => "test/hello_world" - end - - def render_hello_world_with_last_modified_set - response.last_modified = Date.new(2008, 10, 10).to_time - render :template => "test/hello_world" - end - - # :ported: compatibility - def render_hello_world_with_forward_slash - render :template => "/test/hello_world" - end - - # :ported: - def render_template_in_top_directory - render :template => 'shared' - end - - # :deprecated: - def render_template_in_top_directory_with_slash - render :template => '/shared' - end - - # :ported: - def render_hello_world_from_variable - @person = "david" - render :text => "hello #{@person}" - end - - # :ported: - def render_action_hello_world - render :action => "hello_world" - end - - def render_action_upcased_hello_world - render :action => "Hello_world" - end - - def render_action_hello_world_as_string - render "hello_world" - end - - def render_action_hello_world_with_symbol - render :action => :hello_world - end - - # :ported: - def render_text_hello_world - render :text => "hello world" - end - - # :ported: - def render_text_hello_world_with_layout - @variable_for_layout = ", I am here!" - render :text => "hello world", :layout => true - end - - def hello_world_with_layout_false - render :layout => false - end - - # :ported: - def render_file_with_instance_variables - @secret = 'in the sauce' - path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar') - render :file => path - end - - # :ported: - def render_file_as_string_with_instance_variables - @secret = 'in the sauce' - path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar')) - render path - end - - # :ported: - def render_file_not_using_full_path - @secret = 'in the sauce' - render :file => 'test/render_file_with_ivar' - end - - def render_file_not_using_full_path_with_dot_in_path - @secret = 'in the sauce' - render :file => 'test/dot.directory/render_file_with_ivar' - end - - def render_file_using_pathname - @secret = 'in the sauce' - render :file => Pathname.new(File.dirname(__FILE__)).join('..', 'fixtures', 'test', 'dot.directory', 'render_file_with_ivar') - end - - def render_file_from_template - @secret = 'in the sauce' - @path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar')) - end - - def render_file_with_locals - path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals') - render :file => path, :locals => {:secret => 'in the sauce'} - end - - def render_file_as_string_with_locals - path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals')) - render path, :locals => {:secret => 'in the sauce'} - end - - def accessing_request_in_template - render :inline => "Hello: <%= request.host %>" - end - - def accessing_logger_in_template - render :inline => "<%= logger.class %>" - end - - def accessing_action_name_in_template - render :inline => "<%= action_name %>" - end - - def accessing_controller_name_in_template - render :inline => "<%= controller_name %>" - end - - # :ported: - def render_custom_code - render :text => "hello world", :status => 404 - end - - # :ported: - def render_text_with_nil - render :text => nil - end - - # :ported: - def render_text_with_false - render :text => false - end - - def render_text_with_resource - render :text => Customer.new("David") - end - - # :ported: - def render_nothing_with_appendix - render :text => "appended" - end - - # This test is testing 3 things: - # render :file in AV :ported: - # render :template in AC :ported: - # setting content type - def render_xml_hello - @name = "David" - render :template => "test/hello" - end - - def render_xml_hello_as_string_template - @name = "David" - render "test/hello" - end - - def render_line_offset - render :inline => '<% raise %>', :locals => {:foo => 'bar'} - end - - def heading - head :ok - end - - def greeting - # let's just rely on the template - end - - # :ported: - def blank_response - render :text => ' ' - end - - # :ported: - def layout_test - render :action => "hello_world" - end - - # :ported: - def builder_layout_test - @name = nil - render :action => "hello", :layout => "layouts/builder" - end - - # :move: test this in Action View - def builder_partial_test - render :action => "hello_world_container" - end - - # :ported: - def partials_list - @test_unchanged = 'hello' - @customers = [ Customer.new("david"), Customer.new("mary") ] - render :action => "list" - end - - def partial_only - render :partial => true - end - - def hello_in_a_string - @customers = [ Customer.new("david"), Customer.new("mary") ] - render :text => "How's there? " + render_to_string(:template => "test/list") - end - - def accessing_params_in_template - render :inline => "Hello: <%= params[:name] %>" - end - - def accessing_local_assigns_in_inline_template - name = params[:local_name] - render :inline => "<%= 'Goodbye, ' + local_name %>", - :locals => { :local_name => name } - end - - def render_implicit_html_template_from_xhr_request - end - - def render_implicit_js_template_without_layout - end - - def formatted_html_erb - end - - def formatted_xml_erb - end - - def render_to_string_test - @foo = render_to_string :inline => "this is a test" - end - - def default_render - @alternate_default_render ||= nil - if @alternate_default_render - @alternate_default_render.call - else - super - end - end - - def render_action_hello_world_as_symbol - render :action => :hello_world - end - - def layout_test_with_different_layout - render :action => "hello_world", :layout => "standard" - end - - def layout_test_with_different_layout_and_string_action - render "hello_world", :layout => "standard" - end - - def layout_test_with_different_layout_and_symbol_action - render :hello_world, :layout => "standard" - end - - def rendering_without_layout - render :action => "hello_world", :layout => false - end - - def layout_overriding_layout - render :action => "hello_world", :layout => "standard" - end - - def rendering_nothing_on_layout - render :nothing => true - end - - def render_to_string_with_assigns - @before = "i'm before the render" - render_to_string :text => "foo" - @after = "i'm after the render" - render :template => "test/hello_world" - end - - def render_to_string_with_exception - render_to_string :file => "exception that will not be caught - this will certainly not work" - end - - def render_to_string_with_caught_exception - @before = "i'm before the render" - begin - render_to_string :file => "exception that will be caught- hope my future instance vars still work!" - rescue - end - @after = "i'm after the render" - render :template => "test/hello_world" - end - - def accessing_params_in_template_with_layout - render :layout => true, :inline => "Hello: <%= params[:name] %>" - end - - # :ported: - def render_with_explicit_template - render :template => "test/hello_world" - end - - def render_with_explicit_unescaped_template - render :template => "test/h*llo_world" - end - - def render_with_explicit_escaped_template - render :template => "test/hello,world" - end - - def render_with_explicit_string_template - render "test/hello_world" - end - - # :ported: - def render_with_explicit_template_with_locals - render :template => "test/render_file_with_locals", :locals => { :secret => 'area51' } - end - - # :ported: - def double_render - render :text => "hello" - render :text => "world" - end - - def double_redirect - redirect_to :action => "double_render" - redirect_to :action => "double_render" - end - - def render_and_redirect - render :text => "hello" - redirect_to :action => "double_render" - end - - def render_to_string_and_render - @stuff = render_to_string :text => "here is some cached stuff" - render :text => "Hi web users! #{@stuff}" - end - - def render_to_string_with_inline_and_render - render_to_string :inline => "<%= 'dlrow olleh'.reverse %>" - render :template => "test/hello_world" - end - - def rendering_with_conflicting_local_vars - @name = "David" - render :action => "potential_conflicts" - end - - def hello_world_from_rxml_using_action - render :action => "hello_world_from_rxml", :handlers => [:builder] - end - - # :deprecated: - def hello_world_from_rxml_using_template - render :template => "test/hello_world_from_rxml", :handlers => [:builder] - end - - def action_talk_to_layout - # Action template sets variable that's picked up by layout - end - - # :addressed: - def render_text_with_assigns - @hello = "world" - render :text => "foo" - end - - def yield_content_for - render :action => "content_for", :layout => "yield" - end - - def render_content_type_from_body - response.content_type = Mime::RSS - render :text => "hello world!" - end - - def head_created - head :created - end - - def head_created_with_application_json_content_type - head :created, :content_type => "application/json" - end - - def head_ok_with_image_png_content_type - head :ok, :content_type => "image/png" - end - - def head_with_location_header - head :location => "/foo" - end - - def head_with_location_object - head :location => Customer.new("david", 1) - end - - def head_with_symbolic_status - head :status => params[:status].intern - end - - def head_with_integer_status - head :status => params[:status].to_i - end - - def head_with_string_status - head :status => params[:status] - end - - def head_with_custom_header - head :x_custom_header => "something" - end - - def head_with_www_authenticate_header - head 'WWW-Authenticate' => 'something' - end - - def head_with_status_code_first - head :forbidden, :x_custom_header => "something" - end - - def render_using_layout_around_block - render :action => "using_layout_around_block" - end - - def render_using_layout_around_block_in_main_layout_and_within_content_for_layout - render :action => "using_layout_around_block", :layout => "layouts/block_with_layout" - end - - def partial_formats_html - render :partial => 'partial', :formats => [:html] - end - - def partial - render :partial => 'partial' - end - - def partial_html_erb - render :partial => 'partial_html_erb' - end - - def render_to_string_with_partial - @partial_only = render_to_string :partial => "partial_only" - @partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") } - render :template => "test/hello_world" - end - - def render_to_string_with_template_and_html_partial - @text = render_to_string :template => "test/with_partial", :formats => [:text] - @html = render_to_string :template => "test/with_partial", :formats => [:html] - render :template => "test/with_html_partial" - end - - def render_to_string_and_render_with_different_formats - @html = render_to_string :template => "test/with_partial", :formats => [:html] - render :template => "test/with_partial", :formats => [:text] - end - - def render_template_within_a_template_with_other_format - render :template => "test/with_xml_template", - :formats => [:html], - :layout => "with_html_partial" - end - - def partial_with_counter - render :partial => "counter", :locals => { :counter_counter => 5 } - end - - def partial_with_locals - render :partial => "customer", :locals => { :customer => Customer.new("david") } - end - - def partial_with_form_builder - render :partial => ActionView::Helpers::FormBuilder.new(:post, nil, view_context, {}) - end - - def partial_with_form_builder_subclass - render :partial => LabellingFormBuilder.new(:post, nil, view_context, {}) - end - - def partial_collection - render :partial => "customer", :collection => [ Customer.new("david"), Customer.new("mary") ] - end - - def partial_collection_with_as - render :partial => "customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :customer - end - - def partial_collection_with_counter - render :partial => "customer_counter", :collection => [ Customer.new("david"), Customer.new("mary") ] - end - - def partial_collection_with_as_and_counter - render :partial => "customer_counter_with_as", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :client - end - - def partial_collection_with_locals - render :partial => "customer_greeting", :collection => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" } - end - - def partial_collection_with_spacer - render :partial => "customer", :spacer_template => "partial_only", :collection => [ Customer.new("david"), Customer.new("mary") ] - end - - def partial_collection_with_spacer_which_uses_render - render :partial => "customer", :spacer_template => "partial_with_partial", :collection => [ Customer.new("david"), Customer.new("mary") ] - end - - def partial_collection_shorthand_with_locals - render :partial => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" } - end - - def partial_collection_shorthand_with_different_types_of_records - render :partial => [ - BadCustomer.new("mark"), - GoodCustomer.new("craig"), - BadCustomer.new("john"), - GoodCustomer.new("zach"), - GoodCustomer.new("brandon"), - BadCustomer.new("dan") ], - :locals => { :greeting => "Bonjour" } - end - - def empty_partial_collection - render :partial => "customer", :collection => [] - end - - def partial_collection_shorthand_with_different_types_of_records_with_counter - partial_collection_shorthand_with_different_types_of_records - end - - def missing_partial - render :partial => 'thisFileIsntHere' - end - - def partial_with_hash_object - render :partial => "hash_object", :object => {:first_name => "Sam"} - end - - def partial_with_nested_object - render :partial => "quiz/questions/question", :object => Quiz::Question.new("first") - end - - def partial_with_nested_object_shorthand - render Quiz::Question.new("first") - end - - def partial_hash_collection - render :partial => "hash_object", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ] - end - - def partial_hash_collection_with_locals - render :partial => "hash_greeting", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ], :locals => { :greeting => "Hola" } - end - - def partial_with_implicit_local_assignment - @customer = Customer.new("Marcel") - render :partial => "customer" - end - - def render_call_to_partial_with_layout - render :action => "calling_partial_with_layout" - end - - def render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout - render :action => "calling_partial_with_layout", :layout => "layouts/partial_with_layout" - end - - before_action only: :render_with_filters do - request.format = :xml - end - - # Ensure that the before filter is executed *before* self.formats is set. - def render_with_filters - render :action => :formatted_xml_erb - end - - private - - def set_variable_for_layout - @variable_for_layout = nil - end - - def determine_layout - case action_name - when "hello_world", "layout_test", "rendering_without_layout", - "rendering_nothing_on_layout", "render_text_hello_world", - "render_text_hello_world_with_layout", - "hello_world_with_layout_false", - "partial_only", "accessing_params_in_template", - "accessing_params_in_template_with_layout", - "render_with_explicit_template", - "render_with_explicit_string_template", - "update_page", "update_page_with_instance_variables" - - "layouts/standard" - when "action_talk_to_layout", "layout_overriding_layout" - "layouts/talk_from_action" - when "render_implicit_html_template_from_xhr_request" - (request.xhr? ? 'layouts/xhr' : 'layouts/standard') - end - end -end - -class MetalTestController < ActionController::Metal - include AbstractController::Rendering - include ActionView::Rendering - include ActionController::Rendering - - def accessing_logger_in_template - render :inline => "<%= logger.class %>" - end -end - -class RenderTest < ActionController::TestCase - tests TestController - - def setup - # enable a logger so that (e.g.) the benchmarking stuff runs, so we can get - # a more accurate simulation of what happens in "real life". - super - @controller.logger = ActiveSupport::Logger.new(nil) - ActionView::Base.logger = ActiveSupport::Logger.new(nil) - - @request.host = "www.nextangle.com" - end - - # :ported: - def test_simple_show - get :hello_world - assert_response 200 - assert_response :success - assert_template "test/hello_world" - assert_equal "Hello world!", @response.body - end - - # :ported: - def test_renders_default_template_for_missing_action - get :'hyphen-ated' - assert_template 'test/hyphen-ated' - end - - # :ported: - def test_render - get :render_hello_world - assert_template "test/hello_world" - end - - def test_line_offset - get :render_line_offset - flunk "the action should have raised an exception" - rescue StandardError => exc - line = exc.backtrace.first - assert(line =~ %r{:(\d+):}) - assert_equal "1", $1, - "The line offset is wrong, perhaps the wrong exception has been raised, exception was: #{exc.inspect}" - end - - # :ported: compatibility - def test_render_with_forward_slash - get :render_hello_world_with_forward_slash - assert_template "test/hello_world" - end - - # :ported: - def test_render_in_top_directory - get :render_template_in_top_directory - assert_template "shared" - assert_equal "Elastica", @response.body - end - - # :ported: - def test_render_in_top_directory_with_slash - get :render_template_in_top_directory_with_slash - assert_template "shared" - assert_equal "Elastica", @response.body - end - - # :ported: - def test_render_from_variable - get :render_hello_world_from_variable - assert_equal "hello david", @response.body - end - - # :ported: - def test_render_action - get :render_action_hello_world - assert_template "test/hello_world" - end - - def test_render_action_upcased - assert_raise ActionView::MissingTemplate do - get :render_action_upcased_hello_world - end - end - - # :ported: - def test_render_action_hello_world_as_string - get :render_action_hello_world_as_string - assert_equal "Hello world!", @response.body - assert_template "test/hello_world" - end - - # :ported: - def test_render_action_with_symbol - get :render_action_hello_world_with_symbol - assert_template "test/hello_world" - end - - # :ported: - def test_render_text - get :render_text_hello_world - assert_equal "hello world", @response.body - end - - # :ported: - def test_do_with_render_text_and_layout - get :render_text_hello_world_with_layout - assert_equal "hello world, I am here!", @response.body - end - - # :ported: - def test_do_with_render_action_and_layout_false - get :hello_world_with_layout_false - assert_equal 'Hello world!', @response.body - end - - # :ported: - def test_render_file_with_instance_variables - get :render_file_with_instance_variables - assert_equal "The secret is in the sauce\n", @response.body - end - - def test_render_file - get :hello_world_file - assert_equal "Hello world!", @response.body - end - - # :ported: - def test_render_file_as_string_with_instance_variables - get :render_file_as_string_with_instance_variables - assert_equal "The secret is in the sauce\n", @response.body - end - - # :ported: - def test_render_file_not_using_full_path - get :render_file_not_using_full_path - assert_equal "The secret is in the sauce\n", @response.body - end - - # :ported: - def test_render_file_not_using_full_path_with_dot_in_path - get :render_file_not_using_full_path_with_dot_in_path - assert_equal "The secret is in the sauce\n", @response.body - end - - # :ported: - def test_render_file_using_pathname - get :render_file_using_pathname - assert_equal "The secret is in the sauce\n", @response.body - end - - # :ported: - def test_render_file_with_locals - get :render_file_with_locals - assert_equal "The secret is in the sauce\n", @response.body - end - - # :ported: - def test_render_file_as_string_with_locals - get :render_file_as_string_with_locals - assert_equal "The secret is in the sauce\n", @response.body - end - - # :assessed: - def test_render_file_from_template - get :render_file_from_template - assert_equal "The secret is in the sauce\n", @response.body - end - - # :ported: - def test_render_custom_code - get :render_custom_code - assert_response 404 - assert_response :missing - assert_equal 'hello world', @response.body - end - - # :ported: - def test_render_text_with_nil - get :render_text_with_nil - assert_response 200 - assert_equal ' ', @response.body - end - - # :ported: - def test_render_text_with_false - get :render_text_with_false - assert_equal 'false', @response.body - end - - # :ported: - def test_render_nothing_with_appendix - get :render_nothing_with_appendix - assert_response 200 - assert_equal 'appended', @response.body - end - - def test_render_text_with_resource - get :render_text_with_resource - assert_equal 'name: "David"', @response.body - end - - # :ported: - def test_attempt_to_access_object_method - assert_raise(AbstractController::ActionNotFound, "No action responded to [clone]") { get :clone } - end - - # :ported: - def test_private_methods - assert_raise(AbstractController::ActionNotFound, "No action responded to [determine_layout]") { get :determine_layout } - end - - # :ported: - def test_access_to_request_in_view - get :accessing_request_in_template - assert_equal "Hello: www.nextangle.com", @response.body - end - - def test_access_to_logger_in_view - get :accessing_logger_in_template - assert_equal "ActiveSupport::Logger", @response.body - end - - # :ported: - def test_access_to_action_name_in_view - get :accessing_action_name_in_template - assert_equal "accessing_action_name_in_template", @response.body - end - - # :ported: - def test_access_to_controller_name_in_view - get :accessing_controller_name_in_template - assert_equal "test", @response.body # name is explicitly set in the controller. - end - - # :ported: - def test_render_xml - get :render_xml_hello - assert_equal "\n

Hello David

\n

This is grand!

\n\n", @response.body - assert_equal "application/xml", @response.content_type - end - - # :ported: - def test_render_xml_as_string_template - get :render_xml_hello_as_string_template - assert_equal "\n

Hello David

\n

This is grand!

\n\n", @response.body - assert_equal "application/xml", @response.content_type - end - - # :ported: - def test_render_xml_with_default - get :greeting - assert_equal "

This is grand!

\n", @response.body - end - - # :move: test in AV - def test_render_xml_with_partial - get :builder_partial_test - assert_equal "\n \n\n", @response.body - end - - # :ported: - def test_layout_rendering - get :layout_test - assert_equal "Hello world!", @response.body - end - - def test_render_xml_with_layouts - get :builder_layout_test - assert_equal "\n\n

Hello

\n

This is grand!

\n\n
\n", @response.body - end - - def test_partials_list - get :partials_list - assert_equal "goodbyeHello: davidHello: marygoodbye\n", @response.body - end - - def test_render_to_string - get :hello_in_a_string - assert_equal "How's there? goodbyeHello: davidHello: marygoodbye\n", @response.body - end - - def test_render_to_string_resets_assigns - get :render_to_string_test - assert_equal "The value of foo is: ::this is a test::\n", @response.body - end - - def test_render_to_string_inline - get :render_to_string_with_inline_and_render - assert_template "test/hello_world" - end - - # :ported: - def test_nested_rendering - @controller = Fun::GamesController.new - get :hello_world - assert_equal "Living in a nested world", @response.body - end - - def test_accessing_params_in_template - get :accessing_params_in_template, :name => "David" - assert_equal "Hello: David", @response.body - end - - def test_accessing_local_assigns_in_inline_template - get :accessing_local_assigns_in_inline_template, :local_name => "Local David" - assert_equal "Goodbye, Local David", @response.body - assert_equal "text/html", @response.content_type - end - - def test_should_implicitly_render_html_template_from_xhr_request - xhr :get, :render_implicit_html_template_from_xhr_request - assert_equal "XHR!\nHello HTML!", @response.body - end - - def test_should_implicitly_render_js_template_without_layout - get :render_implicit_js_template_without_layout, :format => :js - assert_no_match %r{}, @response.body - end - - def test_should_render_formatted_template - get :formatted_html_erb - assert_equal 'formatted html erb', @response.body - end - - def test_should_render_formatted_html_erb_template - get :formatted_xml_erb - assert_equal 'passed formatted html erb', @response.body - end - - def test_should_render_formatted_html_erb_template_with_bad_accepts_header - @request.env["HTTP_ACCEPT"] = "; a=dsf" - get :formatted_xml_erb - assert_equal 'passed formatted html erb', @response.body - end - - def test_should_render_formatted_html_erb_template_with_faulty_accepts_header - @request.accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, appliction/x-shockwave-flash, */*" - get :formatted_xml_erb - assert_equal 'passed formatted html erb', @response.body - end - - def test_layout_test_with_different_layout - get :layout_test_with_different_layout - assert_equal "Hello world!", @response.body - end - - def test_layout_test_with_different_layout_and_string_action - get :layout_test_with_different_layout_and_string_action - assert_equal "Hello world!", @response.body - end - - def test_layout_test_with_different_layout_and_symbol_action - get :layout_test_with_different_layout_and_symbol_action - assert_equal "Hello world!", @response.body - end - - def test_rendering_without_layout - get :rendering_without_layout - assert_equal "Hello world!", @response.body - end - - def test_layout_overriding_layout - get :layout_overriding_layout - assert_no_match %r{}, @response.body - end - - def test_rendering_nothing_on_layout - get :rendering_nothing_on_layout - assert_equal " ", @response.body - end - - def test_render_to_string_doesnt_break_assigns - get :render_to_string_with_assigns - assert_equal "i'm before the render", assigns(:before) - assert_equal "i'm after the render", assigns(:after) - end - - def test_bad_render_to_string_still_throws_exception - assert_raise(ActionView::MissingTemplate) { get :render_to_string_with_exception } - end - - def test_render_to_string_that_throws_caught_exception_doesnt_break_assigns - assert_nothing_raised { get :render_to_string_with_caught_exception } - assert_equal "i'm before the render", assigns(:before) - assert_equal "i'm after the render", assigns(:after) - end - - def test_accessing_params_in_template_with_layout - get :accessing_params_in_template_with_layout, :name => "David" - assert_equal "<html>Hello: David</html>", @response.body - end - - def test_render_with_explicit_template - get :render_with_explicit_template - assert_response :success - end - - def test_render_with_explicit_unescaped_template - assert_raise(ActionView::MissingTemplate) { get :render_with_explicit_unescaped_template } - get :render_with_explicit_escaped_template - assert_equal "Hello w*rld!", @response.body - end - - def test_render_with_explicit_string_template - get :render_with_explicit_string_template - assert_equal "<html>Hello world!</html>", @response.body - end - - def test_render_with_filters - get :render_with_filters - assert_equal "<test>passed formatted xml erb</test>", @response.body - end - - # :ported: - def test_double_render - assert_raise(AbstractController::DoubleRenderError) { get :double_render } - end - - def test_double_redirect - assert_raise(AbstractController::DoubleRenderError) { get :double_redirect } - end - - def test_render_and_redirect - assert_raise(AbstractController::DoubleRenderError) { get :render_and_redirect } - end - - # specify the one exception to double render rule - render_to_string followed by render - def test_render_to_string_and_render - get :render_to_string_and_render - assert_equal("Hi web users! here is some cached stuff", @response.body) - end - - def test_rendering_with_conflicting_local_vars - get :rendering_with_conflicting_local_vars - assert_equal("First: David\nSecond: Stephan\nThird: David\nFourth: David\nFifth: ", @response.body) - end - - def test_action_talk_to_layout - get :action_talk_to_layout - assert_equal "<title>Talking to the layout\nAction was here!", @response.body - end - - # :addressed: - def test_render_text_with_assigns - get :render_text_with_assigns - assert_equal "world", assigns["hello"] - end - - # :ported: - def test_template_with_locals - get :render_with_explicit_template_with_locals - assert_equal "The secret is area51\n", @response.body - end - - def test_yield_content_for - get :yield_content_for - assert_equal "Putting stuff in the title!\nGreat stuff!\n", @response.body - end - - def test_overwritting_rendering_relative_file_with_extension - get :hello_world_from_rxml_using_template - assert_equal "\n

Hello

\n\n", @response.body - - get :hello_world_from_rxml_using_action - assert_equal "\n

Hello

\n\n", @response.body - end - - def test_head_created - post :head_created - assert @response.body.blank? - assert_response :created - end - - def test_head_created_with_application_json_content_type - post :head_created_with_application_json_content_type - assert @response.body.blank? - assert_equal "application/json", @response.header["Content-Type"] - assert_response :created - end - - def test_head_ok_with_image_png_content_type - post :head_ok_with_image_png_content_type - assert @response.body.blank? - assert_equal "image/png", @response.header["Content-Type"] - assert_response :ok - end - - def test_head_with_location_header - get :head_with_location_header - assert @response.body.blank? - assert_equal "/foo", @response.headers["Location"] - assert_response :ok - end - - def test_head_with_location_object - with_routing do |set| - set.draw do - resources :customers - get ':controller/:action' - end - - get :head_with_location_object - assert @response.body.blank? - assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"] - assert_response :ok - end - end - - def test_head_with_custom_header - get :head_with_custom_header - assert @response.body.blank? - assert_equal "something", @response.headers["X-Custom-Header"] - assert_response :ok - end - - def test_head_with_www_authenticate_header - get :head_with_www_authenticate_header - assert @response.body.blank? - assert_equal "something", @response.headers["WWW-Authenticate"] - assert_response :ok - end - - def test_head_with_symbolic_status - get :head_with_symbolic_status, :status => "ok" - assert_equal 200, @response.status - assert_response :ok - - get :head_with_symbolic_status, :status => "not_found" - assert_equal 404, @response.status - assert_response :not_found - - get :head_with_symbolic_status, :status => "no_content" - assert_equal 204, @response.status - assert !@response.headers.include?('Content-Length') - assert_response :no_content - - Rack::Utils::SYMBOL_TO_STATUS_CODE.each do |status, code| - get :head_with_symbolic_status, :status => status.to_s - assert_equal code, @response.response_code - assert_response status + render :action => 'hello_world' end end - def test_head_with_integer_status - Rack::Utils::HTTP_STATUS_CODES.each do |code, message| - get :head_with_integer_status, :status => code.to_s - assert_equal message, @response.message + def conditional_hello_with_public_header + if stale?(:last_modified => Time.now.utc.beginning_of_day, :etag => [:foo, 123], :public => true) + render :action => 'hello_world' end end - def test_head_with_string_status - get :head_with_string_status, :status => "404 Eat Dirt" - assert_equal 404, @response.response_code - assert_equal "Not Found", @response.message - assert_response :not_found - end + def conditional_hello_with_public_header_with_record + record = Struct.new(:updated_at, :cache_key).new(Time.now.utc.beginning_of_day, "foo/123") - def test_head_with_status_code_first - get :head_with_status_code_first - assert_equal 403, @response.response_code - assert_equal "Forbidden", @response.message - assert_equal "something", @response.headers["X-Custom-Header"] - assert_response :forbidden + if stale?(record, :public => true) + render :action => 'hello_world' + end end - def test_using_layout_around_block - get :render_using_layout_around_block - assert_equal "Before (David)\nInside from block\nAfter", @response.body + def conditional_hello_with_public_header_and_expires_at + expires_in 1.minute + if stale?(:last_modified => Time.now.utc.beginning_of_day, :etag => [:foo, 123], :public => true) + render :action => 'hello_world' + end end - def test_using_layout_around_block_in_main_layout_and_within_content_for_layout - get :render_using_layout_around_block_in_main_layout_and_within_content_for_layout - assert_equal "Before (Anthony)\nInside from first block in layout\nAfter\nBefore (David)\nInside from block\nAfter\nBefore (Ramm)\nInside from second block in layout\nAfter\n", @response.body + def conditional_hello_with_expires_in + expires_in 60.1.seconds + render :action => 'hello_world' end - def test_partial_only - get :partial_only - assert_equal "only partial", @response.body - assert_equal "text/html", @response.content_type + def conditional_hello_with_expires_in_with_public + expires_in 1.minute, :public => true + render :action => 'hello_world' end - def test_should_render_html_formatted_partial - get :partial - assert_equal "partial html", @response.body - assert_equal "text/html", @response.content_type + def conditional_hello_with_expires_in_with_must_revalidate + expires_in 1.minute, :must_revalidate => true + render :action => 'hello_world' end - def test_render_html_formatted_partial_even_with_other_mime_time_in_accept - @request.accept = "text/javascript, text/html" - - get :partial_html_erb - - assert_equal "partial.html.erb", @response.body.strip - assert_equal "text/html", @response.content_type + def conditional_hello_with_expires_in_with_public_and_must_revalidate + expires_in 1.minute, :public => true, :must_revalidate => true + render :action => 'hello_world' end - def test_should_render_html_partial_with_formats - get :partial_formats_html - assert_equal "partial html", @response.body - assert_equal "text/html", @response.content_type + def conditional_hello_with_expires_in_with_public_with_more_keys + expires_in 1.minute, :public => true, 's-maxage' => 5.hours + render :action => 'hello_world' end - def test_render_to_string_partial - get :render_to_string_with_partial - assert_equal "only partial", assigns(:partial_only) - assert_equal "Hello: david", assigns(:partial_with_locals) - assert_equal "text/html", @response.content_type + def conditional_hello_with_expires_in_with_public_with_more_keys_old_syntax + expires_in 1.minute, :public => true, :private => nil, 's-maxage' => 5.hours + render :action => 'hello_world' end - def test_render_to_string_with_template_and_html_partial - get :render_to_string_with_template_and_html_partial - assert_equal "**only partial**\n", assigns(:text) - assert_equal "only partial\n", assigns(:html) - assert_equal "only html partial\n", @response.body - assert_equal "text/html", @response.content_type + def conditional_hello_with_expires_now + expires_now + render :action => 'hello_world' end - def test_render_to_string_and_render_with_different_formats - get :render_to_string_and_render_with_different_formats - assert_equal "only partial\n", assigns(:html) - assert_equal "**only partial**\n", @response.body - assert_equal "text/plain", @response.content_type + def conditional_hello_with_cache_control_headers + response.headers['Cache-Control'] = 'no-transform' + expires_now + render :action => 'hello_world' end - def test_render_template_within_a_template_with_other_format - get :render_template_within_a_template_with_other_format - expected = "only html partial

This is grand!

" - assert_equal expected, @response.body.strip - assert_equal "text/html", @response.content_type + def conditional_hello_with_bangs + render :action => 'hello_world' end + before_action :handle_last_modified_and_etags, :only=>:conditional_hello_with_bangs - def test_partial_with_counter - get :partial_with_counter - assert_equal "5", @response.body + def handle_last_modified_and_etags + fresh_when(:last_modified => Time.now.utc.beginning_of_day, :etag => [ :foo, 123 ]) end - def test_partial_with_locals - get :partial_with_locals - assert_equal "Hello: david", @response.body + def heading + head :ok end - def test_partial_with_form_builder - get :partial_with_form_builder - assert_match(/