diff options
Diffstat (limited to 'actionpack')
42 files changed, 317 insertions, 1153 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 84481d0194..708683747b 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,4 +1,21 @@ -*Rails 3.0.0 [Edge] (pending)* +*Rails 3.0.0 [beta 3] (pending)* + +* Removed verify method in controllers. [JV] + It's now available as a plugin at http://github.com/rails/verification + +* Removed input, form, error_messages_for and error_message_on from views. [JV] + It's now available as a plugin at http://github.com/rails/dynamic_form + +* Routes can be scoped by controller module. [Jeremy Kemper] + + # /session => Auth::SessionsController + scope :module => 'auth' do + resource :session + end + +* Added #favicon_link_tag, it uses #image_path so in particular the favicon gets an asset ID [fxn] + +* Fixed that default locale templates should be used if the current locale template is missing [DHH] * Added all the new HTML5 form types as individual form tag methods (search, url, number, etc) #3646 [Stephen Celis] diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 536154fc6b..c14393dda7 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -33,7 +33,6 @@ module ActionController autoload :Streaming autoload :Testing autoload :UrlFor - autoload :Verification end autoload :Dispatcher, 'action_controller/deprecated/dispatcher' diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 1dfc240029..2e94a20d9d 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -30,7 +30,6 @@ module ActionController Cookies, Flash, - Verification, RequestForgeryProtection, Streaming, RecordIdentifier, diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb index fe95f0e0d7..2a0a1107eb 100644 --- a/actionpack/lib/action_controller/caching/pages.rb +++ b/actionpack/lib/action_controller/caching/pages.rb @@ -38,22 +38,22 @@ module ActionController #:nodoc: extend ActiveSupport::Concern included do - @@page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : "" ## # :singleton-method: # The cache directory should be the document root for the web server and is set using <tt>Base.page_cache_directory = "/document/root"</tt>. # For Rails, this directory has already been set to Rails.public_path (which is usually set to <tt>RAILS_ROOT + "/public"</tt>). Changing # this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your # web server to look in the new location for cached files. + @@page_cache_directory = '' cattr_accessor :page_cache_directory - @@page_cache_extension = '.html' ## # :singleton-method: # Most Rails requests do not have an extension, such as <tt>/weblog/new</tt>. In these cases, the page caching mechanism will add one in # order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is <tt>.html</tt>. # If you want something else, like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension. In cases where a request already has an # extension, such as <tt>.xml</tt> or <tt>.rss</tt>, page caching will not add an extension. This allows it to work well with RESTful apps. + @@page_cache_extension = '.html' cattr_accessor :page_cache_extension end diff --git a/actionpack/lib/action_controller/deprecated/base.rb b/actionpack/lib/action_controller/deprecated/base.rb index 05551ffee4..5d9cfb153a 100644 --- a/actionpack/lib/action_controller/deprecated/base.rb +++ b/actionpack/lib/action_controller/deprecated/base.rb @@ -6,15 +6,6 @@ module ActionController deprecated_config_writer(option, message) end - # This method has been moved to ActionDispatch::Request.filter_parameters - def filter_parameter_logging(*args, &block) - ActiveSupport::Deprecation.warn("Setting filter_parameter_logging in ActionController is deprecated and has no longer effect, please set 'config.filter_parameters' in config/application.rb instead", caller) - filter = Rails.application.config.filter_parameters - filter.concat(args) - filter << block if block - filter - end - def deprecated_config_reader(option, message = nil) message ||= "Reading #{option} directly from ActionController::Base is deprecated. " \ "Please read it from config.#{option}" @@ -136,6 +127,25 @@ module ActionController end end + module DeprecatedBehavior + # This method has been moved to ActionDispatch::Request.filter_parameters + def filter_parameter_logging(*args, &block) + ActiveSupport::Deprecation.warn("Setting filter_parameter_logging in ActionController is deprecated and has no longer effect, please set 'config.filter_parameters' in config/application.rb instead", caller) + filter = Rails.application.config.filter_parameters + filter.concat(args) + filter << block if block + filter + end + + # This was moved to a plugin + def verify(*args) + ActiveSupport::Deprecation.warn "verify was removed from Rails and is now available as a plugin. " << + "Please install it with `rails plugin install git://github.com/rails/verification.git`.", caller + end + end + + extend DeprecatedBehavior + deprecated_config_writer :session_store deprecated_config_writer :session_options deprecated_config_accessor :relative_url_root, "relative_url_root is ineffective. Please stop using it" diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb index e6cea483bb..02722360f1 100644 --- a/actionpack/lib/action_controller/metal/compatibility.rb +++ b/actionpack/lib/action_controller/metal/compatibility.rb @@ -32,8 +32,6 @@ module ActionController def rescue_action(env) raise env["action_dispatch.rescue.exception"] end - - self.page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : "" end # For old tests diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index d97c10a293..6ad9a23542 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -135,7 +135,6 @@ module ActionController #:nodoc: def to_format default_render rescue ActionView::MissingTemplate => e - raise unless resourceful? api_behavior(e) end @@ -154,6 +153,8 @@ module ActionController #:nodoc: # This is the common behavior for "API" requests, like :xml and :json. def api_behavior(error) + raise error unless resourceful? + if get? display resource elsif has_errors? diff --git a/actionpack/lib/action_controller/metal/verification.rb b/actionpack/lib/action_controller/metal/verification.rb deleted file mode 100644 index b7fc2b7421..0000000000 --- a/actionpack/lib/action_controller/metal/verification.rb +++ /dev/null @@ -1,130 +0,0 @@ -module ActionController #:nodoc: - module Verification #:nodoc: - extend ActiveSupport::Concern - - include AbstractController::Callbacks, Flash, Rendering - - # This module provides a class-level method for specifying that certain - # actions are guarded against being called without certain prerequisites - # being met. This is essentially a special kind of before_filter. - # - # An action may be guarded against being invoked without certain request - # parameters being set, or without certain session values existing. - # - # When a verification is violated, values may be inserted into the flash, and - # a specified redirection is triggered. If no specific action is configured, - # verification failures will by default result in a 400 Bad Request response. - # - # Usage: - # - # class GlobalController < ActionController::Base - # # Prevent the #update_settings action from being invoked unless - # # the 'admin_privileges' request parameter exists. The - # # settings action will be redirected to in current controller - # # if verification fails. - # verify :params => "admin_privileges", :only => :update_post, - # :redirect_to => { :action => "settings" } - # - # # Disallow a post from being updated if there was no information - # # submitted with the post, and if there is no active post in the - # # session, and if there is no "note" key in the flash. The route - # # named category_url will be redirected to if verification fails. - # - # verify :params => "post", :session => "post", "flash" => "note", - # :only => :update_post, - # :add_flash => { "alert" => "Failed to create your message" }, - # :redirect_to => :category_url - # - # Note that these prerequisites are not business rules. They do not examine - # the content of the session or the parameters. That level of validation should - # be encapsulated by your domain model or helper methods in the controller. - module ClassMethods - # Verify the given actions so that if certain prerequisites are not met, - # the user is redirected to a different action. The +options+ parameter - # is a hash consisting of the following key/value pairs: - # - # <tt>:params</tt>:: - # a single key or an array of keys that must be in the <tt>params</tt> - # hash in order for the action(s) to be safely called. - # <tt>:session</tt>:: - # a single key or an array of keys that must be in the <tt>session</tt> - # in order for the action(s) to be safely called. - # <tt>:flash</tt>:: - # a single key or an array of keys that must be in the flash in order - # for the action(s) to be safely called. - # <tt>:method</tt>:: - # a single key or an array of keys--any one of which must match the - # current request method in order for the action(s) to be safely called. - # (The key should be a symbol: <tt>:get</tt> or <tt>:post</tt>, for - # example.) - # <tt>:xhr</tt>:: - # true/false option to ensure that the request is coming from an Ajax - # call or not. - # <tt>:add_flash</tt>:: - # a hash of name/value pairs that should be merged into the session's - # flash if the prerequisites cannot be satisfied. - # <tt>:add_headers</tt>:: - # a hash of name/value pairs that should be merged into the response's - # headers hash if the prerequisites cannot be satisfied. - # <tt>:redirect_to</tt>:: - # the redirection parameters to be used when redirecting if the - # prerequisites cannot be satisfied. You can redirect either to named - # route or to the action in some controller. - # <tt>:render</tt>:: - # the render parameters to be used when the prerequisites cannot be satisfied. - # <tt>:only</tt>:: - # only apply this verification to the actions specified in the associated - # array (may also be a single value). - # <tt>:except</tt>:: - # do not apply this verification to the actions specified in the associated - # array (may also be a single value). - def verify(options={}) - before_filter :only => options[:only], :except => options[:except] do - verify_action options - end - end - end - - private - - def verify_action(options) #:nodoc: - if prereqs_invalid?(options) - flash.update(options[:add_flash]) if options[:add_flash] - response.headers.merge!(options[:add_headers]) if options[:add_headers] - apply_remaining_actions(options) unless performed? - end - end - - def prereqs_invalid?(options) # :nodoc: - verify_presence_of_keys_in_hash_flash_or_params(options) || - verify_method(options) || - verify_request_xhr_status(options) - end - - def verify_presence_of_keys_in_hash_flash_or_params(options) # :nodoc: - [*options[:params] ].find { |v| v && params[v.to_sym].nil? } || - [*options[:session]].find { |v| session[v].nil? } || - [*options[:flash] ].find { |v| flash[v].nil? } - end - - def verify_method(options) # :nodoc: - [*options[:method]].all? { |v| request.method_symbol != v.to_sym } if options[:method] - end - - def verify_request_xhr_status(options) # :nodoc: - request.xhr? != options[:xhr] unless options[:xhr].nil? - end - - def apply_redirect_to(redirect_to_option) # :nodoc: - (redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.__send__(redirect_to_option) : redirect_to_option - end - - def apply_remaining_actions(options) # :nodoc: - case - when options[:render] ; render(options[:render]) - when options[:redirect_to] ; redirect_to(apply_redirect_to(options[:redirect_to])) - else head(:bad_request) - end - end - end -end diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb index ae363e300c..7f2eb4306b 100644 --- a/actionpack/lib/action_controller/polymorphic_routes.rb +++ b/actionpack/lib/action_controller/polymorphic_routes.rb @@ -120,7 +120,7 @@ module ActionController end %w(edit new).each do |action| - module_eval <<-EOT, __FILE__, __LINE__ + module_eval <<-EOT, __FILE__, __LINE__ + 1 def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {}) polymorphic_url( # polymorphic_url( record_or_hash, # record_or_hash, diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 030ba4ec48..b029434004 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -44,6 +44,12 @@ module ActionController ActiveSupport.on_load(:action_controller) { self.logger ||= Rails.logger } end + initializer "action_controller.page_cache_directory" do + ActiveSupport.on_load(:action_controller) do + self.page_cache_directory = Rails.public_path + end + end + initializer "action_controller.set_configs" do |app| paths = app.config.paths ac = app.config.action_controller diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 2d4cf2fafb..dfd8e75bcc 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -284,6 +284,8 @@ module ActionController include ActionDispatch::TestProcess include ActionController::TemplateAssertions + attr_reader :response, :request + # Executes a request simulating GET HTTP method and set/volley the response def get(action, parameters = nil, session = nil, flash = nil) process(action, parameters, session, flash, "GET") diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index 18a3688bb0..1524b00d5b 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -36,17 +36,16 @@ module ActionDispatch when Proc strategy.call(request.raw_post) when :xml_simple, :xml_node - request.body.size == 0 ? {} : Hash.from_xml(request.raw_post).with_indifferent_access + data = Hash.from_xml(request.body) || {} + request.body.rewind if request.body.respond_to?(:rewind) + data.with_indifferent_access when :yaml YAML.load(request.raw_post) when :json - if request.body.size == 0 - {} - else - data = ActiveSupport::JSON.decode(request.raw_post) - data = {:_json => data} unless data.is_a?(Hash) - data.with_indifferent_access - end + data = ActiveSupport::JSON.decode(request.body) + request.body.rewind if request.body.respond_to?(:rewind) + data = {:_json => data} unless data.is_a?(Hash) + data.with_indifferent_access else false end @@ -76,4 +75,4 @@ module ActionDispatch defined?(Rails.logger) ? Rails.logger : Logger.new($stderr) end end -end
\ No newline at end of file +end 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 index 839df50999..09ff052fd0 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb @@ -6,7 +6,7 @@ <% end %> <% - clean_params = @request.parameters.clone + clean_params = @request.filtered_parameters.clone clean_params.delete("action") clean_params.delete("controller") diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 925e91f081..7035e360ec 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -324,7 +324,8 @@ module ActionDispatch end def namespace(path) - scope(path.to_s, :name_prefix => path.to_s, :controller_namespace => path.to_s) { yield } + path = path.to_s + scope(:path => path, :name_prefix => path, :module => path) { yield } end def constraints(constraints = {}) @@ -363,15 +364,15 @@ module ActionDispatch parent ? "#{parent}_#{child}" : child end - def merge_controller_namespace_scope(parent, child) + def merge_module_scope(parent, child) parent ? "#{parent}/#{child}" : child end def merge_controller_scope(parent, child) - @scope[:controller_namespace] ? "#{@scope[:controller_namespace]}/#{child}" : child + @scope[:module] ? "#{@scope[:module]}/#{child}" : child end - def merge_resources_path_names_scope(parent, child) + def merge_path_names_scope(parent, child) merge_options_scope(parent, child) end @@ -520,7 +521,7 @@ module ActionDispatch def initialize(*args) #:nodoc: super - @scope[:resources_path_names] = @set.resources_path_names + @scope[:path_names] = @set.resources_path_names end def resource(*resources, &block) @@ -636,7 +637,7 @@ module ActionDispatch return self end - resources_path_names = options.delete(:path_names) + path_names = options.delete(:path_names) if args.first.is_a?(Symbol) action = args.first @@ -653,7 +654,7 @@ module ActionDispatch end else with_exclusive_name_prefix(action) do - return match("#{action_path(action, resources_path_names)}(.:format)", options.reverse_merge(:to => action)) + return match("#{action_path(action, path_names)}(.:format)", options.reverse_merge(:to => action)) end end end @@ -681,7 +682,7 @@ module ActionDispatch private def action_path(name, path_names = nil) - path_names ||= @scope[:resources_path_names] + path_names ||= @scope[:path_names] path_names[name.to_sym] || name.to_s end @@ -692,7 +693,7 @@ module ActionDispatch end if path_names = options.delete(:path_names) - scope(:resources_path_names => path_names) do + scope(:path_names => path_names) do send(method, resources.pop, options, &block) end return true diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb index 0b40465a79..8f0c5d939f 100644 --- a/actionpack/lib/action_pack/version.rb +++ b/actionpack/lib/action_pack/version.rb @@ -3,7 +3,7 @@ module ActionPack MAJOR = 3 MINOR = 0 TINY = 0 - BUILD = "beta2" + BUILD = "beta3" STRING = [MAJOR, MINOR, TINY, BUILD].join('.') end diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb index 44e193f18e..a7650c0050 100644 --- a/actionpack/lib/action_view/helpers/active_model_helper.rb +++ b/actionpack/lib/action_view/helpers/active_model_helper.rb @@ -1,8 +1,6 @@ -require 'cgi' require 'action_view/helpers/form_helper' require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/enumerable' -require 'active_support/core_ext/kernel/reporting' require 'active_support/core_ext/object/blank' module ActionView @@ -14,252 +12,29 @@ module ActionView end module Helpers - # The Active Record Helper makes it easier to create forms for records kept in instance variables. The most far-reaching is the +form+ - # method that creates a complete form for all the basic content types of the record (not associations or aggregations, though). This - # is a great way of making the record quickly available for editing, but likely to prove lackluster for a complicated real-world form. - # In that case, it's better to use the +input+ method and the specialized +form+ methods in link:classes/ActionView/Helpers/FormHelper.html module ActiveModelHelper - # Returns a default input tag for the type of object returned by the method. For example, if <tt>@post</tt> - # has an attribute +title+ mapped to a +VARCHAR+ column that holds "Hello World": - # - # input("post", "title") - # # => <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /> - def input(record_name, method, options = {}) - InstanceTag.new(record_name, method, self).to_tag(options) - end - - # Returns an entire form with all needed input tags for a specified Active Record object. For example, if <tt>@post</tt> - # has attributes named +title+ of type +VARCHAR+ and +body+ of type +TEXT+ then - # - # form("post") - # - # would yield a form like the following (modulus formatting): - # - # <form action='/posts/create' method='post'> - # <p> - # <label for="post_title">Title</label><br /> - # <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /> - # </p> - # <p> - # <label for="post_body">Body</label><br /> - # <textarea cols="40" id="post_body" name="post[body]" rows="20"></textarea> - # </p> - # <input name="commit" type="submit" value="Create" /> - # </form> - # - # It's possible to specialize the form builder by using a different action name and by supplying another - # block renderer. For example, if <tt>@entry</tt> has an attribute +message+ of type +VARCHAR+ then - # - # form("entry", - # :action => "sign", - # :input_block => Proc.new { |record, column| - # "#{column.human_name}: #{input(record, column.name)}<br />" - # }) - # - # would yield a form like the following (modulus formatting): - # - # <form action="/entries/sign" method="post"> - # Message: - # <input id="entry_message" name="entry[message]" size="30" type="text" /><br /> - # <input name="commit" type="submit" value="Sign" /> - # </form> - # - # It's also possible to add additional content to the form by giving it a block, such as: - # - # form("entry", :action => "sign") do |form| - # form << content_tag("b", "Department") - # form << collection_select("department", "id", @departments, "id", "name") - # end - # - # The following options are available: - # - # * <tt>:action</tt> - The action used when submitting the form (default: +create+ if a new record, otherwise +update+). - # * <tt>:input_block</tt> - Specialize the output using a different block, see above. - # * <tt>:method</tt> - The method used when submitting the form (default: +post+). - # * <tt>:multipart</tt> - Whether to change the enctype of the form to "multipart/form-data", used when uploading a file (default: +false+). - # * <tt>:submit_value</tt> - The text of the submit button (default: "Create" if a new record, otherwise "Update"). - def form(record_name, options = {}) - record = instance_variable_get("@#{record_name}") - record = convert_to_model(record) - - options = options.symbolize_keys - options[:action] ||= record.persisted? ? "update" : "create" - action = url_for(:action => options[:action], :id => record) - - submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize - - contents = form_tag({:action => action}, :method =>(options[:method] || 'post'), :enctype => options[:multipart] ? 'multipart/form-data': nil) - contents.safe_concat hidden_field(record_name, :id) if record.persisted? - contents.safe_concat all_input_tags(record, record_name, options) - yield contents if block_given? - contents.safe_concat submit_tag(submit_value) - contents.safe_concat('</form>') - end - - # Returns a string containing the error message attached to the +method+ on the +object+ if one exists. - # This error message is wrapped in a <tt>DIV</tt> tag by default or with <tt>:html_tag</tt> if specified, - # which can be extended to include a <tt>:prepend_text</tt> and/or <tt>:append_text</tt> (to properly explain - # the error), and a <tt>:css_class</tt> to style it accordingly. +object+ should either be the name of an - # instance variable or the actual object. The method can be passed in either as a string or a symbol. - # As an example, let's say you have a model <tt>@post</tt> that has an error message on the +title+ attribute: - # - # <%= error_message_on "post", "title" %> - # # => <div class="formError">can't be empty</div> - # - # <%= error_message_on @post, :title %> - # # => <div class="formError">can't be empty</div> - # - # <%= error_message_on "post", "title", - # :prepend_text => "Title simply ", - # :append_text => " (or it won't work).", - # :html_tag => "span", - # :css_class => "inputError" %> - # # => <span class="inputError">Title simply can't be empty (or it won't work).</span> - def error_message_on(object, method, *args) - options = args.extract_options! - unless args.empty? - ActiveSupport::Deprecation.warn('error_message_on takes an option hash instead of separate ' + - 'prepend_text, append_text, html_tag, and css_class arguments', caller) - - options[:prepend_text] = args[0] || '' - options[:append_text] = args[1] || '' - options[:html_tag] = args[2] || 'div' - options[:css_class] = args[3] || 'formError' - end - options.reverse_merge!(:prepend_text => '', :append_text => '', :html_tag => 'div', :css_class => 'formError') - - object = convert_to_model(object) - - if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) && - (errors = obj.errors[method]).presence - content_tag(options[:html_tag], - (options[:prepend_text].html_safe << errors.first).safe_concat(options[:append_text]), - :class => options[:css_class] - ) - else - '' - end - end - - # Returns a string with a <tt>DIV</tt> containing all of the error messages for the objects located as instance variables by the names - # given. If more than one object is specified, the errors for the objects are displayed in the order that the object names are - # provided. - # - # This <tt>DIV</tt> can be tailored by the following options: - # - # * <tt>:header_tag</tt> - Used for the header of the error div (default: "h2"). - # * <tt>:id</tt> - The id of the error div (default: "errorExplanation"). - # * <tt>:class</tt> - The class of the error div (default: "errorExplanation"). - # * <tt>:object</tt> - The object (or array of objects) for which to display errors, - # if you need to escape the instance variable convention. - # * <tt>:object_name</tt> - The object name to use in the header, or any text that you prefer. - # If <tt>:object_name</tt> is not set, the name of the first object will be used. - # * <tt>:header_message</tt> - The message in the header of the error div. Pass +nil+ - # or an empty string to avoid the header message altogether. (Default: "X errors - # prohibited this object from being saved"). - # * <tt>:message</tt> - The explanation message after the header message and before - # the error list. Pass +nil+ or an empty string to avoid the explanation message - # altogether. (Default: "There were problems with the following fields:"). - # - # To specify the display for one object, you simply provide its name as a parameter. - # For example, for the <tt>@user</tt> model: - # - # error_messages_for 'user' - # - # You can also supply an object: - # - # error_messages_for @user - # - # This will use the last part of the model name in the presentation. For instance, if - # this is a MyKlass::User object, this will use "user" as the name in the String. This - # is taken from MyKlass::User.model_name.human, which can be overridden. - # - # To specify more than one object, you simply list them; optionally, you can add an extra <tt>:object_name</tt> parameter, which - # will be the name used in the header message: - # - # error_messages_for 'user_common', 'user', :object_name => 'user' - # - # You can also use a number of objects, which will have the same naming semantics - # as a single object. - # - # error_messages_for @user, @post - # - # If the objects cannot be located as instance variables, you can add an extra <tt>:object</tt> parameter which gives the actual - # object (or array of objects to use): - # - # error_messages_for 'user', :object => @question.user - # - # NOTE: This is a pre-packaged presentation of the errors with embedded strings and a certain HTML structure. If what - # you need is significantly different from the default presentation, it makes plenty of sense to access the <tt>object.errors</tt> - # instance yourself and set it up. View the source of this method to see how easy it is. - def error_messages_for(*params) - options = params.extract_options!.symbolize_keys - - objects = Array.wrap(options.delete(:object) || params).map do |object| - object = instance_variable_get("@#{object}") unless object.respond_to?(:to_model) - object = convert_to_model(object) - - if object.class.respond_to?(:model_name) - options[:object_name] ||= object.class.model_name.human.downcase + %w(input form error_messages_for error_message_on).each do |method| + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(*args) + ActiveSupport::Deprecation.warn "#{method} was removed from Rails and is now available as a plugin. " << + "Please install it with `rails plugin install git://github.com/rails/dynamic_form.git`.", caller end + RUBY + end + end - object - end - - objects.compact! - count = objects.inject(0) {|sum, object| sum + object.errors.count } - - unless count.zero? - html = {} - [:id, :class].each do |key| - if options.include?(key) - value = options[key] - html[key] = value unless value.blank? - else - html[key] = 'errorExplanation' - end - end - options[:object_name] ||= params.first - - I18n.with_options :locale => options[:locale], :scope => [:errors, :template] do |locale| - header_message = if options.include?(:header_message) - options[:header_message] - else - locale.t :header, :count => count, :model => options[:object_name].to_s.gsub('_', ' ') - end - - message = options.include?(:message) ? options[:message] : locale.t(:body) - - error_messages = objects.sum do |object| - object.errors.full_messages.map do |msg| - content_tag(:li, msg) - end - end.join.html_safe - - contents = '' - contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank? - contents << content_tag(:p, message) unless message.blank? - contents << content_tag(:ul, error_messages) - - content_tag(:div, contents.html_safe, html) + module ActiveModelFormBuilder + %w(error_messages error_message_on).each do |method| + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(*args) + ActiveSupport::Deprecation.warn "f.#{method} was removed from Rails and is now available as a plugin. " << + "Please install it with `rails plugin install git://github.com/rails/dynamic_form.git`.", caller end - else - '' - end + RUBY end - - private - def all_input_tags(record, record_name, options) - input_block = options[:input_block] || default_input_block - record.class.content_columns.collect{ |column| input_block.call(record_name, column) }.join("\n") - end - - def default_input_block - Proc.new { |record, column| %(<p><label for="#{record}_#{column.name}">#{column.human_name}</label><br />#{input(record, column.name)}</p>) } - end end - module ActiveRecordInstanceTag + module ActiveModelInstanceTag def object @active_model_object ||= begin object = super @@ -267,26 +42,6 @@ module ActionView end end - def to_tag(options = {}) - case column_type - when :string - field_type = @method_name.include?("password") ? "password" : "text" - to_input_field_tag(field_type, options) - when :text - to_text_area_tag(options) - when :integer, :float, :decimal - to_input_field_tag("text", options) - when :date - to_date_select_tag(options) - when :datetime, :timestamp - to_datetime_select_tag(options) - when :time - to_time_select_tag(options) - when :boolean - to_boolean_select_tag(options) - end - end - %w(tag content_tag to_date_select_tag to_datetime_select_tag to_time_select_tag).each do |meth| module_eval "def #{meth}(*) error_wrapping(super) end" end @@ -302,14 +57,14 @@ module ActionView def error_message object.errors[@method_name] end + end - def column_type - object.send(:column_for_attribute, @method_name).type - end + class FormBuilder + include ActiveModelFormBuilder end class InstanceTag - include ActiveRecordInstanceTag + include ActiveModelInstanceTag end end end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index e4ec17467e..563d9ec319 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -501,16 +501,53 @@ module ActionView end end + # Web browsers cache favicons. If you just throw a <tt>favicon.ico</tt> into the document + # root of your application and it changes later, clients that have it in their cache + # won't see the update. Using this helper prevents that because it appends an asset ID: + # + # <%= favicon_link_tag %> + # + # generates + # + # <link href="/favicon.ico?4649789979" rel="shortcut icon" type="image/vnd.microsoft.icon" /> + # + # You may specify a different file in the first argument: + # + # <%= favicon_link_tag 'favicon.ico' %> + # + # That's passed to +path_to_image+ as is, so it gives + # + # <link href="/images/favicon.ico?4649789979" rel="shortcut icon" type="image/vnd.microsoft.icon" /> + # + # The helper accepts an additional options hash where you can override "rel" and "type". + # + # For example, Mobile Safari looks for a different LINK tag, pointing to an image that + # will be used if you add the page to the home screen of an iPod Touch, iPhone, or iPad. + # The following call would generate such a tag: + # + # <%= favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png' %> + # + def favicon_link_tag(source='/favicon.ico', options={}) + tag('link', { + :rel => 'shortcut icon', + :type => 'image/vnd.microsoft.icon', + :href => path_to_image(source) + }.merge(options.symbolize_keys)) + end + # Computes the path to an image asset in the public images directory. # Full paths from the document root will be passed through. - # Used internally by +image_tag+ to build the image path. + # Used internally by +image_tag+ to build the image path: # - # ==== Examples - # image_path("edit") # => /images/edit - # image_path("edit.png") # => /images/edit.png - # image_path("icons/edit.png") # => /images/icons/edit.png - # image_path("/icons/edit.png") # => /icons/edit.png - # image_path("http://www.railsapplication.com/img/edit.png") # => http://www.railsapplication.com/img/edit.png + # image_path("edit") # => "/images/edit" + # image_path("edit.png") # => "/images/edit.png" + # image_path("icons/edit.png") # => "/images/icons/edit.png" + # image_path("/icons/edit.png") # => "/icons/edit.png" + # image_path("http://www.railsapplication.com/img/edit.png") # => "http://www.railsapplication.com/img/edit.png" + # + # If you have images as application resources this method may conflict with their named routes. + # The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and + # plugin authors are encouraged to do so. def image_path(source) compute_public_path(source, 'images') end @@ -590,7 +627,7 @@ module ActionView end if mouseover = options.delete(:mouseover) - options[:onmouseover] = "this.src='#{image_path(mouseover)}'" + options[:onmouseover] = "this.src='#{path_to_image(mouseover)}'" options[:onmouseout] = "this.src='#{src}'" end diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index fc02d959d4..a3453cc47a 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -1105,7 +1105,7 @@ module ActionView end (field_helpers - %w(label check_box radio_button fields_for hidden_field)).each do |selector| - src, file, line = <<-end_src, __FILE__, __LINE__ + 1 + src, line = <<-end_src, __LINE__ + 1 def #{selector}(method, options = {}) # def text_field(method, options = {}) @template.send( # @template.send( #{selector.inspect}, # "text_field", @@ -1114,7 +1114,7 @@ module ActionView objectify_options(options)) # objectify_options(options)) end # end end_src - class_eval src, file, line + class_eval src, __FILE__, line end def fields_for(record_or_name_or_array, *args, &block) @@ -1169,14 +1169,6 @@ module ActionView @template.hidden_field(@object_name, method, objectify_options(options)) end - def error_message_on(method, *args) - @template.error_message_on(@object, method, *args) - end - - def error_messages(options = {}) - @template.error_messages_for(@object_name, objectify_options(options)) - end - # Add the submit button for the given form. When no value is given, it checks # if the object is a new resource or not to create the proper label: # diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 11c6351bd3..105f4565e6 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -217,8 +217,6 @@ module ActionView InstanceTag.new(object, method, self, options.delete(:object)).to_grouped_collection_select_tag(collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options) end - - # Return select and option tags for the given object and method, using # #time_zone_options_for_select to generate the list of option tags. # diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 081c317e0c..b840f77fb5 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -199,8 +199,8 @@ module ActionView # file_field_tag 'attachment' # # => <input id="attachment" name="attachment" type="file" /> # - # file_field_tag 'avatar', :class => 'profile-input' - # # => <input class="profile-input" id="avatar" name="avatar" type="file" /> + # file_field_tag 'avatar', :class => 'profile_input' + # # => <input class="profile_input" id="avatar" name="avatar" type="file" /> # # file_field_tag 'picture', :disabled => true # # => <input disabled="disabled" id="picture" name="picture" type="file" /> @@ -244,8 +244,8 @@ module ActionView # password_field_tag 'confirm_pass', nil, :disabled => true # # => <input disabled="disabled" id="confirm_pass" name="confirm_pass" type="password" /> # - # password_field_tag 'pin', '1234', :maxlength => 4, :size => 6, :class => "pin-input" - # # => <input class="pin-input" id="pin" maxlength="4" name="pin" size="6" type="password" value="1234" /> + # password_field_tag 'pin', '1234', :maxlength => 4, :size => 6, :class => "pin_input" + # # => <input class="pin_input" id="pin" maxlength="4" name="pin" size="6" type="password" value="1234" /> def password_field_tag(name = "password", value = nil, options = {}) text_field_tag(name, value, options.update("type" => "password")) end @@ -374,8 +374,8 @@ module ActionView # submit_tag nil, :class => "form_submit" # # => <input class="form_submit" name="commit" type="submit" /> # - # submit_tag "Edit", :disable_with => "Editing...", :class => "edit-button" - # # => <input class="edit-button" data-disable_with="Editing..." + # submit_tag "Edit", :disable_with => "Editing...", :class => "edit_button" + # # => <input class="edit_button" data-disable_with="Editing..." # # name="commit" type="submit" value="Edit" /> # # submit_tag "Save", :confirm => "Are you sure?" @@ -386,7 +386,7 @@ module ActionView options.stringify_keys! if disable_with = options.delete("disable_with") - options["data-disable-with"] = disable_with if disable_with + options["data-disable-with"] = disable_with end if confirm = options.delete("confirm") @@ -398,7 +398,7 @@ module ActionView # Displays an image which when clicked will submit the form. # - # <tt>source</tt> is passed to AssetTagHelper#image_path + # <tt>source</tt> is passed to AssetTagHelper#path_to_image # # ==== Options # * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm @@ -414,11 +414,11 @@ module ActionView # image_submit_tag("purchase.png", :disabled => true) # # => <input disabled="disabled" src="/images/purchase.png" type="image" /> # - # image_submit_tag("search.png", :class => 'search-button') - # # => <input class="search-button" src="/images/search.png" type="image" /> + # image_submit_tag("search.png", :class => 'search_button') + # # => <input class="search_button" src="/images/search.png" type="image" /> # - # image_submit_tag("agree.png", :disabled => true, :class => "agree-disagree-button") - # # => <input class="agree-disagree-button" disabled="disabled" src="/images/agree.png" type="image" /> + # image_submit_tag("agree.png", :disabled => true, :class => "agree_disagree_button") + # # => <input class="agree_disagree_button" disabled="disabled" src="/images/agree.png" type="image" /> def image_submit_tag(source, options = {}) options.stringify_keys! diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 5925faf810..0b748d700b 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -265,7 +265,7 @@ module ActionView # using the +link_to+ method with the <tt>:method</tt> modifier as described in # the +link_to+ documentation. # - # The generated form element has a class name of <tt>button-to</tt> + # The generated form element has a class name of <tt>button_to</tt> # to allow styling of the form itself and its children. You can control # the form submission and input element behavior using +html_options+. # This method accepts the <tt>:method</tt> and <tt>:confirm</tt> modifiers @@ -289,14 +289,14 @@ module ActionView # # ==== Examples # <%= button_to "New", :action => "new" %> - # # => "<form method="post" action="/controller/new" class="button-to"> + # # => "<form method="post" action="/controller/new" class="button_to"> # # <div><input value="New" type="submit" /></div> # # </form>" # # # <%= button_to "Delete Image", { :action => "delete", :id => @image.id }, # :confirm => "Are you sure?", :method => :delete %> - # # => "<form method="post" action="/images/delete/1" class="button-to"> + # # => "<form method="post" action="/images/delete/1" class="button_to"> # # <div> # # <input type="hidden" name="_method" value="delete" /> # # <input data-confirm='Are you sure?' value="Delete" type="submit" /> @@ -306,7 +306,7 @@ module ActionView # # <%= button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?', # :method => "delete", :remote => true, :disable_with => 'loading...') %> - # # => "<form class='button-to' method='post' action='http://www.example.com' data-remote='true'> + # # => "<form class='button_to' method='post' action='http://www.example.com' data-remote='true'> # # <div> # # <input name='_method' value='delete' type='hidden' /> # # <input value='Destroy' type='submit' disable_with='loading...' data-confirm='Are you sure?' /> @@ -338,7 +338,7 @@ module ActionView html_options.merge!("type" => "submit", "value" => name) - ("<form method=\"#{form_method}\" action=\"#{escape_once url}\" #{"data-remote=\"true\"" if remote} class=\"button-to\"><div>" + + ("<form method=\"#{form_method}\" action=\"#{escape_once url}\" #{"data-remote=\"true\"" if remote} class=\"button_to\"><div>" + method_tag + tag("input", html_options) + request_token_tag + "</div></form>").html_safe end diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml index a3e2230f6f..187e010e30 100644 --- a/actionpack/lib/action_view/locale/en.yml +++ b/actionpack/lib/action_view/locale/en.yml @@ -141,14 +141,6 @@ minute: "Minute" second: "Seconds" - errors: - template: - header: - one: "1 error prohibited this {{model}} from being saved" - other: "{{count}} errors prohibited this {{model}} from being saved" - # The variable :count is also available - body: "There were problems with the following fields:" - helpers: select: # Default value for :prompt => true in FormOptionsHelper diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb index 9b59aac0eb..6e61d85dcc 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionpack/lib/action_view/lookup_context.rb @@ -38,7 +38,7 @@ module ActionView end register_detail(:formats) { Mime::SET.symbols } - register_detail(:locale) { [I18n.locale] } + register_detail(:locale) { [I18n.locale, I18n.default_locale] } class DetailsKey #:nodoc: alias :eql? :equal? @@ -160,7 +160,7 @@ module ActionView config = I18n.config.respond_to?(:i18n_config) ? I18n.config.i18n_config : I18n.config config.locale = value end - super(I18n.locale) + super(_locale_defaults) end # Update the details keys by merging the given hash into the current diff --git a/actionpack/lib/action_view/render/layouts.rb b/actionpack/lib/action_view/render/layouts.rb index 7311730a19..31b09d9f0a 100644 --- a/actionpack/lib/action_view/render/layouts.rb +++ b/actionpack/lib/action_view/render/layouts.rb @@ -48,7 +48,7 @@ module ActionView # def _layout_for(name = nil, &block) #:nodoc: if !block || name - @_content_for[name || :layout] + @_content_for[name || :layout].html_safe else capture(&block) end diff --git a/actionpack/test/controller/localized_templates_test.rb b/actionpack/test/controller/localized_templates_test.rb new file mode 100644 index 0000000000..41ff2f3809 --- /dev/null +++ b/actionpack/test/controller/localized_templates_test.rb @@ -0,0 +1,22 @@ +require 'abstract_unit' + +class LocalizedController < ActionController::Base + def hello_world + end +end + +class LocalizedTemplatesTest < ActionController::TestCase + tests LocalizedController + + def test_localized_template_is_used + I18n.locale = :de + get :hello_world + assert_equal "Gutten Tag", @response.body + end + + def test_default_locale_template_is_used_when_locale_is_missing + I18n.locale = :dk + get :hello_world + assert_equal "Hello World", @response.body + end +end
\ No newline at end of file diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index 8910454b8b..6f1ce2fef7 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -189,6 +189,12 @@ XML assert_equal Hash.new, @request.session.to_hash end + def test_response_and_request_have_nice_accessors + process :no_op + assert_equal @response, response + assert_equal @request, request + end + def test_process_with_request_uri_with_no_params process :test_uri assert_equal "/test_test/test/test_uri", @response.body diff --git a/actionpack/test/controller/verification_test.rb b/actionpack/test/controller/verification_test.rb deleted file mode 100644 index 0600ec2ec1..0000000000 --- a/actionpack/test/controller/verification_test.rb +++ /dev/null @@ -1,270 +0,0 @@ -require 'abstract_unit' - -class VerificationTest < ActionController::TestCase - class TestController < ActionController::Base - verify :only => :guarded_one, :params => "one", - :add_flash => { :error => 'unguarded' }, - :redirect_to => { :action => "unguarded" } - - verify :only => :guarded_two, :params => %w( one two ), - :redirect_to => { :action => "unguarded" } - - verify :only => :guarded_with_flash, :params => "one", - :add_flash => { :notice => "prereqs failed" }, - :redirect_to => { :action => "unguarded" } - - verify :only => :guarded_in_session, :session => "one", - :redirect_to => { :action => "unguarded" } - - verify :only => [:multi_one, :multi_two], :session => %w( one two ), - :redirect_to => { :action => "unguarded" } - - verify :only => :guarded_by_method, :method => :post, - :redirect_to => { :action => "unguarded" } - - verify :only => :guarded_by_xhr, :xhr => true, - :redirect_to => { :action => "unguarded" } - - verify :only => :guarded_by_not_xhr, :xhr => false, - :redirect_to => { :action => "unguarded" } - - before_filter :unconditional_redirect, :only => :two_redirects - verify :only => :two_redirects, :method => :post, - :redirect_to => { :action => "unguarded" } - - verify :only => :must_be_post, :method => :post, :render => { :status => 405, :text => "Must be post" }, :add_headers => { "Allow" => "POST" } - - verify :only => :guarded_one_for_named_route_test, :params => "one", - :redirect_to => :foo_url - - verify :only => :no_default_action, :params => "santa" - - verify :only => :guarded_with_back, :method => :post, - :redirect_to => :back - - def guarded_one - render :text => "#{params[:one]}" - end - - def guarded_one_for_named_route_test - render :text => "#{params[:one]}" - end - - def guarded_with_flash - render :text => "#{params[:one]}" - end - - def guarded_two - render :text => "#{params[:one]}:#{params[:two]}" - end - - def guarded_in_session - render :text => "#{session["one"]}" - end - - def multi_one - render :text => "#{session["one"]}:#{session["two"]}" - end - - def multi_two - render :text => "#{session["two"]}:#{session["one"]}" - end - - def guarded_by_method - render :text => "#{request.method.downcase}" - end - - def guarded_by_xhr - render :text => "#{request.xhr?}" - end - - def guarded_by_not_xhr - render :text => "#{request.xhr?}" - end - - def unguarded - render :text => "#{params[:one]}" - end - - def two_redirects - render :nothing => true - end - - def must_be_post - render :text => "Was a post!" - end - - def guarded_with_back - render :text => "#{params[:one]}" - end - - def no_default_action - # Will never run - end - - protected - - def unconditional_redirect - redirect_to :action => "unguarded" - end - end - - tests TestController - - def test_using_symbol_back_with_no_referrer - assert_raise(ActionController::RedirectBackError) { get :guarded_with_back } - end - - def test_using_symbol_back_redirects_to_referrer - @request.env["HTTP_REFERER"] = "/foo" - get :guarded_with_back - assert_redirected_to '/foo' - end - - def test_no_deprecation_warning_for_named_route - assert_not_deprecated do - with_routing do |set| - set.draw do |map| - match 'foo', :to => 'test#foo', :as => :foo - match 'verification_test/:action', :to => ::VerificationTest::TestController - end - get :guarded_one_for_named_route_test, :two => "not one" - assert_redirected_to '/foo' - end - end - end - - def test_guarded_one_with_prereqs - get :guarded_one, :one => "here" - assert_equal "here", @response.body - end - - def test_guarded_one_without_prereqs - get :guarded_one - assert_redirected_to :action => "unguarded" - assert_equal 'unguarded', flash[:error] - end - - def test_guarded_with_flash_with_prereqs - get :guarded_with_flash, :one => "here" - assert_equal "here", @response.body - assert flash.empty? - end - - def test_guarded_with_flash_without_prereqs - get :guarded_with_flash - assert_redirected_to :action => "unguarded" - assert_equal "prereqs failed", flash[:notice] - end - - def test_guarded_two_with_prereqs - get :guarded_two, :one => "here", :two => "there" - assert_equal "here:there", @response.body - end - - def test_guarded_two_without_prereqs_one - get :guarded_two, :two => "there" - assert_redirected_to :action => "unguarded" - end - - def test_guarded_two_without_prereqs_two - get :guarded_two, :one => "here" - assert_redirected_to :action => "unguarded" - end - - def test_guarded_two_without_prereqs_both - get :guarded_two - assert_redirected_to :action => "unguarded" - end - - def test_unguarded_with_params - get :unguarded, :one => "here" - assert_equal "here", @response.body - end - - def test_unguarded_without_params - get :unguarded - assert @response.body.blank? - end - - def test_guarded_in_session_with_prereqs - get :guarded_in_session, {}, "one" => "here" - assert_equal "here", @response.body - end - - def test_guarded_in_session_without_prereqs - get :guarded_in_session - assert_redirected_to :action => "unguarded" - end - - def test_multi_one_with_prereqs - get :multi_one, {}, "one" => "here", "two" => "there" - assert_equal "here:there", @response.body - end - - def test_multi_one_without_prereqs - get :multi_one - assert_redirected_to :action => "unguarded" - end - - def test_multi_two_with_prereqs - get :multi_two, {}, "one" => "here", "two" => "there" - assert_equal "there:here", @response.body - end - - def test_multi_two_without_prereqs - get :multi_two - assert_redirected_to :action => "unguarded" - end - - def test_guarded_by_method_with_prereqs - post :guarded_by_method - assert_equal "post", @response.body - end - - def test_guarded_by_method_without_prereqs - get :guarded_by_method - assert_redirected_to :action => "unguarded" - end - - def test_guarded_by_xhr_with_prereqs - xhr :post, :guarded_by_xhr - assert_equal "true", @response.body - end - - def test_guarded_by_xhr_without_prereqs - get :guarded_by_xhr - assert_redirected_to :action => "unguarded" - end - - def test_guarded_by_not_xhr_with_prereqs - get :guarded_by_not_xhr - assert_equal "false", @response.body - end - - def test_guarded_by_not_xhr_without_prereqs - xhr :post, :guarded_by_not_xhr - assert_redirected_to :action => "unguarded" - end - - def test_guarded_post_and_calls_render_succeeds - post :must_be_post - assert_equal "Was a post!", @response.body - end - - def test_default_failure_should_be_a_bad_request - post :no_default_action - assert_response :bad_request - end - - def test_guarded_post_and_calls_render_fails_and_sets_allow_header - get :must_be_post - assert_response 405 - assert_equal "Must be post", @response.body - assert_equal "POST", @response.headers["Allow"] - end - - def test_second_redirect - assert_nothing_raised { get :two_redirects } - end -end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 6ff478aec1..d38c48bfd4 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -186,6 +186,15 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end resource :dashboard, :constraints => { :ip => /192\.168\.1\.\d{1,3}/ } + + scope :module => 'api' do + resource :token + end + + scope :path => 'api' do + resource :me + match '/' => 'mes#index' + end end end @@ -942,6 +951,25 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_module_scope + with_test_routes do + get '/token' + assert_equal 'api/tokens#show', @response.body + assert_equal '/token', token_path + end + end + + def test_path_scope + with_test_routes do + get '/api/me' + assert_equal 'mes#show', @response.body + assert_equal '/api/me', me_path + + get '/api' + assert_equal 'mes#index', @response.body + end + end + private def with_test_routes yield diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 97da680f17..b447b0715c 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -106,4 +106,13 @@ class ShowExceptionsTest < ActionController::IntegrationTest assert_response 405 assert_match /ActionController::MethodNotAllowed/, body end + + test "does not show filtered parameters" do + @app = DevelopmentApp + + get "/", {"foo"=>"bar"}, {'action_dispatch.show_exceptions' => true, + 'action_dispatch.parameter_filter' => [:foo]} + assert_response 500 + assert_match ""foo"=>"[FILTERED]"", body + end end diff --git a/actionpack/test/fixtures/localized/hello_world.de.html b/actionpack/test/fixtures/localized/hello_world.de.html new file mode 100644 index 0000000000..4727d7a7e0 --- /dev/null +++ b/actionpack/test/fixtures/localized/hello_world.de.html @@ -0,0 +1 @@ +Gutten Tag
\ No newline at end of file diff --git a/actionpack/test/fixtures/localized/hello_world.en.html b/actionpack/test/fixtures/localized/hello_world.en.html new file mode 100644 index 0000000000..5e1c309dae --- /dev/null +++ b/actionpack/test/fixtures/localized/hello_world.en.html @@ -0,0 +1 @@ +Hello World
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_utf8_partial.html.erb b/actionpack/test/fixtures/test/_utf8_partial.html.erb new file mode 100644 index 0000000000..8d717fd427 --- /dev/null +++ b/actionpack/test/fixtures/test/_utf8_partial.html.erb @@ -0,0 +1 @@ +<%= "текст" %> diff --git a/actionpack/test/fixtures/test/_utf8_partial_magic.html.erb b/actionpack/test/fixtures/test/_utf8_partial_magic.html.erb new file mode 100644 index 0000000000..4e2224610a --- /dev/null +++ b/actionpack/test/fixtures/test/_utf8_partial_magic.html.erb @@ -0,0 +1,2 @@ +<%# encoding: utf-8 -%> +<%= "текст" %> diff --git a/actionpack/test/fixtures/test/utf8.html.erb b/actionpack/test/fixtures/test/utf8.html.erb index 14fe12debc..ac98c2f012 100644 --- a/actionpack/test/fixtures/test/utf8.html.erb +++ b/actionpack/test/fixtures/test/utf8.html.erb @@ -1,4 +1,4 @@ -Русский текст +Русский <%= render :partial => 'test/utf8_partial' %> <%= "日".encoding %> <%= @output_buffer.encoding %> <%= __ENCODING__ %> diff --git a/actionpack/test/fixtures/test/utf8_magic.html.erb b/actionpack/test/fixtures/test/utf8_magic.html.erb index 58cd03b439..257279c29f 100644 --- a/actionpack/test/fixtures/test/utf8_magic.html.erb +++ b/actionpack/test/fixtures/test/utf8_magic.html.erb @@ -1,5 +1,5 @@ <%# encoding: utf-8 -%> -Русский текст +Русский <%= render :partial => 'test/utf8_partial_magic' %> <%= "日".encoding %> <%= @output_buffer.encoding %> <%= __ENCODING__ %> diff --git a/actionpack/test/fixtures/test/utf8_magic_with_bare_partial.html.erb b/actionpack/test/fixtures/test/utf8_magic_with_bare_partial.html.erb new file mode 100644 index 0000000000..cb22692f9a --- /dev/null +++ b/actionpack/test/fixtures/test/utf8_magic_with_bare_partial.html.erb @@ -0,0 +1,5 @@ +<%# encoding: utf-8 -%> +Русский <%= render :partial => 'test/utf8_partial' %> +<%= "日".encoding %> +<%= @output_buffer.encoding %> +<%= __ENCODING__ %> diff --git a/actionpack/test/template/active_model_helper_i18n_test.rb b/actionpack/test/template/active_model_helper_i18n_test.rb deleted file mode 100644 index 4eb2f262bd..0000000000 --- a/actionpack/test/template/active_model_helper_i18n_test.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'abstract_unit' - -class ActiveModelHelperI18nTest < Test::Unit::TestCase - include ActionView::Context - include ActionView::Helpers::ActiveModelHelper - - attr_reader :request - - def setup - @object = stub :errors => stub(:count => 1, :full_messages => ['full_messages']) - @object.stubs :to_model => @object - @object.stubs :class => stub(:model_name => stub(:human => "")) - - @object_name = 'book_seller' - @object_name_without_underscore = 'book seller' - - stubs(:content_tag).returns 'content_tag' - - I18n.stubs(:t).with(:'header', :locale => 'en', :scope => [:errors, :template], :count => 1, :model => '').returns "1 error prohibited this from being saved" - I18n.stubs(:t).with(:'body', :locale => 'en', :scope => [:errors, :template]).returns 'There were problems with the following fields:' - end - - def test_error_messages_for_given_a_header_option_it_does_not_translate_header_message - I18n.expects(:t).with(:'header', :locale => 'en', :scope => [:errors, :template], :count => 1, :model => '').never - error_messages_for(:object => @object, :header_message => 'header message', :locale => 'en') - end - - def test_error_messages_for_given_no_header_option_it_translates_header_message - I18n.expects(:t).with(:'header', :locale => 'en', :scope => [:errors, :template], :count => 1, :model => '').returns 'header message' - error_messages_for(:object => @object, :locale => 'en') - end - - def test_error_messages_for_given_a_message_option_it_does_not_translate_message - I18n.expects(:t).with(:'body', :locale => 'en', :scope => [:errors, :template]).never - error_messages_for(:object => @object, :message => 'message', :locale => 'en') - end - - def test_error_messages_for_given_no_message_option_it_translates_message - I18n.expects(:t).with(:'body', :locale => 'en', :scope => [:errors, :template]).returns 'There were problems with the following fields:' - error_messages_for(:object => @object, :locale => 'en') - end -end diff --git a/actionpack/test/template/active_model_helper_test.rb b/actionpack/test/template/active_model_helper_test.rb index 47eb620f7a..8deeb78eab 100644 --- a/actionpack/test/template/active_model_helper_test.rb +++ b/actionpack/test/template/active_model_helper_test.rb @@ -4,132 +4,25 @@ class ActiveModelHelperTest < ActionView::TestCase tests ActionView::Helpers::ActiveModelHelper silence_warnings do - class Post < Struct.new(:title, :author_name, :body, :secret, :written_on) - extend ActiveModel::Naming + class Post < Struct.new(:author_name, :body) include ActiveModel::Conversion - end - - class User < Struct.new(:email) - extend ActiveModel::Naming - include ActiveModel::Conversion - end - - class Column < Struct.new(:type, :name, :human_name) - extend ActiveModel::Naming - include ActiveModel::Conversion - end - end + include ActiveModel::Validations - class DirtyPost - class Errors - def empty? + def persisted? false end - - def count - 1 - end - - def full_messages - ["Author name can't be <em>empty</em>"] - end - - def [](field) - ["can't be <em>empty</em>"] - end - end - - def errors - Errors.new end end - def setup_post - @post = Post.new - def @post.errors - Class.new { - def [](field) - case field.to_s - when "author_name" - ["can't be empty"] - when "body" - ['foo'] - else - [] - end - end - def empty?() false end - def count() 1 end - def full_messages() [ "Author name can't be empty" ] end - }.new - end - - def @post.persisted?() false end - def @post.to_param() nil end - - def @post.column_for_attribute(attr_name) - Post.content_columns.select { |column| column.name == attr_name }.first - end - - silence_warnings do - def Post.content_columns() [ Column.new(:string, "title", "Title"), Column.new(:text, "body", "Body") ] end - end - - @post.title = "Hello World" - @post.author_name = "" - @post.body = "Back to the hill and over it again!" - @post.secret = 1 - @post.written_on = Date.new(2004, 6, 15) - end - - def setup_user - @user = User.new - def @user.errors - Class.new { - def [](field) field == "email" ? ['nonempty'] : [] end - def empty?() false end - def count() 1 end - def full_messages() [ "User email can't be empty" ] end - }.new - end - - def @user.new_record?() true end - def @user.to_param() nil end - - def @user.column_for_attribute(attr_name) - User.content_columns.select { |column| column.name == attr_name }.first - end - - silence_warnings do - def User.content_columns() [ Column.new(:string, "email", "Email") ] end - end - - @user.email = "" - end - - def protect_against_forgery? - @protect_against_forgery ? true : false - end - attr_accessor :request_forgery_protection_token, :form_authenticity_token - def setup super - setup_post - setup_user - - @response = ActionController::TestResponse.new - end - - def url_for(options) - options = options.symbolize_keys - [options[:action], options[:id].to_param].compact.join('/') - end + @post = Post.new + @post.errors[:author_name] << "can't be empty" + @post.errors[:body] << "foo" - def test_generic_input_tag - assert_dom_equal( - %(<input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />), input("post", "title") - ) + @post.author_name = "" + @post.body = "Back to the hill and over it again!" end def test_text_area_with_errors @@ -160,176 +53,11 @@ class ActiveModelHelperTest < ActionView::TestCase ActionView::Base.field_error_proc = old_proc if old_proc end - def test_form_with_string - assert_dom_equal( - %(<form action="create" method="post"><p><label for="post_title">Title</label><br /><input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /></p>\n<p><label for="post_body">Body</label><br /><div class="fieldWithErrors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div></p><input name="commit" type="submit" value="Create" /></form>), - form("post") - ) - - silence_warnings do - class << @post - def persisted?() true end - def to_param() id end - def id() 1 end + def test_deprecations + %w(input form error_messages_for error_message_on).each do |method| + assert_deprecated do + send(method, "post") end end - - assert_dom_equal( - %(<form action="update/1" method="post"><input id="post_id" name="post[id]" type="hidden" value="1" /><p><label for="post_title">Title</label><br /><input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /></p>\n<p><label for="post_body">Body</label><br /><div class="fieldWithErrors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div></p><input name="commit" type="submit" value="Update" /></form>), - form("post") - ) - end - - def test_form_with_protect_against_forgery - @protect_against_forgery = true - @request_forgery_protection_token = 'authenticity_token' - @form_authenticity_token = '123' - assert_dom_equal( - %(<form action="create" method="post"><div style='margin:0;padding:0;display:inline'><input type='hidden' name='authenticity_token' value='123' /></div><p><label for="post_title">Title</label><br /><input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /></p>\n<p><label for="post_body">Body</label><br /><div class="fieldWithErrors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div></p><input name="commit" type="submit" value="Create" /></form>), - form("post") - ) - end - - def test_form_with_method_option - assert_dom_equal( - %(<form action="create" method="get"><p><label for="post_title">Title</label><br /><input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /></p>\n<p><label for="post_body">Body</label><br /><div class="fieldWithErrors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div></p><input name="commit" type="submit" value="Create" /></form>), - form("post", :method=>'get') - ) - end - - def test_form_with_action_option - output_buffer << form("post", :action => "sign") - assert_select "form[action=sign]" do |form| - assert_select "input[type=submit][value=Sign]" - end - end - - def test_form_with_date - silence_warnings do - def Post.content_columns() [ Column.new(:date, "written_on", "Written on") ] end - end - - assert_dom_equal( - %(<form action="create" method="post"><p><label for="post_written_on">Written on</label><br /><select id="post_written_on_1i" name="post[written_on(1i)]">\n<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n</select>\n<select id="post_written_on_2i" name="post[written_on(2i)]">\n<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6" selected="selected">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n</select>\n<select id="post_written_on_3i" name="post[written_on(3i)]">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15" selected="selected">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n</select>\n</p><input name="commit" type="submit" value="Create" /></form>), - form("post") - ) - end - - def test_form_with_datetime - silence_warnings do - def Post.content_columns() [ Column.new(:datetime, "written_on", "Written on") ] end - end - @post.written_on = Time.gm(2004, 6, 15, 16, 30) - - assert_dom_equal( - %(<form action="create" method="post"><p><label for="post_written_on">Written on</label><br /><select id="post_written_on_1i" name="post[written_on(1i)]">\n<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n</select>\n<select id="post_written_on_2i" name="post[written_on(2i)]">\n<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6" selected="selected">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n</select>\n<select id="post_written_on_3i" name="post[written_on(3i)]">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15" selected="selected">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n</select>\n — <select id="post_written_on_4i" name="post[written_on(4i)]">\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n</select>\n : <select id="post_written_on_5i" name="post[written_on(5i)]">\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30" selected="selected">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n</select>\n</p><input name="commit" type="submit" value="Create" /></form>), - form("post") - ) - end - - def test_error_for_block - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>), error_messages_for("post") - assert_equal %(<div class="errorDeathByClass" id="errorDeathById"><h1>1 error prohibited this post from being saved</h1><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>), error_messages_for("post", :class => "errorDeathByClass", :id => "errorDeathById", :header_tag => "h1") - assert_equal %(<div id="errorDeathById"><h1>1 error prohibited this post from being saved</h1><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>), error_messages_for("post", :class => nil, :id => "errorDeathById", :header_tag => "h1") - assert_equal %(<div class="errorDeathByClass"><h1>1 error prohibited this post from being saved</h1><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>), error_messages_for("post", :class => "errorDeathByClass", :id => nil, :header_tag => "h1") - end - - def test_error_messages_for_escapes_html - @dirty_post = DirtyPost.new - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this dirty post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be <em>empty</em></li></ul></div>), error_messages_for("dirty_post") - end - - def test_error_messages_for_handles_nil - assert_equal "", error_messages_for("notthere") - end - - def test_error_message_on_escapes_html - @dirty_post = DirtyPost.new - assert_dom_equal "<div class=\"formError\">can't be <em>empty</em></div>", error_message_on(:dirty_post, :author_name) - end - - def test_error_message_on_handles_nil - assert_equal "", error_message_on("notthere", "notthere") - end - - def test_error_message_on - assert_dom_equal "<div class=\"formError\">can't be empty</div>", error_message_on(:post, :author_name) - end - - def test_error_message_on_no_instance_variable - other_post = @post - assert_dom_equal "<div class=\"formError\">can't be empty</div>", error_message_on(other_post, :author_name) - end - - def test_error_message_on_with_options_hash - assert_dom_equal "<div class=\"differentError\">beforecan't be emptyafter</div>", error_message_on(:post, :author_name, :css_class => 'differentError', :prepend_text => 'before', :append_text => 'after') - end - - def test_error_message_on_with_tag_option_in_options_hash - assert_dom_equal "<span class=\"differentError\">beforecan't be emptyafter</span>", error_message_on(:post, :author_name, :html_tag => "span", :css_class => 'differentError', :prepend_text => 'before', :append_text => 'after') - end - - def test_error_message_on_handles_empty_errors - assert_equal "", error_message_on(@post, :tag) - end - - def test_error_messages_for_many_objects - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li><li>User email can't be empty</li></ul></div>), error_messages_for("post", "user") - - # reverse the order, error order changes and so does the title - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this user from being saved</h2><p>There were problems with the following fields:</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), error_messages_for("user", "post") - - # add the default to put post back in the title - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), error_messages_for("user", "post", :object_name => "post") - - # symbols work as well - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), error_messages_for(:user, :post, :object_name => :post) - - # any default works too - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this monkey from being saved</h2><p>There were problems with the following fields:</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), error_messages_for(:user, :post, :object_name => "monkey") - - # should space object name - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this chunky bacon from being saved</h2><p>There were problems with the following fields:</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), error_messages_for(:user, :post, :object_name => "chunky_bacon") - - # hide header and explanation messages with nil or empty string - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), error_messages_for(:user, :post, :header_message => nil, :message => "") - - # override header and explanation messages - header_message = "Yikes! Some errors" - message = "Please fix the following fields and resubmit:" - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>#{header_message}</h2><p>#{message}</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), error_messages_for(:user, :post, :header_message => header_message, :message => message) - end - - def test_error_messages_for_non_instance_variable - actual_user = @user - actual_post = @post - @user = nil - @post = nil - - #explicitly set object - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>), error_messages_for("post", :object => actual_post) - - #multiple objects - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this user from being saved</h2><p>There were problems with the following fields:</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), error_messages_for("user", "post", :object => [actual_user, actual_post]) - - #nil object - assert_equal '', error_messages_for('user', :object => nil) - end - - def test_error_messages_for_model_objects - error = error_messages_for(@post) - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>), - error - - error = error_messages_for(@user, @post) - assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this user from being saved</h2><p>There were problems with the following fields:</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), - error - end - - def test_form_with_string_multipart - assert_dom_equal( - %(<form action="create" enctype="multipart/form-data" method="post"><p><label for="post_title">Title</label><br /><input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /></p>\n<p><label for="post_body">Body</label><br /><div class="fieldWithErrors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div></p><input name="commit" type="submit" value="Create" /></form>), - form("post", :multipart => true) - ) end end diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index 223a430f92..124bf734ac 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -157,6 +157,14 @@ class AssetTagHelperTest < ActionView::TestCase %(image_tag("mouse.png", :mouseover => image_path("mouse_over.png"))) => %(<img alt="Mouse" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" src="/images/mouse.png" />) } + FaviconLinkToTag = { + %(favicon_link_tag) => %(<link href="/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />), + %(favicon_link_tag 'favicon.ico') => %(<link href="/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />), + %(favicon_link_tag 'favicon.ico', :rel => 'foo') => %(<link href="/images/favicon.ico" rel="foo" type="image/vnd.microsoft.icon" />), + %(favicon_link_tag 'favicon.ico', :rel => 'foo', :type => 'bar') => %(<link href="/images/favicon.ico" rel="foo" type="bar" />), + %(favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png') => %(<link href="/images/mb-icon.png" rel="apple-touch-icon" type="image/png" />) + } + VideoPathToTag = { %(video_path("xml")) => %(/videos/xml), %(video_path("xml.ogg")) => %(/videos/xml.ogg), @@ -331,6 +339,10 @@ class AssetTagHelperTest < ActionView::TestCase ImageLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end + def test_favicon_link_tag + FaviconLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + def test_image_tag_windows_behaviour old_asset_id, ENV["RAILS_ASSET_ID"] = ENV["RAILS_ASSET_ID"], "1" # This simulates the behaviour of File#exist? on windows when testing a file ending in "." diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 64dfbde0b0..28a13b07be 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -1314,12 +1314,12 @@ class FormHelperTest < ActionView::TestCase class LabelledFormBuilder < ActionView::Helpers::FormBuilder (field_helpers - %w(hidden_field)).each do |selector| - src = <<-END_SRC + src, line = <<-END_SRC, __LINE__ + 1 def #{selector}(field, *args, &proc) ("<label for='\#{field}'>\#{field.to_s.humanize}:</label> " + super + "<br/>").html_safe end END_SRC - class_eval src, __FILE__, __LINE__ + class_eval src, __FILE__, line end end @@ -1366,43 +1366,6 @@ class FormHelperTest < ActionView::TestCase ActionView::Base.default_form_builder = old_default_form_builder end - def test_default_form_builder_with_active_record_helpers - assert_deprecated do - form_for(:post, @post) do |f| - concat f.error_message_on('author_name') - concat f.error_messages - end - end - - expected = %(<form action='http://www.example.com' method='post'>) + - %(<div class='formError'>can't be empty</div>) + - %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) + - %(</form>) - - assert_dom_equal expected, output_buffer - - end - - def test_default_form_builder_no_instance_variable - post = @post - @post = nil - - assert_deprecated do - form_for(:post, post) do |f| - concat f.error_message_on('author_name') - concat f.error_messages - end - end - - expected = %(<form action='http://www.example.com' method='post'>) + - %(<div class='formError'>can't be empty</div>) + - %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) + - %(</form>) - - assert_dom_equal expected, output_buffer - - end - def test_fields_for_with_labelled_builder output_buffer = fields_for(:post, @post, :builder => LabelledFormBuilder) do |f| concat f.text_field(:title) diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 5f33c933db..c9a50da418 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -245,31 +245,6 @@ module RenderTestCases assert_equal %(\n<title>title</title>\n\n), @view.render(:file => "test/layout_render_file.erb") end - - if '1.9'.respond_to?(:force_encoding) - def test_render_utf8_template_with_magic_comment - with_external_encoding Encoding::ASCII_8BIT do - result = @view.render(:file => "test/utf8_magic.html.erb", :layouts => "layouts/yield") - assert_equal "Русский текст\nUTF-8\nUTF-8\nUTF-8\n", result - assert_equal Encoding::UTF_8, result.encoding - end - end - - def test_render_utf8_template_with_default_external_encoding - with_external_encoding Encoding::UTF_8 do - result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") - assert_equal "Русский текст\nUTF-8\nUTF-8\nUTF-8\n", result - assert_equal Encoding::UTF_8, result.encoding - end - end - - def with_external_encoding(encoding) - old, Encoding.default_external = Encoding.default_external, encoding - yield - ensure - Encoding.default_external = old - end - end end class CachedViewRenderTest < ActiveSupport::TestCase @@ -302,4 +277,51 @@ class LazyViewRenderTest < ActiveSupport::TestCase def teardown GC.start end + + if '1.9'.respond_to?(:force_encoding) + def test_render_utf8_template_with_magic_comment + with_external_encoding Encoding::ASCII_8BIT do + result = @view.render(:file => "test/utf8_magic.html.erb", :layouts => "layouts/yield") + assert_equal Encoding::UTF_8, result.encoding + assert_equal "Русский текст\n\nUTF-8\nUTF-8\nUTF-8\n", result + end + end + + def test_render_utf8_template_with_default_external_encoding + with_external_encoding Encoding::UTF_8 do + result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") + assert_equal Encoding::UTF_8, result.encoding + assert_equal "Русский текст\n\nUTF-8\nUTF-8\nUTF-8\n", result + end + end + + def test_render_utf8_template_with_incompatible_external_encoding + with_external_encoding Encoding::SJIS do + begin + result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") + flunk 'Should have raised incompatible encoding error' + rescue ActionView::Template::Error => error + assert_match 'invalid byte sequence in Shift_JIS', error.original_exception.message + end + end + end + + def test_render_utf8_template_with_partial_with_incompatible_encoding + with_external_encoding Encoding::SJIS do + begin + result = @view.render(:file => "test/utf8_magic_with_bare_partial.html.erb", :layouts => "layouts/yield") + flunk 'Should have raised incompatible encoding error' + rescue ActionView::Template::Error => error + assert_match 'invalid byte sequence in Shift_JIS', error.original_exception.message + end + end + end + + def with_external_encoding(encoding) + old, Encoding.default_external = Encoding.default_external, encoding + yield + ensure + Encoding.default_external = old + end + end end diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 35e73fbf1e..de63030714 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -74,56 +74,56 @@ class UrlHelperTest < ActiveSupport::TestCase # todo: missing test cases def test_button_to_with_straight_url - assert_dom_equal "<form method=\"post\" action=\"http://www.example.com\" class=\"button-to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com") + assert_dom_equal "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com") end def test_button_to_with_query - assert_dom_equal "<form method=\"post\" action=\"http://www.example.com/q1=v1&q2=v2\" class=\"button-to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com/q1=v1&q2=v2") + assert_dom_equal "<form method=\"post\" action=\"http://www.example.com/q1=v1&q2=v2\" class=\"button_to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com/q1=v1&q2=v2") end def test_button_to_with_escaped_query - assert_dom_equal "<form method=\"post\" action=\"http://www.example.com/q1=v1&q2=v2\" class=\"button-to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com/q1=v1&q2=v2") + assert_dom_equal "<form method=\"post\" action=\"http://www.example.com/q1=v1&q2=v2\" class=\"button_to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com/q1=v1&q2=v2") end def test_button_to_with_query_and_no_name - assert_dom_equal "<form method=\"post\" action=\"http://www.example.com?q1=v1&q2=v2\" class=\"button-to\"><div><input type=\"submit\" value=\"http://www.example.com?q1=v1&q2=v2\" /></div></form>", button_to(nil, "http://www.example.com?q1=v1&q2=v2") + assert_dom_equal "<form method=\"post\" action=\"http://www.example.com?q1=v1&q2=v2\" class=\"button_to\"><div><input type=\"submit\" value=\"http://www.example.com?q1=v1&q2=v2\" /></div></form>", button_to(nil, "http://www.example.com?q1=v1&q2=v2") end def test_button_to_with_javascript_confirm assert_dom_equal( - "<form method=\"post\" action=\"http://www.example.com\" class=\"button-to\"><div><input data-confirm=\"Are you sure?\" type=\"submit\" value=\"Hello\" /></div></form>", + "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input data-confirm=\"Are you sure?\" type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com", :confirm => "Are you sure?") ) end def test_button_to_with_remote_and_javascript_confirm assert_dom_equal( - "<form method=\"post\" action=\"http://www.example.com\" class=\"button-to\" data-remote=\"true\"><div><input data-confirm=\"Are you sure?\" type=\"submit\" value=\"Hello\" /></div></form>", + "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\" data-remote=\"true\"><div><input data-confirm=\"Are you sure?\" type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com", :remote => true, :confirm => "Are you sure?") ) end def test_button_to_enabled_disabled assert_dom_equal( - "<form method=\"post\" action=\"http://www.example.com\" class=\"button-to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", + "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com", :disabled => false) ) assert_dom_equal( - "<form method=\"post\" action=\"http://www.example.com\" class=\"button-to\"><div><input disabled=\"disabled\" type=\"submit\" value=\"Hello\" /></div></form>", + "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input disabled=\"disabled\" type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com", :disabled => true) ) end def test_button_to_with_method_delete assert_dom_equal( - "<form method=\"post\" action=\"http://www.example.com\" class=\"button-to\"><div><input type=\"hidden\" name=\"_method\" value=\"delete\" /><input type=\"submit\" value=\"Hello\" /></div></form>", + "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input type=\"hidden\" name=\"_method\" value=\"delete\" /><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com", :method => :delete) ) end def test_button_to_with_method_get assert_dom_equal( - "<form method=\"get\" action=\"http://www.example.com\" class=\"button-to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", + "<form method=\"get\" action=\"http://www.example.com\" class=\"button_to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com", :method => :get) ) end |