diff options
Diffstat (limited to 'actionpack')
31 files changed, 481 insertions, 1239 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 88cdd53336..ffafa7412d 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,1159 +1,3 @@ -## Rails 4.0.0 (unreleased) ## +* No changes. -* Fix explicit names on multiple file fields. If a file field tag has - the multiple option, it is turned into an array field (appending `[]`), - but if an explicit name is passed to `file_field` the `[]` is not - appended. - Fixes #9830. - - *Ryan McGeary* - -* Add block support for the `mail_to` helper, similar to the `link_to` helper. - - *Sam Pohlenz* - -* Automatically configure cookie-based sessions to be encrypted if - `secret_key_base` is set, falling back to signed if only `secret_token` - is set. Automatically upgrade existing signed cookie-based sessions from - Rails 3.x to be encrypted if both `secret_key_base` and `secret_token` - are set, or signed with the new key generator if only `secret_token` is - set. This leaves only the `config.session_store :cookie_store` option and - removes the two new options introduced in 4.0.0.beta1: - `encrypted_cookie_store` and `upgrade_signature_to_encryption_cookie_store`. - - *Trevor Turk* - -* Ensure consistent fallback to the default layout lookup for layouts set - using symbols or procs that return `nil`. - - All of the following layouts will result in the default layout lookup: - - layout nil - - layout proc { nil } - - layout :returns_nil - def returns_nil - nil - end - - Previously symbols and procs which returned `nil` resulted in no layout which - differed from the `layout nil` behavior. To get the "no layout" behavior just - return `false` instead of `nil` for `layout`. - - *Chris Nicola* - -* Create `UpgradeLegacySignedCookieJar` to transparently upgrade existing signed - cookies generated by Rails 3.x to avoid invalidating them when upgrading to Rails 4.x. - - *Trevor Turk + Neeraj Singh* - -* Raise an `ArgumentError` when a clashing named route is defined. - - *Trevor Turk* - -* Allow default url options to accept host with protocol such as `http://` - - config.action_mailer.default_url_options = { host: "http://mydomain.com" } - - *Richard Schneeman* - -* Ensure that digest authentication responds with a 401 status when a basic - header is received. - - *Brad Dunbar* - -* Include I18n locale fallbacks in view lookup. - Fixes #3512. - - *Juan Barreneche* - -* Integration and functional tests allow headers and rack env - variables to be passed when performing requests. - Fixes #6513. - - Example: - - # integration test - get "/success", {}, "HTTP_REFERER" => "http://test.com/", - "Accepts" => "text/plain, text/html" - - # functional test - @request.headers["Accepts"] = "text/plain, text/html" - - *Yves Senn* - -* Http::Headers respects headers that are not prefixed with HTTP_ - - *Yves Senn* - -* Fix incorrectly appended square brackets to a multiple select box - if an explicit name has been given and it already ends with "[]" - - Before: - - select(:category, [], {}, multiple: true, name: "post[category][]") - # => <select name="post[category][][]" ...> - - After: - - select(:category, [], {}, multiple: true, name: "post[category][]") - # => <select name="post[category][]" ...> - - *Olek Janiszewski* - -* Fixed regression when using `assert_template` to verify files sent using - `render file: 'README.md'`. - Fixes #9464. - - *Justin Coyne* - -* Fixed `ActionView::Helpers::CaptureHelper#content_for` regression when trying to use it in - a boolean statement. - Fixes #9360. - - *Nikolay Shebanov* - -* `format: true` does not override existing format constraints. - Fixes #9466. - - Example: - - # This will force the .json extension. - get '/json_only', to: ok, format: true, constraints: { format: /json/ } - - *Yves Senn* - -* Skip valid encoding checks for non-String parameters that come - from the matched route's defaults. - Fixes #9435. - - Example: - - root to: 'main#posts', page: 1 - - *Yves Senn* - -* Don't verify Regexp requirements for non-Regexp `:constraints`. - Fixes #9432. - - Example: - - get '/photos.:format' => 'feeds#photos', constraints: {format: 'xml'} - - *Yves Senn* - -* Make `ActionDispatch::Journey::Path::Pattern#new` raise more meaningful exception message. - - *Thierry Zires* - - -## Rails 4.0.0.beta1 (February 25, 2013) ## - -* Fix `respond_to` not using formats that have no block if all is present. *Michael Grosser* - -* New applications use an encrypted session store by default. - - *Santiago Pastorino* - -* Determine the controller#action from only the matched path when using the - shorthand syntax. Previously the complete path was used, which led - to problems with nesting (scopes and namespaces). - Fixes #7554. - - Example: - - # This will route to questions#new. - scope ':locale' do - get 'questions/new' - end - - *Yves Senn* - -* Remove support for parsing XML parameters from request. If you still want to parse XML - parameters, please install `actionpack-xml_parser' gem. - - *Prem Sichanugrist* - -* Remove support for parsing YAML parameters from request. - - *Aaron Patterson* - -* Add a message when you have no routes defined to both `rake routes` and - GET "/rails/info/routes" that lets you know you have none defined and links - to the Rails guide on the topic. - - *Steve Klabnik* - -* Change `image_alt` method to replace underscores/hyphens to spaces in filenames. - - Previously, underscored filenames became `alt="A_long_file_name_with_underscores"` - in HTML, which is poor for accessibility. For instance, Apple's VoiceOver Utility - pronounces each underscore. `A_long_file_name` thus would be read as `A underscore - long underscore file underscore name.` Now underscored or hyphenated filenames - (both of which are very popular naming conventions) read more naturally in - screen readers by converting both hyphens and underscores to spaces. - - Before: - - image_tag('underscored_file_name.png') - # => <img alt="Underscored_file_name" src="/assets/underscored_file_name.png" /> - - After: - - image_tag('underscored_file_name.png') - # => <img alt="Underscored file name" src="/assets/underscored_file_name.png" /> - - *Nick Cox* - -* We don't support Ruby constant notation in the `:controller` option for route - definitions. So, this raises an `ArgumentError` now: - - resources :posts, controller: "Admin::Posts" # WRONG - - Use path notation instead: - - resources :posts, controller: "admin/posts" # RIGHT - - *Yves Senn* - -* `assert_template` can be used to verify the locals of partials, - which live inside a directory. - - # Prefixed partials inside directories worked and still work. - assert_template partial: 'directory/_partial', locals: {name: 'John'} - - # This did not work but does now. - assert_template partial: 'directory/partial', locals: {name: 'John'} - - Fixes #8516. - - *Yves Senn* - -* Fix `content_tag_for` with array HTML option. - It would embed array as string instead of joining it like `content_tag` does: - - content_tag(:td, class: ["foo", "bar"]){} - # => <td class="foo bar"></td> - - Before: - - content_tag_for(:td, item, class: ["foo", "bar"]) - # => <td class="item ["foo", "bar"]" id="item_1"></td> - - After: - - content_tag_for(:td, item, class: ["foo", "bar"]) - # => <td class="item foo bar" id="item_1"></td> - - *Semyon Perepelitsa* - -* Remove `BestStandardsSupport` middleware, !DOCTYPE html already triggers - standards mode per http://msdn.microsoft.com/en-us/library/jj676915(v=vs.85).aspx - and ChromeFrame header has been moved to `config.action_dispatch.default_headers` - - *Guillermo Iguaran* - -* Fix CSRF protection and `current_url?` helper to work with HEAD requests - now that `ActionDispatch::Head` has been removed in favor of `Rack::Head`. - - *Michiel Sikkes* - -* Change `asset_path` to not include `SCRIPT_NAME` when it's used - from a mounted engine. Fixes #8119. - - *Piotr Sarnacki* - -* Add JavaScript based routing path matcher to `/rails/info/routes`. - Routes can now be filtered by whether or not they match a path. - - *Richard Schneeman* - -* Change the behavior of route defaults so that explicit defaults are no longer - required where the key is not part of the path. For example: - - resources :posts, bucket_type: 'posts' - - will be required whenever constructing the url from a hash such as a functional - test or using `url_for` directly. However using the explicit form alters the - behavior so it's not required: - - resources :projects, defaults: { bucket_type: 'projects' } - - This changes existing behavior slightly in that any routes which only differ - in their defaults will match the first route rather than the closest match. - - *Andrew White* - -* Add support for routing constraints other than Regexp and String. - For example this now allows the use of arrays like this: - - get '/foo/:action', to: 'foo', constraints: { subdomain: %w[www admin] } - - or constraints where the request method returns an Fixnum like this: - - get '/foo', to: 'foo#index', constraints: { port: 8080 } - - Note that this only applies to constraints on the request - path constraints - still need to be specified as Regexps as the various constraints are compiled - into a single Regexp. - - *Andrew White* - -* Fix a bug in integration tests where setting the port via a url passed to - the process method was ignored when constructing the request environment. - - *Andrew White* - -* Allow `:selected` to be set on `date_select` tag helper. - - *Colin Burn-Murdoch* - -* Fixed JSON params parsing regression for non-object JSON content. - - *Dylan Smith* - -* Extract `ActionDispatch::PerformanceTest` into https://github.com/rails/rails-perftest - You can add the gem to your Gemfile to keep using performance tests. - - gem 'rails-perftest' - - *Yves Senn* - -* Added view_cache_dependency API for declaring dependencies that affect - cache digest computation. - - *Jamis Buck* - -* `image_submit_tag` will set `alt` attribute from image source if not - specified. - - *Nihad Abbasov* - -* Do not generate local variables for partials without object or collection. - Previously rendering a partial without giving `:object` or `:collection` - would generate a local variable with the partial name by default. - - *Carlos Antonio da Silva* - -* Return the last valid, non-private IP address from the X-Forwarded-For, - Client-IP and Remote-Addr headers, in that order. Document the rationale - for that decision, and describe the options that can be passed to the - RemoteIp middleware to change it. - Fixes #7979. - - *André Arko*, *Steve Klabnik*, *Alexey Gaziev* - -* Do not append second slash to `root_url` when using `trailing_slash: true` - Fixes #8700. - - Before: - - root_url(trailing_slash: true) # => http://test.host// - - After: - - root_url(trailing_slash: true) # => http://test.host/ - - *Yves Senn* - -* Allow to toggle dumps on error pages. - - *Gosha Arinich* - -* Fix a bug in `content_tag_for` that prevents it from working without a block. - - *Jasl* - -* Change the stylesheet of exception pages for development mode. - Additionally display also the line of code and fragment that raised - the exception in all exceptions pages. - - *Guillermo Iguaran + Jorge Cuadrado* - -* Do not append `charset=` parameter when `head` is called with a - `:content_type` option. - Fixes #8661. - - *Yves Senn* - -* Added `Mime::NullType` class. This allows to use `html?`, `xml?`, `json?`, etc. - when the format of the request is unknown, without raising an exception. - - *Angelo Capilleri* - -* Integrate the Journey gem into Action Dispatch so that the global namespace - is not polluted with names that may be used as models. - - *Andrew White* - -* Extract support for email address obfuscation via `:encode`, `:replace_at`, and `replace_dot` - options from the `mail_to` helper into the `actionview-encoded_mail_to` gem. - - *Nick Reed + DHH* - -* Handle `:protocol` option in `stylesheet_link_tag` and `javascript_include_tag` - - *Vasiliy Ermolovich* - -* Clear url helper methods when routes are reloaded. *Andrew White* - -* Fix a bug in `ActionDispatch::Request#raw_post` that caused `env['rack.input']` - to be read but not rewound. - - *Matt Venables* - -* Prevent raising `EOFError` on multipart GET request (IE issue). *Adam Stankiewicz* - -* Rename all action callbacks from *_filter to *_action to avoid the misconception that these - callbacks are only suited for transforming or halting the response. With the new style, - it's more inviting to use them as they were intended, like setting shared ivars for views. - - Example: - - class PeopleController < ActionController::Base - before_action :set_person, except: [:index, :new, :create] - before_action :ensure_permission, only: [:edit, :update] - - ... - - private - def set_person - @person = current_account.people.find(params[:id]) - end - - def ensure_permission - current_person.can_change?(@person) - end - end - - The old *_filter methods still work with no deprecation notice. - - *DHH* - -* Add `cache_if` and `cache_unless` for conditional fragment caching: - - Example: - - <%= cache_if condition, project do %> - <b>All the topics on this project</b> - <%= render project.topics %> - <% end %> - - # and - - <%= cache_unless condition, project do %> - <b>All the topics on this project</b> - <%= render project.topics %> - <% end %> - - *Stephen Ausman + Fabrizio Regini + Angelo Capilleri* - -* Add logging filter capability for redirect URLs: - - config.filter_redirect << 'http://please.hide.it/' - - *Fabrizio Regini* - -* Fixed a bug that ignores constraints on a glob route. This was caused because the constraint - regular expression is overwritten when the `routes.rb` file is processed. Fixes #7924 - - *Maura Fitzgerald* - -* More descriptive error messages when calling `render :partial` with - an invalid `:layout` argument. - - Fixes #8376. - - render partial: 'partial', layout: true - - # results in ActionView::MissingTemplate: Missing partial /true - - *Yves Senn* - -* Sweepers was extracted from Action Controller as `rails-observers` gem. - - *Rafael Mendonça França* - -* Add option flag to `CacheHelper#cache` to manually bypass automatic template digests: - - <% cache project, skip_digest: true do %> - ... - <% end %> - - *Drew Ulmer* - -* Do not sort Hash options in `grouped_options_for_select`. *Sergey Kojin* - -* Accept symbols as `send_data :disposition` value *Elia Schito* - -* Add i18n scope to `distance_of_time_in_words`. *Steve Klabnik* - -* `assert_template`: - - is no more passing with empty string. - - is now validating option keys. It accepts: `:layout`, `:partial`, `:locals` and `:count`. - - *Roberto Soares* - -* Allow setting a symbol as path in scope on routes. This is now allowed: - - scope :api do - resources :users - end - - It is also possible to pass multiple symbols to scope to shorten multiple nested scopes: - - scope :api do - scope :v1 do - resources :users - end - end - - can be rewritten as: - - scope :api, :v1 do - resources :users - end - - *Guillermo Iguaran + Amparo Luna* - -* Fix error when using a non-hash query argument named "params" in `url_for`. - - Before: - - url_for(params: "") # => undefined method `reject!' for "":String - - After: - - url_for(params: "") # => http://www.example.com?params= - - *tumayun + Carlos Antonio da Silva* - -* Render every partial with a new `ActionView::PartialRenderer`. This resolves - issues when rendering nested partials. - Fixes #8197. - - *Yves Senn* - -* Introduce `ActionView::Template::Handlers::ERB.escape_whitelist`. This is a list - of mime types where template text is not html escaped by default. It prevents `Jack & Joe` - from rendering as `Jack & Joe` for the whitelisted mime types. The default whitelist - contains `text/plain`. - Fixes #7976. - - *Joost Baaij* - -* Fix input name when `multiple: true` and `:index` are set. - - Before: - - check_box("post", "comment_ids", { multiple: true, index: "foo" }, 1) - # => <input name=\"post[foo][comment_ids]\" type=\"hidden\" value=\"0\" /><input id=\"post_foo_comment_ids_1\" name=\"post[foo][comment_ids]\" type=\"checkbox\" value=\"1\" /> - - After: - - check_box("post", "comment_ids", { multiple: true, index: "foo" }, 1) - # => <input name=\"post[foo][comment_ids][]\" type=\"hidden\" value=\"0\" /><input id=\"post_foo_comment_ids_1\" name=\"post[foo][comment_ids][]\" type=\"checkbox\" value=\"1\" /> - - Fixes #8108. - - *Daniel Fox, Grant Hutchins & Trace Wax* - -* `date_select` helper accepts `with_css_classes: true` to add css classes similar with type - of generated select tags. - - *Pavel Nikitin* - -* Only non-js/css under `app/assets` path will be included in default `config.assets.precompile`. - - *Josh Peek* - -* Remove support for the `RAILS_ASSET_ID` environment configuration - (no longer needed now that we have the asset pipeline). - - *Josh Peek* - -* Remove old `asset_path` configuration (no longer needed now that we have the asset pipeline). - - *Josh Peek* - -* `assert_template` can be used to assert on the same template with different locals - Fixes #3675. - - *Yves Senn* - -* Remove old asset tag concatenation (no longer needed now that we have the asset pipeline). - - *Josh Peek* - -* Accept `:remote` as symbolic option for `link_to` helper. *Riley Lynch* - -* Warn when the `:locals` option is passed to `assert_template` outside of a view test case - Fixes #3415. - - *Yves Senn* - -* The `Rack::Cache` middleware is now disabled by default. To enable it, - set `config.action_dispatch.rack_cache = true` and add `gem rack-cache` to your Gemfile. - - *Guillermo Iguaran* - -* `ActionController::Base.page_cache_extension` option is deprecated - in favour of `ActionController::Base.default_static_extension`. - - *Francesco Rodriguez* - -* Action and Page caching has been extracted from Action Dispatch - as `actionpack-action_caching` and `actionpack-page_caching` gems. - Please read the `README.md` file on both gems for the usage. - - *Francesco Rodriguez* - -* Failsafe exception returns `text/plain`. *Steve Klabnik* - -* Rename internal variables on `ActionController::TemplateAssertions` to prevent - naming collisions. `@partials`, `@templates` and `@layouts` are now prefixed with an underscore. - Fixes #7459. - - *Yves Senn* - -* `resource` and `resources` don't modify the passed options hash. - Fixes #7777. - - *Yves Senn* - -* Precompiled assets include aliases from `foo.js` to `foo/index.js` and vice versa. - - # Precompiles phone-<digest>.css and aliases phone/index.css to phone.css. - config.assets.precompile = [ 'phone.css' ] - - # Precompiles phone/index-<digest>.css and aliases phone.css to phone/index.css. - config.assets.precompile = [ 'phone/index.css' ] - - # Both of these work with either precompile thanks to their aliases. - <%= stylesheet_link_tag 'phone', media: 'all' %> - <%= stylesheet_link_tag 'phone/index', media: 'all' %> - - *Jeremy Kemper* - -* `assert_template` is no more passing with what ever string that matches - with the template name. - - Before when we have a template `/layout/hello.html.erb`, `assert_template` - was passing with any string that matches. This behavior allowed false - positive like: - - assert_template "layout" - assert_template "out/hello" - - Now it only passes with: - - assert_template "layout/hello" - assert_template "hello" - - Fixes #3849. - - *Hugolnx* - -* `image_tag` will set the same width and height for image if numerical value - passed to `size` option. - - *Nihad Abbasov* - -* Deprecate `Mime::Type#verify_request?` and `Mime::Type.browser_generated_types`, - since they are no longer used inside of Rails, they will be removed in Rails 4.1. - - *Michael Grosser* - -* `ActionDispatch::Http::UploadedFile` now delegates `close` to its tempfile. *Sergio Gil* - -* Add `ActionController::StrongParameters`, this module converts `params` hash into - an instance of ActionController::Parameters that allows whitelisting of permitted - parameters. Non-permitted parameters are forbidden to be used in Active Model by default - For more details check the documentation of the module or the - [strong_parameters gem](https://github.com/rails/strong_parameters) - - *DHH + Guillermo Iguaran* - -* Remove Integration between `attr_accessible`/`attr_protected` and - `ActionController::ParamsWrapper`. ParamWrapper now wraps all the parameters returned - by the class method `attribute_names`. - - *Guillermo Iguaran* - -* Log now displays the correct status code when an exception is raised. - Fixes #7646. - - *Yves Senn* - -* Allow pass couple extensions to `ActionView::Template.register_template_handler` call. - - *Tima Maslyuchenko* - -* Sprockets integration has been extracted from Action Pack to the `sprockets-rails` - gem. `rails` gem is depending on `sprockets-rails` by default. - - *Guillermo Iguaran* - -* `ActionDispatch::Session::MemCacheStore` now uses `dalli` instead of the deprecated - `memcache-client` gem. - - *Arun Agrawal + Guillermo Iguaran* - -* Support multiple etags in If-None-Match header. *Travis Warlick* - -* Allow to configure how unverified request will be handled using `:with` - option in `protect_from_forgery` method. - - Valid unverified request handling methods are: - - - `:exception` - Raises ActionController::InvalidAuthenticityToken exception. - - `:reset_session` - Resets the session. - - `:null_session` - Provides an empty session during request but doesn't - reset it completely. Used as default if `:with` option is not specified. - - New applications are generated with: - - protect_from_forgery with: :exception - - *Sergey Nartimov* - -* Add `.ruby` template handler, this handler simply allows arbitrary Ruby code as a template. *Guillermo Iguaran* - -* Add `separator` option for `ActionView::Helpers::TextHelper#excerpt`: - - excerpt('This is a very beautiful morning', 'very', separator: ' ', radius: 1) - # => ...a very beautiful... - - *Guirec Corbel* - -* Added controller-level etag additions that will be part of the action etag computation *Jeremy Kemper/DHH* - - class InvoicesController < ApplicationController - etag { current_user.try :id } - - def show - # Etag will differ even for the same invoice when it's viewed by a different current_user - @invoice = Invoice.find(params[:id]) - fresh_when(@invoice) - end - end - -* Add automatic template digests to all `CacheHelper#cache` calls (originally spiked in the `cache_digests` plugin) *DHH* - -* When building a URL fails, add missing keys provided by Journey. Failed URL - generation now returns a 500 status instead of a 404. - - *Richard Schneeman* - -* Deprecate availability of `ActionView::RecordIdentifier` in controllers by default. - It's view specific and can be easily included in controllers manually if someone - really needs it. Also deprecate calling `ActionController::RecordIdentifier.dom_id` and - `dom_class` directly, in favor of `ActionView::RecordIdentifier.dom_id` and `dom_class`. - `RecordIdentifier` will be removed from `ActionController::Base` in Rails 4.1. - - *Piotr Sarnacki* - -* Fix `ActionView::RecordIdentifier` to work as a singleton. *Piotr Sarnacki* - -* Deprecate `Template#mime_type`, it will be removed in Rails 4.1 in favor of `#type`. - *Piotr Sarnacki* - -* Move vendored html-scanner from `action_controller` to `action_view` directory. If you - require it directly, please use 'action_view/vendor/html-scanner', reference to - 'action_controller/vendor/html-scanner' will be removed in Rails 4.1. *Piot Sarnacki* - -* Fix handling of date selects when using both disabled and discard options. - Fixes #7431. - - *Vasiliy Ermolovich* - -* `ActiveRecord::SessionStore` is extracted out of Rails into a gem `activerecord-session_store`. - Setting `config.session_store` to `:active_record_store` will no longer work and will break - if the `activerecord-session_store` gem isn't available. *Prem Sichanugrist* - -* Fix `select_tag` when `option_tags` is nil. - Fixes #7404. - - *Sandeep Ravichandran* - -* Add `Request#formats=(extensions)` that lets you set multiple formats directly in a prioritized order. - - Example of using this for custom iphone views with an HTML fallback: - - class ApplicationController < ActionController::Base - before_filter :adjust_format_for_iphone_with_html_fallback - - private - def adjust_format_for_iphone_with_html_fallback - request.formats = [ :iphone, :html ] if request.env["HTTP_USER_AGENT"][/iPhone/] - end - end - - *DHH* - -* Add Routing Concerns to declare common routes that can be reused inside - others resources and routes. - - Code before: - - resources :messages do - resources :comments - end - - resources :posts do - resources :comments - resources :images, only: :index - end - - Code after: - - concern :commentable do - resources :comments - end - - concern :image_attachable do - resources :images, only: :index - end - - resources :messages, concerns: :commentable - - resources :posts, concerns: [:commentable, :image_attachable] - - *DHH + Rafael Mendonça França* - -* Add `start_hour` and `end_hour` options to the `select_hour` helper. *Evan Tann* - -* Raises an `ArgumentError` when the first argument in `form_for` contain `nil` - or is empty. - - *Richard Schneeman* - -* Add 'X-Frame-Options' => 'SAMEORIGIN' - 'X-XSS-Protection' => '1; mode=block' and - 'X-Content-Type-Options' => 'nosniff' - as default headers. - - *Egor Homakov* - -* Allow data attributes to be set as a first-level option for `form_for`, so you can write `form_for @record, data: { behavior: 'autosave' }` instead of `form_for @record, html: { data: { behavior: 'autosave' } }` *DHH* - -* Deprecate `button_to_function` and `link_to_function` helpers. - - We recommend the use of Unobtrusive JavaScript instead. For example: - - link_to "Greeting", "#", class: "nav_link" - - $(function() { - $('.nav_link').click(function() { - // Some complex code - - return false; - }); - }); - - or - - link_to "Greeting", '#', onclick: "alert('Hello world!'); return false", class: "nav_link" - - for simple cases. - - *Rafael Mendonça França* - -* `javascript_include_tag :all` will now not include `application.js` if the file does not exists. *Prem Sichanugrist* - -* Send an empty response body when call `head` with status between 100 and 199, 204, 205 or 304. - - *Armand du Plessis* - -* Fixed issue with where digest authentication would not work behind a proxy. *Arthur Smith* - -* Added `ActionController::Live`. Mix it in to your controller and you can - stream data to the client live. For example: - - class FooController < ActionController::Base - include ActionController::Live - - def index - 100.times { - # Client will see this as it's written - response.stream.write "hello world\n" - sleep 1 - } - response.stream.close - end - end - - *Aaron Patterson* - -* Remove `ActionDispatch::Head` middleware in favor of `Rack::Head`. *Santiago Pastorino* - -* Deprecate `:confirm` in favor of `data: { confirm: "Text" }` option for `button_to`, `button_tag`, `image_submit_tag`, `link_to` and `submit_tag` helpers. - - *Carlos Galdino + Rafael Mendonça França* - -* Show routes in exception page while debugging a `RoutingError` in development. - - *Richard Schneeman + Mattt Thompson + Yves Senn* - -* Add `ActionController::Flash.add_flash_types` method to allow people to register their own flash types. e.g.: - - class ApplicationController - add_flash_types :error, :warning - end - - If you add the above code, you can use `<%= error %>` in an erb, and `redirect_to /foo, error: 'message'` in a controller. - - *kennyj* - -* Remove Active Model dependency from Action Pack. *Guillermo Iguaran* - -* Support unicode characters in routes. Route will be automatically escaped, so instead of manually escaping: - - get Rack::Utils.escape('こんにちは') => 'home#index' - - You just have to write the unicode route: - - get 'こんにちは' => 'home#index' - - *kennyj* - -* Return proper format on exceptions. *Santiago Pastorino* - -* Allow to use `mounted_helpers` (helpers for accessing mounted engines) in `ActionView::TestCase`. *Piotr Sarnacki* - -* Include `mounted_helpers` (helpers for accessing mounted engines) in `ActionDispatch::IntegrationTest` by default. *Piotr Sarnacki* - -* Extracted redirect logic from `ActionController::ForceSSL::ClassMethods.force_ssl` into `ActionController::ForceSSL#force_ssl_redirect` - - *Jeremy Friesen* - -* Make possible to use a block in `button_to` if the button text is hard - to fit into the name parameter, e.g.: - - <%= button_to [:make_happy, @user] do %> - Make happy <strong><%= @user.name %></strong> - <% end %> - # => "<form method="post" action="/users/1/make_happy" class="button_to"> - # <div> - # <button type="submit"> - # Make happy <strong>Name</strong> - # </button> - # </div> - # </form>" - - *Sergey Nartimov* - -* Change a way of ordering helpers from several directories. Previously, - when loading helpers from multiple paths, all of the helpers files were - gathered into one array an then they were sorted. Helpers from different - directories should not be mixed before loading them to make loading more - predictable. The most common use case for such behavior is loading helpers - from engines. When you load helpers from application and engine Foo, in - that order, first rails will load all of the helpers from application, - sorted alphabetically and then it will do the same for Foo engine. - - *Piotr Sarnacki* - -* `truncate` now always returns an escaped HTML-safe string. The option `:escape` can be used as - false to not escape the result. - - *Li Ellis Gallardo + Rafael Mendonça França* - -* `truncate` now accepts a block to show extra content when the text is truncated. *Li Ellis Gallardo* - -* Add `week_field`, `week_field_tag`, `month_field`, `month_field_tag`, `datetime_local_field`, - `datetime_local_field_tag`, `datetime_field` and `datetime_field_tag` helpers. *Carlos Galdino* - -* Add `color_field` and `color_field_tag` helpers. *Carlos Galdino* - -* `assert_generates`, `assert_recognizes`, and `assert_routing` all raise - `Assertion` instead of `RoutingError` *David Chelimsky* - -* URL path parameters with invalid encoding now raise `ActionController::BadRequest`. *Andrew White* - -* Malformed query and request parameter hashes now raise `ActionController::BadRequest`. *Andrew White* - -* Add `divider` option to `grouped_options_for_select` to generate a separator - `optgroup` automatically, and deprecate `prompt` as third argument, in favor - of using an options hash. *Nicholas Greenfield* - -* Add `time_field` and `time_field_tag` helpers which render an `input[type="time"]` tag. *Alex Soulim* - -* Removed old text helper apis from `highlight`, `excerpt` and `word_wrap`. *Jeremy Walker* - -* Templates without a handler extension now raises a deprecation warning but still - defaults to ERB. In future releases, it will simply return the template contents. *Steve Klabnik* - -* Deprecate `:disable_with` in favor of `data: { disable_with: "Text" }` option from `submit_tag`, `button_tag` and `button_to` helpers. - - *Carlos Galdino + Rafael Mendonça França* - -* Remove `:mouseover` option from `image_tag` helper. *Rafael Mendonça França* - -* The `select` method (select tag) forces `:include_blank` if `required` is true and - `display size` is one and `multiple` is not true. *Angelo Capilleri* - -* Copy literal route constraints to defaults so that url generation know about them. - The copied constraints are `:protocol`, `:subdomain`, `:domain`, `:host` and `:port`. - - *Andrew White* - -* `respond_to` and `respond_with` now raise `ActionController::UnknownFormat` instead - of directly returning head 406. The exception is rescued and converted to 406 - in the exception handling middleware. *Steven Soroka* - -* Allows `assert_redirected_to` to match against a regular expression. *Andy Lindeman* - -* Add backtrace to development routing error page. *Richard Schneeman* - -* Replace `include_seconds` boolean argument with `include_seconds: true` option - in `distance_of_time_in_words` and `time_ago_in_words` signature. *Dmitriy Kiriyenko* - -* Make current object and counter (when it applies) variables accessible when - rendering templates with :object / :collection. *Carlos Antonio da Silva* - -* JSONP now uses mimetype `text/javascript` instead of `application/json`. *omjokine* - -* Allow to lazy load `default_form_builder` by passing a `String` instead of a constant. *Piotr Sarnacki* - -* Session arguments passed to `process` calls in functional tests are now merged into - the existing session, whereas previously they would replace the existing session. - This change may break some existing tests if they are asserting the exact contents of - the session but should not break existing tests that only assert individual keys. - - *Andrew White* - -* Add `index` method to FormBuilder class. *Jorge Bejar* - -* Remove the leading \n added by textarea on `assert_select`. *Santiago Pastorino* - -* Changed default value for `config.action_view.embed_authenticity_token_in_remote_forms` - to `false`. This change breaks remote forms that need to work also without JavaScript, - so if you need such behavior, you can either set it to `true` or explicitly pass - `authenticity_token: true` in form options. - -* Added `ActionDispatch::SSL` middleware that when included force all the requests to be under HTTPS protocol. *Rafael Mendonça França* - -* Add `include_hidden` option to select tag. With `include_hidden: false` select with `multiple` attribute doesn't generate hidden input with blank value. *Vasiliy Ermolovich* - -* Removed default `size` option from the `text_field`, `search_field`, `telephone_field`, `url_field`, `email_field` helpers. *Philip Arndt* - -* Removed default `cols` and `rows` options from the `text_area` helper. *Philip Arndt* - -* Adds support for layouts when rendering a partial with a given collection. *serabe* - -* Allows the route helper `root` to take a string argument. For example, `root 'pages#main'`. *bcardarella* - -* Forms of persisted records use always PATCH (via the `_method` hack). *fxn* - -* For resources, both PATCH and PUT are routed to the `update` action. *fxn* - -* Don't ignore `force_ssl` in development. This is a change of behavior - use a `:if` condition to recreate the old behavior. - - class AccountsController < ApplicationController - force_ssl if: :ssl_configured? - - def ssl_configured? - !Rails.env.development? - end - end - - *Pat Allan* - -* Adds support for the PATCH verb: - * Request objects respond to `patch?`. - * Routes have a new `patch` method, and understand `:patch` in the - existing places where a verb is configured, like `:via`. - * New method `patch` available in functional tests. - * If `:patch` is the default verb for updates, edits are - tunneled as PATCH rather than as PUT, and routing acts accordingly. - * New method `patch_via_redirect` available in integration tests. - - *dlee* - -* Integration tests support the `OPTIONS` method. *Jeremy Kemper* - -* `expires_in` accepts a `must_revalidate` flag. If true, "must-revalidate" - is added to the Cache-Control header. *fxn* - -* Add `date_field` and `date_field_tag` helpers which render an `input[type="date"]` tag *Olek Janiszewski* - -* Adds `image_url`, `javascript_url`, `stylesheet_url`, `audio_url`, `video_url`, and `font_url` - to assets tag helper. These URL helpers will return the full path to your assets. This is useful - when you are going to reference this asset from external host. *Prem Sichanugrist* - -* Default responder will now always use your overridden block in `respond_with` to render your response. *Prem Sichanugrist* - -* Allow `value_method` and `text_method` arguments from `collection_select` and - `options_from_collection_for_select` to receive an object that responds to `:call`, - such as a `proc`, to evaluate the option in the current element context. This works - the same way with `collection_radio_buttons` and `collection_check_boxes`. - - *Carlos Antonio da Silva + Rafael Mendonça França* - -* Add `collection_check_boxes` form helper, similar to `collection_select`: - Example: - - collection_check_boxes :post, :author_ids, Author.all, :id, :name - # Outputs something like: - <input id="post_author_ids_1" name="post[author_ids][]" type="checkbox" value="1" /> - <label for="post_author_ids_1">D. Heinemeier Hansson</label> - <input id="post_author_ids_2" name="post[author_ids][]" type="checkbox" value="2" /> - <label for="post_author_ids_2">D. Thomas</label> - <input name="post[author_ids][]" type="hidden" value="" /> - - The label/check_box pairs can be customized with a block. - - *Carlos Antonio da Silva + Rafael Mendonça França* - -* Add `collection_radio_buttons` form helper, similar to `collection_select`: - Example: - - collection_radio_buttons :post, :author_id, Author.all, :id, :name - # Outputs something like: - <input id="post_author_id_1" name="post[author_id]" type="radio" value="1" /> - <label for="post_author_id_1">D. Heinemeier Hansson</label> - <input id="post_author_id_2" name="post[author_id]" type="radio" value="2" /> - <label for="post_author_id_2">D. Thomas</label> - - The label/radio_button pairs can be customized with a block. - - *Carlos Antonio da Silva + Rafael Mendonça França* - -* `check_box` with `:form` html5 attribute will now replicate the `:form` - attribute to the hidden field as well. *Carlos Antonio da Silva* - -* `label` form helper accepts `for: nil` to not generate the attribute. *Carlos Antonio da Silva* - -* Add `:format` option to `number_to_percentage`. *Rodrigo Flores* - -* Add `config.action_view.logger` to configure logger for Action View. *Rafael Mendonça França* - -* Deprecated `ActionController::Integration` in favour of `ActionDispatch::Integration`. - -* Deprecated `ActionController::IntegrationTest` in favour of `ActionDispatch::IntegrationTest`. - -* Deprecated `ActionController::PerformanceTest` in favour of `ActionDispatch::PerformanceTest`. - -* Deprecated `ActionController::AbstractRequest` in favour of `ActionDispatch::Request`. - -* Deprecated `ActionController::Request` in favour of `ActionDispatch::Request`. - -* Deprecated `ActionController::AbstractResponse` in favour of `ActionDispatch::Response`. - -* Deprecated `ActionController::Response` in favour of `ActionDispatch::Response`. - -* Deprecated `ActionController::Routing` in favour of `ActionDispatch::Routing`. - -* `check_box helper` with `disabled: true` will generate a disabled - hidden field to conform with the HTML convention where disabled fields are - not submitted with the form. This is a behavior change, previously the hidden - tag had a value of the disabled checkbox. *Tadas Tamosauskas* - -* `favicon_link_tag` helper will now use the favicon in app/assets by default. *Lucas Caton* - -* `ActionView::Helpers::TextHelper#highlight` now defaults to the - HTML5 `mark` element. *Brian Cardarella* - -Please check [3-2-stable](https://github.com/rails/rails/blob/3-2-stable/actionpack/CHANGELOG.md) for previous changes. +Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/actionpack/CHANGELOG.md) for previous changes. diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index bac994496e..8e7bdf620e 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -309,6 +309,7 @@ module AbstractController 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? diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 143b3e0cbd..b84c9e78c3 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -36,8 +36,7 @@ module ActionController raise "MiddlewareStack#build requires an app" unless app middlewares.reverse.inject(app) do |a, middleware| - middleware.valid?(action) ? - middleware.build(a) : a + middleware.valid?(action) ? middleware.build(a) : a end end end @@ -57,7 +56,7 @@ module ActionController # And then to route requests to your metal controller, you would add # something like this to <tt>config/routes.rb</tt>: # - # match 'hello', to: HelloController.action(:index) + # get 'hello', to: HelloController.action(:index) # # The +action+ method returns a valid Rack application for the \Rails # router to dispatch to. diff --git a/actionpack/lib/action_controller/metal/force_ssl.rb b/actionpack/lib/action_controller/metal/force_ssl.rb index f1e8714a86..b8afce42c9 100644 --- a/actionpack/lib/action_controller/metal/force_ssl.rb +++ b/actionpack/lib/action_controller/metal/force_ssl.rb @@ -1,3 +1,6 @@ +require 'active_support/core_ext/hash/except' +require 'active_support/core_ext/hash/slice' + module ActionController # This module provides a method which will redirect browser to use HTTPS # protocol. This will ensure that user's sensitive information will be @@ -14,6 +17,10 @@ module ActionController extend ActiveSupport::Concern include AbstractController::Callbacks + ACTION_OPTIONS = [:only, :except, :if, :unless] + URL_OPTIONS = [:protocol, :host, :domain, :subdomain, :port, :path] + REDIRECT_OPTIONS = [:status, :flash, :alert, :notice] + module ClassMethods # Force the request to this particular controller or specified actions to be # under HTTPS protocol. @@ -29,18 +36,34 @@ module ActionController # end # end # - # ==== Options - # * <tt>host</tt> - Redirect to a different host name - # * <tt>only</tt> - The callback should be run only for this action - # * <tt>except</tt> - The callback should be run for all actions except this action - # * <tt>if</tt> - A symbol naming an instance method or a proc; the callback - # will be called only when it returns a true value. - # * <tt>unless</tt> - A symbol naming an instance method or a proc; the callback - # will be called only when it returns a false value. + # ==== URL Options + # You can pass any of the following options to affect the redirect url + # * <tt>host</tt> - Redirect to a different host name + # * <tt>subdomain</tt> - Redirect to a different subdomain + # * <tt>domain</tt> - Redirect to a different domain + # * <tt>port</tt> - Redirect to a non-standard port + # * <tt>path</tt> - Redirect to a different path + # + # ==== Redirect Options + # You can pass any of the following options to affect the redirect status and response + # * <tt>status</tt> - Redirect with a custom status (default is 301 Moved Permanently) + # * <tt>flash</tt> - Set a flash message when redirecting + # * <tt>alert</tt> - Set a alert message when redirecting + # * <tt>notice</tt> - Set a notice message when redirecting + # + # ==== Action Options + # You can pass any of the following options to affect the before_action callback + # * <tt>only</tt> - The callback should be run only for this action + # * <tt>except</tt> - The callback should be run for all actions except this action + # * <tt>if</tt> - A symbol naming an instance method or a proc; the callback + # will be called only when it returns a true value. + # * <tt>unless</tt> - A symbol naming an instance method or a proc; the callback + # will be called only when it returns a false value. def force_ssl(options = {}) - host = options.delete(:host) - before_action(options) do - force_ssl_redirect(host) + action_options = options.slice(*ACTION_OPTIONS) + redirect_options = options.except(*ACTION_OPTIONS) + before_action(action_options) do + force_ssl_redirect(redirect_options) end end end @@ -48,14 +71,26 @@ module ActionController # Redirect the existing request to use the HTTPS protocol. # # ==== Parameters - # * <tt>host</tt> - Redirect to a different host name - def force_ssl_redirect(host = nil) + # * <tt>host_or_options</tt> - Either a host name or any of the url & redirect options + # available to the <tt>force_ssl</tt> method. + def force_ssl_redirect(host_or_options = nil) unless request.ssl? - redirect_options = {:protocol => 'https://', :status => :moved_permanently} - redirect_options.merge!(:host => host) if host - redirect_options.merge!(:params => request.query_parameters) + options = { + :protocol => 'https://', + :host => request.host, + :path => request.fullpath, + :status => :moved_permanently + } + + if host_or_options.is_a?(Hash) + options.merge!(host_or_options) + elsif host_or_options + options.merge!(:host => host_or_options) + end + + secure_url = ActionDispatch::Http::URL.url_for(options.slice(*URL_OPTIONS)) flash.keep if respond_to?(:flash) - redirect_to redirect_options + redirect_to secure_url, options.slice(*REDIRECT_OPTIONS) end end end diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index 23d70c9ea2..44703221f3 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -230,7 +230,7 @@ module ActionController # params = ActionController::Parameters.new({ # person: { # contact: { - # email: 'none@test.com' + # email: 'none@test.com', # phone: '555-1234' # } # } diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index a35a613158..41a286f0ed 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -455,13 +455,14 @@ module ActionController # # - +action+: The controller action to call. # - +parameters+: The HTTP parameters that you want to pass. This may - # be +nil+, a Hash, or a String that is appropriately encoded + # be +nil+, a hash, or a string that is appropriately encoded # (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>). - # - +session+: A Hash of parameters to store in the session. This may be +nil+. - # - +flash+: A Hash of parameters to store in the flash. This may be +nil+. + # - +session+: A hash of parameters to store in the session. This may be +nil+. + # - +flash+: A hash of parameters to store in the flash. This may be +nil+. + # + # You can also simulate POST, PATCH, PUT, DELETE, HEAD, and OPTIONS requests with + # +post+, +patch+, +put+, +delete+, +head+, and +options+. # - # You can also simulate POST, PATCH, PUT, DELETE, and HEAD requests with - # +#post+, +#patch+, +#put+, +#delete+, and +#head+. # Note that the request method is not verified. The different methods are # available to make the tests more expressive. def get(action, *args) @@ -469,37 +470,37 @@ module ActionController end # Simulate a POST request with the given parameters and set/volley the response. - # See +#get+ for more details. + # See +get+ for more details. def post(action, *args) process(action, "POST", *args) end # Simulate a PATCH request with the given parameters and set/volley the response. - # See +#get+ for more details. + # See +get+ for more details. def patch(action, *args) process(action, "PATCH", *args) end # Simulate a PUT request with the given parameters and set/volley the response. - # See +#get+ for more details. + # See +get+ for more details. def put(action, *args) process(action, "PUT", *args) end # Simulate a DELETE request with the given parameters and set/volley the response. - # See +#get+ for more details. + # See +get+ for more details. def delete(action, *args) process(action, "DELETE", *args) end # Simulate a HEAD request with the given parameters and set/volley the response. - # See +#get+ for more details. + # See +get+ for more details. def head(action, *args) process(action, "HEAD", *args) end # Simulate a OPTIONS request with the given parameters and set/volley the response. - # See +#get+ for more details. + # See +get+ for more details. def options(action, *args) process(action, "OPTIONS", *args) end diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 06e936cdb0..60a2cccdc5 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -55,6 +55,7 @@ module ActionDispatch # :nodoc: CONTENT_TYPE = "Content-Type".freeze SET_COOKIE = "Set-Cookie".freeze LOCATION = "Location".freeze + NO_CONTENT_CODES = [204, 304] cattr_accessor(:default_charset) { "utf-8" } cattr_accessor(:default_headers) @@ -289,7 +290,7 @@ module ActionDispatch # :nodoc: header[SET_COOKIE] = header[SET_COOKIE].join("\n") if header[SET_COOKIE].respond_to?(:join) - if [204, 304].include?(@status) + if NO_CONTENT_CODES.include?(@status) header.delete CONTENT_TYPE [status, header, []] else diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index ab5399c8ea..6f5a52c568 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -4,7 +4,9 @@ require 'active_support/core_ext/hash/slice' module ActionDispatch module Http module URL - IP_HOST_REGEXP = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ + IP_HOST_REGEXP = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ + HOST_REGEXP = /(^.*:\/\/)?([^:]+)(?::(\d+$))?/ + PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/ mattr_accessor :tld_length self.tld_length = 1 @@ -28,6 +30,7 @@ module ActionDispatch end def url_for(options = {}) + options = options.dup path = options.delete(:script_name).to_s.chomp("/") path << options.delete(:path).to_s @@ -59,15 +62,20 @@ module ActionDispatch result = "" unless options[:only_path] - protocol = extract_protocol(options) - unless options[:protocol] == false - result << protocol - result << ":" unless result.match(%r{:|//}) + if match = options[:host].match(HOST_REGEXP) + options[:protocol] ||= match[1] unless options[:protocol] == false + options[:host] = match[2] + options[:port] = match[3] unless options.key?(:port) end - result << "//" unless result.match("//") + + options[:protocol] = normalize_protocol(options) + options[:host] = normalize_host(options) + options[:port] = normalize_port(options) + + result << options[:protocol] result << rewrite_authentication(options) - result << host_or_subdomain_and_domain(options) - result << ":#{options.delete(:port)}" if options[:port] + result << options[:host] + result << ":#{options[:port]}" if options[:port] end result end @@ -76,6 +84,10 @@ module ActionDispatch host && IP_HOST_REGEXP !~ host end + def same_host?(options) + (options[:subdomain] == true || !options.key?(:subdomain)) && options[:domain].nil? + end + def rewrite_authentication(options) if options[:user] && options[:password] "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@" @@ -84,29 +96,47 @@ module ActionDispatch end end - # Extracts protocol http:// or https:// from options[:host] - # needs to be called whether the :protocol is being used or not - def extract_protocol(options) - if options[:host] && match = options[:host].match(/(^.*:\/\/)(.*)/) - options[:protocol] ||= match[1] - options[:host] = match[2] + def normalize_protocol(options) + case options[:protocol] + when nil + "http://" + when false, "//" + "//" + when PROTOCOL_REGEXP + "#{$1}://" + else + raise ArgumentError, "Invalid :protocol option: #{options[:protocol].inspect}" end - options[:protocol] || "http" end - def host_or_subdomain_and_domain(options) - return options[:host] if !named_host?(options[:host]) || (options[:subdomain].nil? && options[:domain].nil?) + def normalize_host(options) + return options[:host] if !named_host?(options[:host]) || same_host?(options) tld_length = options[:tld_length] || @@tld_length host = "" - unless options[:subdomain] == false - host << (options[:subdomain] || extract_subdomain(options[:host], tld_length)).to_param - host << "." + if options[:subdomain] == true || !options.key?(:subdomain) + host << extract_subdomain(options[:host], tld_length).to_param + elsif options[:subdomain].present? + host << options[:subdomain].to_param end + host << "." unless host.empty? host << (options[:domain] || extract_domain(options[:host], tld_length)) host end + + def normalize_port(options) + return nil if options[:port].nil? || options[:port] == false + + case options[:protocol] + when "//" + nil + when "https://" + options[:port].to_i == 443 ? nil : options[:port] + else + options[:port].to_i == 80 ? nil : options[:port] + end + end end def initialize(env) diff --git a/actionpack/lib/action_dispatch/journey/parser.y b/actionpack/lib/action_dispatch/journey/parser.y index a2e1afed32..040f8d5922 100644 --- a/actionpack/lib/action_dispatch/journey/parser.y +++ b/actionpack/lib/action_dispatch/journey/parser.y @@ -36,6 +36,7 @@ rule ; literal : LITERAL { result = Literal.new(val.first) } + ; dot : DOT { result = Dot.new(val.first) } ; diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb index 6fda085681..50e1853094 100644 --- a/actionpack/lib/action_dispatch/journey/route.rb +++ b/actionpack/lib/action_dispatch/journey/route.rb @@ -102,6 +102,10 @@ module ActionDispatch value === request.send(method).to_s when Array value.include?(request.send(method)) + when TrueClass + request.send(method).present? + when FalseClass + request.send(method).blank? else value === request.send(method) end diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb index 31868b1814..419e665d12 100644 --- a/actionpack/lib/action_dispatch/journey/router.rb +++ b/actionpack/lib/action_dispatch/journey/router.rb @@ -38,7 +38,9 @@ module ActionDispatch env['REMOTE_ADDR'] end - def [](k); env[k]; end + def [](k) + env[k] + end end attr_reader :request_class, :formatter diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb index 7489ce8028..1de3d14530 100644 --- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb +++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb @@ -9,9 +9,11 @@ module ActionDispatch 'ActionController::RoutingError' => :not_found, 'AbstractController::ActionNotFound' => :not_found, 'ActionController::MethodNotAllowed' => :method_not_allowed, + 'ActionController::UnknownHttpMethod' => :method_not_allowed, 'ActionController::NotImplemented' => :not_implemented, 'ActionController::UnknownFormat' => :not_acceptable, 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity, + 'ActionDispatch::ParamsParser::ParseError' => :bad_request, 'ActionController::BadRequest' => :bad_request, 'ActionController::ParameterMissing' => :bad_request ) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 80054c8a40..c3fd0c18ec 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -299,7 +299,7 @@ module ActionDispatch end end - # Invokes Rack::Mount::Utils.normalize path and ensure that + # Invokes Journey::Router::Utils.normalize_path and ensure that # (:locale) becomes (/:locale) instead of /(:locale). Except # for root cases, where the latter is the correct one. def self.normalize_path(path) @@ -945,6 +945,8 @@ module ActionDispatch VALID_ON_OPTIONS = [:new, :collection, :member] RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except, :param, :concerns] CANONICAL_ACTIONS = %w(index create new show update destroy) + RESOURCE_METHOD_SCOPES = [:collection, :member, :new] + RESOURCE_SCOPES = [:resource, :resources] class Resource #:nodoc: attr_reader :controller, :path, :options, :param @@ -1499,11 +1501,11 @@ module ActionDispatch end def resource_scope? #:nodoc: - [:resource, :resources].include? @scope[:scope_level] + RESOURCE_SCOPES.include? @scope[:scope_level] end def resource_method_scope? #:nodoc: - [:collection, :member, :new].include? @scope[:scope_level] + RESOURCE_METHOD_SCOPES.include? @scope[:scope_level] end def with_exclusive_scope diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index d48a83e6c6..342b6ec23d 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -170,9 +170,10 @@ module ActionDispatch def call(t, args) if args.size == arg_size && !args.last.is_a?(Hash) && optimize_routes_generation?(t) - @options.merge!(t.url_options) if t.respond_to?(:url_options) - @options[:path] = optimized_helper(args) - ActionDispatch::Http::URL.url_for(@options) + options = @options.dup + options.merge!(t.url_options) if t.respond_to?(:url_options) + options[:path] = optimized_helper(args) + ActionDispatch::Http::URL.url_for(options) else super end diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb index b5e47d78d1..fd08f392aa 100644 --- a/actionpack/lib/action_pack/version.rb +++ b/actionpack/lib/action_pack/version.rb @@ -1,7 +1,7 @@ module ActionPack # Returns the version of the currently loaded ActionPack as a Gem::Version def self.version - Gem::Version.new "4.0.0.beta1" + Gem::Version.new "4.1.0.beta" end module VERSION #:nodoc: diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index d3953c26b7..8fb5eb1548 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -808,7 +808,7 @@ module ActionView options[:max_years_allowed] = @options[:max_years_allowed] || 1000 if (options[:end] - options[:start]).abs > options[:max_years_allowed] - raise ArgumentError, "There're too many years options to be built. Are you sure you haven't mistyped something? You can provide the :max_years_allowed parameter" + raise ArgumentError, "There are too many years options to be built. Are you sure you haven't mistyped something? You can provide the :max_years_allowed parameter." end build_options_and_select(:year, val, options) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 7e65ebb4e4..719c9c09b5 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -380,7 +380,7 @@ module ActionView # should produce the desired results. def options_from_collection_for_select(collection, value_method, text_method, selected = nil) options = collection.map do |element| - [value_for_collection(element, text_method), value_for_collection(element, value_method)] + [value_for_collection(element, text_method), value_for_collection(element, value_method), option_html_attributes(element)] end selected, disabled = extract_selected_and_disabled(selected) select_deselect = { diff --git a/actionpack/lib/action_view/path_set.rb b/actionpack/lib/action_view/path_set.rb index d9c76366f8..91ee2ea8f5 100644 --- a/actionpack/lib/action_view/path_set.rb +++ b/actionpack/lib/action_view/path_set.rb @@ -1,5 +1,11 @@ module ActionView #:nodoc: # = Action View PathSet + # + # This class is used to store and access paths in Action View. A number of + # operations are defined so that you can search among the paths in this + # set and also perform operations on other +PathSet+ objects. + # + # A +LookupContext+ will use a +PathSet+ to store the paths in its context. class PathSet #:nodoc: include Enumerable diff --git a/actionpack/lib/action_view/renderer/abstract_renderer.rb b/actionpack/lib/action_view/renderer/abstract_renderer.rb index 6fb8cbb46c..73c19a0ae2 100644 --- a/actionpack/lib/action_view/renderer/abstract_renderer.rb +++ b/actionpack/lib/action_view/renderer/abstract_renderer.rb @@ -1,4 +1,19 @@ module ActionView + # This class defines the interface for a renderer. Each class that + # subclasses +AbstractRenderer+ is used by the base +Renderer+ class to + # render a specific type of object. + # + # The base +Renderer+ class uses its +render+ method to delegate to the + # renderers. These currently consist of + # + # PartialRenderer - Used for rendering partials + # TemplateRenderer - Used for rendering other types of templates + # StreamingTemplateRenderer - Used for streaming + # + # Whenever the +render+ method is called on the base +Renderer+ class, a new + # renderer object of the correct type is created, and the +render+ method on + # that new object is called in turn. This abstracts the setup and rendering + # into a separate classes for partials and templates. class AbstractRenderer #:nodoc: delegate :find_template, :template_exists?, :with_fallbacks, :with_layout_format, :formats, :to => :@lookup_context diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index 43a88b0623..821026268a 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -313,6 +313,13 @@ module ActionView private + # Sets up instance variables needed for rendering a partial. This method + # finds the options and details and extracts them. The method also contains + # logic that handles the type of object passed in as the partial. + # + # If +options[:partial]+ is a string, then the +@path+ instance variable is + # set to that string. Otherwise, the +options[:partial]+ object must + # respond to +to_partial_path+ in order to setup the path. def setup(context, options, block) @view = context partial = options[:partial] @@ -413,6 +420,13 @@ module ActionView end end + # Obtains the path to where the object's partial is located. If the object + # responds to +to_partial_path+, then +to_partial_path+ will be called and + # will provide the path. If the object does not respond to +to_partial_path+, + # then an +ArgumentError+ is raised. + # + # If +prefix_partial_path_with_controller_namespace+ is true, then this + # method will prefix the partial paths with a namespace. def partial_path(object = @object) object = object.to_model if object.respond_to?(:to_model) diff --git a/actionpack/lib/action_view/renderer/renderer.rb b/actionpack/lib/action_view/renderer/renderer.rb index 30a0c4be70..964b18337e 100644 --- a/actionpack/lib/action_view/renderer/renderer.rb +++ b/actionpack/lib/action_view/renderer/renderer.rb @@ -2,6 +2,12 @@ module ActionView # This is the main entry point for rendering. It basically delegates # to other objects like TemplateRenderer and PartialRenderer which # actually renders the template. + # + # The Renderer will parse the options from the +render+ or +render_body+ + # method and render a partial or a template based on the options. The + # +TemplateRenderer+ and +PartialRenderer+ objects are wrappers which do all + # the setup and logic necessary to render a view and a new object is created + # each time +render+ is called. class Renderer attr_accessor :lookup_context diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb index 92baad4523..4a05c00f8b 100644 --- a/actionpack/test/abstract/layouts_test.rb +++ b/actionpack/test/abstract/layouts_test.rb @@ -8,6 +8,8 @@ module AbstractControllerTests include AbstractController::Rendering include AbstractController::Layouts + abstract! + self.view_paths = [ActionView::FixtureResolver.new( "layouts/hello.erb" => "With String <%= yield %>", "layouts/hello_override.erb" => "With Override <%= yield %>", @@ -251,6 +253,10 @@ module AbstractControllerTests assert_equal "Hello nil!", controller.response_body end + test "when layout is specified as a proc, do not leak any methods into controller's action_methods" do + assert_equal Set.new(['index']), WithProc.action_methods + end + test "when layout is specified as a proc, call it and use the layout returned" do controller = WithProc.new controller.process(:index) diff --git a/actionpack/test/controller/force_ssl_test.rb b/actionpack/test/controller/force_ssl_test.rb index 6758668b7a..3655b90e32 100644 --- a/actionpack/test/controller/force_ssl_test.rb +++ b/actionpack/test/controller/force_ssl_test.rb @@ -14,8 +14,42 @@ class ForceSSLControllerLevel < ForceSSLController force_ssl end -class ForceSSLCustomDomain < ForceSSLController - force_ssl :host => "secure.test.host" +class ForceSSLCustomOptions < ForceSSLController + force_ssl :host => "secure.example.com", :only => :redirect_host + force_ssl :port => 8443, :only => :redirect_port + force_ssl :subdomain => 'secure', :only => :redirect_subdomain + force_ssl :domain => 'secure.com', :only => :redirect_domain + force_ssl :path => '/foo', :only => :redirect_path + force_ssl :status => :found, :only => :redirect_status + force_ssl :flash => { :message => 'Foo, Bar!' }, :only => :redirect_flash + force_ssl :alert => 'Foo, Bar!', :only => :redirect_alert + force_ssl :notice => 'Foo, Bar!', :only => :redirect_notice + + def force_ssl_action + render :text => action_name + end + + alias_method :redirect_host, :force_ssl_action + alias_method :redirect_port, :force_ssl_action + alias_method :redirect_subdomain, :force_ssl_action + alias_method :redirect_domain, :force_ssl_action + alias_method :redirect_path, :force_ssl_action + alias_method :redirect_status, :force_ssl_action + alias_method :redirect_flash, :force_ssl_action + alias_method :redirect_alert, :force_ssl_action + alias_method :redirect_notice, :force_ssl_action + + def use_flash + render :text => flash[:message] + end + + def use_alert + render :text => flash[:alert] + end + + def use_notice + render :text => flash[:notice] + end end class ForceSSLOnlyAction < ForceSSLController @@ -80,19 +114,77 @@ class ForceSSLControllerLevelTest < ActionController::TestCase end end -class ForceSSLCustomDomainTest < ActionController::TestCase - tests ForceSSLCustomDomain +class ForceSSLCustomOptionsTest < ActionController::TestCase + tests ForceSSLCustomOptions - def test_banana_redirects_to_https_with_custom_host - get :banana + def setup + @request.env['HTTP_HOST'] = 'www.example.com:80' + end + + def test_redirect_to_custom_host + get :redirect_host assert_response 301 - assert_equal "https://secure.test.host/force_ssl_custom_domain/banana", redirect_to_url + assert_equal "https://secure.example.com/force_ssl_custom_options/redirect_host", redirect_to_url end - def test_cheeseburger_redirects_to_https_with_custom_host - get :cheeseburger + def test_redirect_to_custom_port + get :redirect_port + assert_response 301 + assert_equal "https://www.example.com:8443/force_ssl_custom_options/redirect_port", redirect_to_url + end + + def test_redirect_to_custom_subdomain + get :redirect_subdomain assert_response 301 - assert_equal "https://secure.test.host/force_ssl_custom_domain/cheeseburger", redirect_to_url + assert_equal "https://secure.example.com/force_ssl_custom_options/redirect_subdomain", redirect_to_url + end + + def test_redirect_to_custom_domain + get :redirect_domain + assert_response 301 + assert_equal "https://www.secure.com/force_ssl_custom_options/redirect_domain", redirect_to_url + end + + def test_redirect_to_custom_path + get :redirect_path + assert_response 301 + assert_equal "https://www.example.com/foo", redirect_to_url + end + + def test_redirect_to_custom_status + get :redirect_status + assert_response 302 + assert_equal "https://www.example.com/force_ssl_custom_options/redirect_status", redirect_to_url + end + + def test_redirect_to_custom_flash + get :redirect_flash + assert_response 301 + assert_equal "https://www.example.com/force_ssl_custom_options/redirect_flash", redirect_to_url + + get :use_flash + assert_response 200 + assert_equal "Foo, Bar!", @response.body + end + + def test_redirect_to_custom_alert + get :redirect_alert + assert_response 301 + assert_equal "https://www.example.com/force_ssl_custom_options/redirect_alert", redirect_to_url + + get :use_alert + assert_response 200 + assert_equal "Foo, Bar!", @response.body + end + + def test_redirect_to_custom_notice + get :redirect_notice + assert_response 301 + assert_equal "https://www.example.com/force_ssl_custom_options/redirect_notice", redirect_to_url + + get :use_notice + assert_response 200 + assert_equal "Foo, Bar!", @response.body end end @@ -149,16 +241,79 @@ class ForceSSLFlashTest < ActionController::TestCase assert_response 302 assert_equal "http://test.host/force_ssl_flash/cheeseburger", redirect_to_url + # FIXME: AC::TestCase#build_request_uri doesn't build a new uri if PATH_INFO exists + @request.env.delete('PATH_INFO') + get :cheeseburger assert_response 301 assert_equal "https://test.host/force_ssl_flash/cheeseburger", redirect_to_url + # FIXME: AC::TestCase#build_request_uri doesn't build a new uri if PATH_INFO exists + @request.env.delete('PATH_INFO') + get :use_flash assert_equal "hello", assigns["flash_copy"]["that"] assert_equal "hello", assigns["flashy"] end end +class ForceSSLDuplicateRoutesTest < ActionController::TestCase + tests ForceSSLControllerLevel + + def test_force_ssl_redirects_to_same_path + with_routing do |set| + set.draw do + get '/foo', :to => 'force_ssl_controller_level#banana' + get '/bar', :to => 'force_ssl_controller_level#banana' + end + + @request.env['PATH_INFO'] = '/bar' + + get :banana + assert_response 301 + assert_equal 'https://test.host/bar', redirect_to_url + end + end +end + +class ForceSSLFormatTest < ActionController::TestCase + tests ForceSSLControllerLevel + + def test_force_ssl_redirects_to_same_format + with_routing do |set| + set.draw do + get '/foo', :to => 'force_ssl_controller_level#banana' + end + + get :banana, :format => :json + assert_response 301 + assert_equal 'https://test.host/foo.json', redirect_to_url + end + end +end + +class ForceSSLOptionalSegmentsTest < ActionController::TestCase + tests ForceSSLControllerLevel + + def test_force_ssl_redirects_to_same_format + with_routing do |set| + set.draw do + scope '(:locale)' do + defaults :locale => 'en' do + get '/foo', :to => 'force_ssl_controller_level#banana' + end + end + end + + @request.env['PATH_INFO'] = '/en/foo' + get :banana, :locale => 'en' + assert_equal 'en', @controller.params[:locale] + assert_response 301 + assert_equal 'https://test.host/en/foo', redirect_to_url + end + end +end + class RedirectToSSLTest < ActionController::TestCase tests RedirectToSSL def test_banana_redirects_to_https_if_not_https diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb index ba24e7fac5..088ad73f2f 100644 --- a/actionpack/test/controller/url_for_test.rb +++ b/actionpack/test/controller/url_for_test.rb @@ -89,6 +89,13 @@ module AbstractController ) end + def test_subdomain_may_be_removed_with_blank_string + W.default_url_options[:host] = 'api.basecamphq.com' + assert_equal('http://basecamphq.com/c/a/i', + W.new.url_for(:subdomain => '', :controller => 'c', :action => 'a', :id => 'i') + ) + end + def test_multiple_subdomains_may_be_removed W.default_url_options[:host] = 'mobile.www.api.basecamphq.com' assert_equal('http://basecamphq.com/c/a/i', diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb index 6035f0361e..ff0baccd76 100644 --- a/actionpack/test/dispatch/debug_exceptions_test.rb +++ b/actionpack/test/dispatch/debug_exceptions_test.rb @@ -29,6 +29,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest raise RuntimeError when "/method_not_allowed" raise ActionController::MethodNotAllowed + when "/unknown_http_method" + raise ActionController::UnknownHttpMethod when "/not_implemented" raise ActionController::NotImplemented when "/unprocessable_entity" @@ -113,6 +115,10 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest assert_response 405 assert_match(/ActionController::MethodNotAllowed/, body) + get "/unknown_http_method", {}, {'action_dispatch.show_exceptions' => true} + assert_response 405 + assert_match(/ActionController::UnknownHttpMethod/, body) + get "/bad_request", {}, {'action_dispatch.show_exceptions' => true} assert_response 400 assert_match(/ActionController::BadRequest/, body) diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 29703dd5b1..5b42ca0f21 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -1124,6 +1124,35 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal "Not Found", @response.body end + def test_resources_with_format_false_from_scope + draw do + scope format: false do + resources :posts + resource :user + end + end + + get "/posts" + assert_response :success + assert_equal "posts#index", @response.body + assert_equal "/posts", posts_path + + get "/posts.html" + assert_response :not_found + assert_equal "Not Found", @response.body + assert_equal "/posts?format=html", posts_path(format: "html") + + get "/user" + assert_response :success + assert_equal "users#show", @response.body + assert_equal "/user", user_path + + get "/user.html" + assert_response :not_found + assert_equal "Not Found", @response.body + assert_equal "/user?format=html", user_path(format: "html") + end + def test_index draw do get '/info' => 'projects#info', :as => 'info' @@ -3322,6 +3351,10 @@ class TestUrlConstraints < ActionDispatch::IntegrationTest end get '/' => ok, :as => :alternate_root, :constraints => { :port => 8080 } + + get '/search' => ok, :constraints => { :subdomain => false } + + get '/logs' => ok, :constraints => { :subdomain => true } end end @@ -3348,6 +3381,24 @@ class TestUrlConstraints < ActionDispatch::IntegrationTest get 'http://www.example.com:8080/' assert_response :success end + + test "false constraint expressions check for absence of values" do + get 'http://example.com/search' + assert_response :success + assert_equal 'http://example.com/search', search_url + + get 'http://api.example.com/search' + assert_response :not_found + end + + test "true constraint expressions check for presence of values" do + get 'http://api.example.com/logs' + assert_response :success + assert_equal 'http://api.example.com/logs', logs_url + + get 'http://example.com/logs' + assert_response :not_found + end end class TestInvalidUrls < ActionDispatch::IntegrationTest diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 45f8fc11b3..38bd234f37 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -8,8 +8,12 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest case req.path when "/not_found" raise AbstractController::ActionNotFound + when "/bad_params" + raise ActionDispatch::ParamsParser::ParseError.new("", StandardError.new) when "/method_not_allowed" raise ActionController::MethodNotAllowed + when "/unknown_http_method" + raise ActionController::UnknownHttpMethod when "/not_found_original_exception" raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new) else @@ -33,6 +37,10 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest get "/", {}, {'action_dispatch.show_exceptions' => true} assert_response 500 assert_equal "500 error fixture\n", body + + get "/bad_params", {}, {'action_dispatch.show_exceptions' => true} + assert_response 400 + assert_equal "400 error fixture\n", body get "/not_found", {}, {'action_dispatch.show_exceptions' => true} assert_response 404 @@ -41,6 +49,10 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest get "/method_not_allowed", {}, {'action_dispatch.show_exceptions' => true} assert_response 405 assert_equal "", body + + get "/unknown_http_method", {}, {'action_dispatch.show_exceptions' => true} + assert_response 405 + assert_equal "", body end test "localize rescue error page" do diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb index 4123529092..f919592d24 100644 --- a/actionpack/test/dispatch/url_generation_test.rb +++ b/actionpack/test/dispatch/url_generation_test.rb @@ -56,6 +56,47 @@ module TestUrlGeneration test "formatting host when protocol is present" do assert_equal "http://www.example.com/foo", foo_url(host: "httpz://www.example.com", protocol: "http://") end + + test "default ports are removed from the host" do + assert_equal "http://www.example.com/foo", foo_url(host: "www.example.com:80", protocol: "http://") + assert_equal "https://www.example.com/foo", foo_url(host: "www.example.com:443", protocol: "https://") + end + + test "port is extracted from the host" do + assert_equal "http://www.example.com:8080/foo", foo_url(host: "www.example.com:8080", protocol: "http://") + end + + test "port option overides the host" do + assert_equal "http://www.example.com:8080/foo", foo_url(host: "www.example.com:8443", protocol: "http://", port: 8080) + end + + test "port option disables the host when set to nil" do + assert_equal "http://www.example.com/foo", foo_url(host: "www.example.com:8443", protocol: "http://", port: nil) + end + + test "port option disables the host when set to false" do + assert_equal "http://www.example.com/foo", foo_url(host: "www.example.com:8443", protocol: "http://", port: false) + end + + test "keep subdomain when key is true" do + assert_equal "http://www.example.com/foo", foo_url(subdomain: true) + end + + test "keep subdomain when key is missing" do + assert_equal "http://www.example.com/foo", foo_url + end + + test "omit subdomain when key is nil" do + assert_equal "http://example.com/foo", foo_url(subdomain: nil) + end + + test "omit subdomain when key is false" do + assert_equal "http://example.com/foo", foo_url(subdomain: false) + end + + test "omit subdomain when key is blank" do + assert_equal "http://example.com/foo", foo_url(subdomain: "") + end end end diff --git a/actionpack/test/fixtures/public/400.html b/actionpack/test/fixtures/public/400.html new file mode 100644 index 0000000000..03be6bedaf --- /dev/null +++ b/actionpack/test/fixtures/public/400.html @@ -0,0 +1 @@ +400 error fixture diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb index 94ae8549f7..1715902927 100644 --- a/actionpack/test/template/form_options_helper_test.rb +++ b/actionpack/test/template/form_options_helper_test.rb @@ -100,6 +100,13 @@ class FormOptionsHelperTest < ActionView::TestCase ) end + def test_collection_options_with_element_attributes + assert_dom_equal( + "<option value=\"USA\" class=\"bold\">USA</option>", + options_from_collection_for_select([[ "USA", "USA", { :class => 'bold' } ]], :first, :second) + ) + end + def test_string_options_for_select options = "<option value=\"Denmark\">Denmark</option><option value=\"USA\">USA</option><option value=\"Sweden\">Sweden</option>" assert_dom_equal( diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 2237d747be..81f3391fcd 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -29,14 +29,6 @@ module RenderTestCases assert_equal "Hello world!", @view.render(:file => "test/hello_world") end - def test_render_file_not_using_full_path - assert_equal "Hello world!", @view.render(:file => "test/hello_world") - end - - def test_render_file_without_specific_extension - assert_equal "Hello world!", @view.render(:file => "test/hello_world") - end - # Test if :formats, :locale etc. options are passed correctly to the resolvers. def test_render_file_with_format assert_match "<h1>No Comment</h1>", @view.render(:file => "comments/empty", :formats => [:html]) |