mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Merge branch 'master' into docrails_master
This commit is contained in:
@@ -3,7 +3,7 @@ module ActionMailer
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "beta2"
|
||||
BUILD = "beta3"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
end
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ module ActionController
|
||||
autoload :Streaming
|
||||
autoload :Testing
|
||||
autoload :UrlFor
|
||||
autoload :Verification
|
||||
end
|
||||
|
||||
autoload :Dispatcher, 'action_controller/deprecated/dispatcher'
|
||||
|
||||
@@ -30,7 +30,6 @@ module ActionController
|
||||
|
||||
Cookies,
|
||||
Flash,
|
||||
Verification,
|
||||
RequestForgeryProtection,
|
||||
Streaming,
|
||||
RecordIdentifier,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<% end %>
|
||||
|
||||
<%
|
||||
clean_params = @request.parameters.clone
|
||||
clean_params = @request.filtered_parameters.clone
|
||||
clean_params.delete("action")
|
||||
clean_params.delete("controller")
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -3,7 +3,7 @@ module ActionPack
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "beta2"
|
||||
BUILD = "beta3"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
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)
|
||||
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 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
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
#
|
||||
|
||||
@@ -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.
|
||||
#
|
||||
|
||||
@@ -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!
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
22
actionpack/test/controller/localized_templates_test.rb
Normal file
22
actionpack/test/controller/localized_templates_test.rb
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
1
actionpack/test/fixtures/localized/hello_world.de.html
vendored
Normal file
1
actionpack/test/fixtures/localized/hello_world.de.html
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Gutten Tag
|
||||
1
actionpack/test/fixtures/localized/hello_world.en.html
vendored
Normal file
1
actionpack/test/fixtures/localized/hello_world.en.html
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Hello World
|
||||
1
actionpack/test/fixtures/test/_utf8_partial.html.erb
vendored
Normal file
1
actionpack/test/fixtures/test/_utf8_partial.html.erb
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<%= "текст" %>
|
||||
2
actionpack/test/fixtures/test/_utf8_partial_magic.html.erb
vendored
Normal file
2
actionpack/test/fixtures/test/_utf8_partial_magic.html.erb
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<%# encoding: utf-8 -%>
|
||||
<%= "текст" %>
|
||||
2
actionpack/test/fixtures/test/utf8.html.erb
vendored
2
actionpack/test/fixtures/test/utf8.html.erb
vendored
@@ -1,4 +1,4 @@
|
||||
Русский текст
|
||||
Русский <%= render :partial => 'test/utf8_partial' %>
|
||||
<%= "日".encoding %>
|
||||
<%= @output_buffer.encoding %>
|
||||
<%= __ENCODING__ %>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<%# encoding: utf-8 -%>
|
||||
Русский текст
|
||||
Русский <%= render :partial => 'test/utf8_partial_magic' %>
|
||||
<%= "日".encoding %>
|
||||
<%= @output_buffer.encoding %>
|
||||
<%= __ENCODING__ %>
|
||||
|
||||
5
actionpack/test/fixtures/test/utf8_magic_with_bare_partial.html.erb
vendored
Normal file
5
actionpack/test/fixtures/test/utf8_magic_with_bare_partial.html.erb
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
<%# encoding: utf-8 -%>
|
||||
Русский <%= render :partial => 'test/utf8_partial' %>
|
||||
<%= "日".encoding %>
|
||||
<%= @output_buffer.encoding %>
|
||||
<%= __ENCODING__ %>
|
||||
@@ -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
|
||||
File diff suppressed because one or more lines are too long
@@ -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 "."
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -221,7 +221,7 @@ module ActiveModel
|
||||
|
||||
def alias_attribute(new_name, old_name)
|
||||
attribute_method_matchers.each do |matcher|
|
||||
module_eval <<-STR, __FILE__, __LINE__+1
|
||||
module_eval <<-STR, __FILE__, __LINE__ + 1
|
||||
def #{matcher.method_name(new_name)}(*args)
|
||||
send(:#{matcher.method_name(old_name)}, *args)
|
||||
end
|
||||
@@ -265,7 +265,7 @@ module ActiveModel
|
||||
else
|
||||
method_name = matcher.method_name(attr_name)
|
||||
|
||||
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__+1
|
||||
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
||||
if method_defined?(:#{method_name})
|
||||
undef :#{method_name}
|
||||
end
|
||||
|
||||
@@ -105,7 +105,7 @@ module ActiveModel
|
||||
end
|
||||
|
||||
def _define_before_model_callback(klass, callback) #:nodoc:
|
||||
klass.class_eval <<-CALLBACK, __FILE__, __LINE__
|
||||
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
|
||||
def self.before_#{callback}(*args, &block)
|
||||
set_callback(:#{callback}, :before, *args, &block)
|
||||
end
|
||||
@@ -113,7 +113,7 @@ module ActiveModel
|
||||
end
|
||||
|
||||
def _define_around_model_callback(klass, callback) #:nodoc:
|
||||
klass.class_eval <<-CALLBACK, __FILE__, __LINE__
|
||||
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
|
||||
def self.around_#{callback}(*args, &block)
|
||||
set_callback(:#{callback}, :around, *args, &block)
|
||||
end
|
||||
@@ -121,7 +121,7 @@ module ActiveModel
|
||||
end
|
||||
|
||||
def _define_after_model_callback(klass, callback) #:nodoc:
|
||||
klass.class_eval <<-CALLBACK, __FILE__, __LINE__
|
||||
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
|
||||
def self.after_#{callback}(*args, &block)
|
||||
options = args.extract_options!
|
||||
options[:prepend] = true
|
||||
|
||||
@@ -142,6 +142,11 @@ module ActiveModel
|
||||
to_a.size
|
||||
end
|
||||
|
||||
# Returns true if there are any errors, false if not.
|
||||
def empty?
|
||||
all? { |k, v| v && v.empty? }
|
||||
end
|
||||
|
||||
# Returns an xml formatted representation of the Errors hash.
|
||||
#
|
||||
# p.errors.add(:name, "can't be blank")
|
||||
|
||||
@@ -3,7 +3,7 @@ module ActiveModel
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "beta2"
|
||||
BUILD = "beta3"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
end
|
||||
|
||||
@@ -97,6 +97,12 @@ class ValidationsTest < ActiveModel::TestCase
|
||||
assert_equal 2, r.errors.count
|
||||
end
|
||||
|
||||
def test_errors_empty_after_errors_on_check
|
||||
t = Topic.new
|
||||
assert t.errors[:id].empty?
|
||||
assert t.errors.empty?
|
||||
end
|
||||
|
||||
def test_validates_each
|
||||
hits = 0
|
||||
Topic.validates_each(:title, :content, [:title, :content]) do |record, attr|
|
||||
|
||||
@@ -50,6 +50,7 @@ end
|
||||
t.libs << "test" << connection_path
|
||||
t.test_files=Dir.glob( "test/cases/**/*_test{,_#{adapter_short}}.rb" ).sort
|
||||
t.verbose = true
|
||||
t.warning = true
|
||||
}
|
||||
|
||||
task "isolated_test_#{adapter}" do
|
||||
|
||||
@@ -105,6 +105,7 @@ module ActiveRecord
|
||||
|
||||
def reset
|
||||
reset_target!
|
||||
reset_named_scopes_cache!
|
||||
@loaded = false
|
||||
end
|
||||
|
||||
@@ -146,7 +147,7 @@ module ActiveRecord
|
||||
# has_many :books
|
||||
# end
|
||||
#
|
||||
# Author.find(:first).books.transaction do
|
||||
# Author.first.books.transaction do
|
||||
# # same effect as calling Book.transaction
|
||||
# end
|
||||
def transaction(*args)
|
||||
@@ -162,6 +163,7 @@ module ActiveRecord
|
||||
load_target
|
||||
delete(@target)
|
||||
reset_target!
|
||||
reset_named_scopes_cache!
|
||||
end
|
||||
|
||||
# Calculate sum using SQL, not Enumerable
|
||||
@@ -250,6 +252,7 @@ module ActiveRecord
|
||||
load_target
|
||||
destroy(@target)
|
||||
reset_target!
|
||||
reset_named_scopes_cache!
|
||||
end
|
||||
|
||||
def create(attrs = {})
|
||||
@@ -406,8 +409,8 @@ module ActiveRecord
|
||||
super
|
||||
end
|
||||
elsif @reflection.klass.scopes[method]
|
||||
@_scopes ||= {}
|
||||
@_scopes[method] ||= with_scope(construct_scope) { @reflection.klass.send(method, *args) }
|
||||
@_named_scopes_cache ||= {}
|
||||
@_named_scopes_cache[method] ||= with_scope(construct_scope) { @reflection.klass.send(method, *args) }
|
||||
else
|
||||
with_scope(construct_scope) do
|
||||
if block_given?
|
||||
@@ -428,6 +431,10 @@ module ActiveRecord
|
||||
@target = Array.new
|
||||
end
|
||||
|
||||
def reset_named_scopes_cache!
|
||||
@_named_scopes_cache = {}
|
||||
end
|
||||
|
||||
def find_target
|
||||
records =
|
||||
if @reflection.options[:finder_sql]
|
||||
|
||||
@@ -52,6 +52,8 @@ module ActiveRecord
|
||||
@changed_attributes.delete(attr) unless field_changed?(attr, old, value)
|
||||
else
|
||||
old = clone_attribute_value(:read_attribute, attr)
|
||||
# Save Time objects as TimeWithZone if time_zone_aware_attributes == true
|
||||
old = old.in_time_zone if clone_with_time_zone_conversion_attribute?(attr, old)
|
||||
@changed_attributes[attr] = old if field_changed?(attr, old, value)
|
||||
end
|
||||
|
||||
@@ -84,6 +86,10 @@ module ActiveRecord
|
||||
|
||||
old != value
|
||||
end
|
||||
|
||||
def clone_with_time_zone_conversion_attribute?(attr, old)
|
||||
old.class.name == "Time" && time_zone_aware_attributes && !skip_time_zone_conversion_for_attributes.include?(attr.to_sym)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,7 +17,7 @@ module ActiveRecord
|
||||
# This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone.
|
||||
def define_method_attribute(attr_name)
|
||||
if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
|
||||
method_body = <<-EOV
|
||||
method_body, line = <<-EOV, __LINE__ + 1
|
||||
def #{attr_name}(reload = false)
|
||||
cached = @attributes_cache['#{attr_name}']
|
||||
return cached if cached && !reload
|
||||
@@ -25,7 +25,7 @@ module ActiveRecord
|
||||
@attributes_cache['#{attr_name}'] = time.acts_like?(:time) ? time.in_time_zone : time
|
||||
end
|
||||
EOV
|
||||
generated_attribute_methods.module_eval(method_body, __FILE__, __LINE__)
|
||||
generated_attribute_methods.module_eval(method_body, __FILE__, line)
|
||||
else
|
||||
super
|
||||
end
|
||||
@@ -35,7 +35,7 @@ module ActiveRecord
|
||||
# This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone.
|
||||
def define_method_attribute=(attr_name)
|
||||
if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
|
||||
method_body = <<-EOV
|
||||
method_body, line = <<-EOV, __LINE__ + 1
|
||||
def #{attr_name}=(time)
|
||||
unless time.acts_like?(:time)
|
||||
time = time.is_a?(String) ? Time.zone.parse(time) : time.to_time rescue time
|
||||
@@ -44,7 +44,7 @@ module ActiveRecord
|
||||
write_attribute(:#{attr_name}, time)
|
||||
end
|
||||
EOV
|
||||
generated_attribute_methods.module_eval(method_body, __FILE__, __LINE__)
|
||||
generated_attribute_methods.module_eval(method_body, __FILE__, line)
|
||||
else
|
||||
super
|
||||
end
|
||||
|
||||
@@ -56,15 +56,15 @@ module ActiveRecord #:nodoc:
|
||||
#
|
||||
# class User < ActiveRecord::Base
|
||||
# def self.authenticate_unsafely(user_name, password)
|
||||
# find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'")
|
||||
# where("user_name = '#{user_name}' AND password = '#{password}'").first
|
||||
# end
|
||||
#
|
||||
# def self.authenticate_safely(user_name, password)
|
||||
# find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ])
|
||||
# where("user_name = ? AND password = ?", user_name, password).first
|
||||
# end
|
||||
#
|
||||
# def self.authenticate_safely_simply(user_name, password)
|
||||
# find(:first, :conditions => { :user_name => user_name, :password => password })
|
||||
# where(:user_name => user_name, :password => password).first
|
||||
# end
|
||||
# end
|
||||
#
|
||||
@@ -77,30 +77,30 @@ module ActiveRecord #:nodoc:
|
||||
# question mark is supposed to represent. In those cases, you can resort to named bind variables instead. That's done by replacing
|
||||
# the question marks with symbols and supplying a hash with values for the matching symbol keys:
|
||||
#
|
||||
# Company.find(:first, :conditions => [
|
||||
# Company.where(
|
||||
# "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
|
||||
# { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' }
|
||||
# ])
|
||||
# ).first
|
||||
#
|
||||
# Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND
|
||||
# operator. For instance:
|
||||
#
|
||||
# Student.find(:all, :conditions => { :first_name => "Harvey", :status => 1 })
|
||||
# Student.find(:all, :conditions => params[:student])
|
||||
# Student.where(:first_name => "Harvey", :status => 1)
|
||||
# Student.where(params[:student])
|
||||
#
|
||||
# A range may be used in the hash to use the SQL BETWEEN operator:
|
||||
#
|
||||
# Student.find(:all, :conditions => { :grade => 9..12 })
|
||||
# Student.where(:grade => 9..12)
|
||||
#
|
||||
# An array may be used in the hash to use the SQL IN operator:
|
||||
#
|
||||
# Student.find(:all, :conditions => { :grade => [9,11,12] })
|
||||
# Student.where(:grade => [9,11,12])
|
||||
#
|
||||
# When joining tables, nested hashes or keys written in the form 'table_name.column_name' can be used to qualify the table name of a
|
||||
# particular condition. For instance:
|
||||
#
|
||||
# Student.find(:all, :conditions => { :schools => { :type => 'public' }}, :joins => :schools)
|
||||
# Student.find(:all, :conditions => { 'schools.type' => 'public' }, :joins => :schools)
|
||||
# Student.joins(:schools).where(:schools => { :type => 'public' })
|
||||
# Student.joins(:schools).where('schools.type' => 'public' )
|
||||
#
|
||||
# == Overwriting default accessors
|
||||
#
|
||||
@@ -153,18 +153,18 @@ module ActiveRecord #:nodoc:
|
||||
# Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by
|
||||
# appending the name of an attribute to <tt>find_by_</tt>, <tt>find_last_by_</tt>, or <tt>find_all_by_</tt>, so you get finders like <tt>Person.find_by_user_name</tt>,
|
||||
# <tt>Person.find_all_by_last_name</tt>, and <tt>Payment.find_by_transaction_id</tt>. So instead of writing
|
||||
# <tt>Person.find(:first, :conditions => ["user_name = ?", user_name])</tt>, you just do <tt>Person.find_by_user_name(user_name)</tt>.
|
||||
# And instead of writing <tt>Person.find(:all, :conditions => ["last_name = ?", last_name])</tt>, you just do <tt>Person.find_all_by_last_name(last_name)</tt>.
|
||||
# <tt>Person.where(:user_name => user_name).first</tt>, you just do <tt>Person.find_by_user_name(user_name)</tt>.
|
||||
# And instead of writing <tt>Person.where(:last_name => last_name).all</tt>, you just do <tt>Person.find_all_by_last_name(last_name)</tt>.
|
||||
#
|
||||
# It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders like
|
||||
# <tt>Person.find_by_user_name_and_password</tt> or even <tt>Payment.find_by_purchaser_and_state_and_country</tt>. So instead of writing
|
||||
# <tt>Person.find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password])</tt>, you just do
|
||||
# <tt>Person.where(:user_name => user_name, :password => password).first</tt>, you just do
|
||||
# <tt>Person.find_by_user_name_and_password(user_name, password)</tt>.
|
||||
#
|
||||
# It's even possible to use all the additional parameters to find. For example, the full interface for <tt>Payment.find_all_by_amount</tt>
|
||||
# is actually <tt>Payment.find_all_by_amount(amount, options)</tt>. And the full interface to <tt>Person.find_by_user_name</tt> is
|
||||
# actually <tt>Person.find_by_user_name(user_name, options)</tt>. So you could call <tt>Payment.find_all_by_amount(50, :order => "created_on")</tt>.
|
||||
# Also you may call <tt>Payment.find_last_by_amount(amount, options)</tt> returning the last record matching that amount and options.
|
||||
# It's even possible to call these dynamic finder methods on relations and named scopes. For example :
|
||||
#
|
||||
# Payment.order("created_on").find_all_by_amount(50)
|
||||
# Payment.pending.find_last_by_amount(100)
|
||||
#
|
||||
# The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with
|
||||
# <tt>find_or_create_by_</tt> and will return the object if it already exists and otherwise creates it, then returns it. Protected attributes won't be set unless they are given in a block. For example:
|
||||
@@ -224,7 +224,7 @@ module ActiveRecord #:nodoc:
|
||||
# class PriorityClient < Client; end
|
||||
#
|
||||
# When you do <tt>Firm.create(:name => "37signals")</tt>, this record will be saved in the companies table with type = "Firm". You can then
|
||||
# fetch this row again using <tt>Company.find(:first, "name = '37signals'")</tt> and it will return a Firm object.
|
||||
# fetch this row again using <tt>Company.where(:name => '37signals').first</tt> and it will return a Firm object.
|
||||
#
|
||||
# If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just
|
||||
# like normal subclasses with no special magic for differentiating between them or reloading the right type with find.
|
||||
@@ -1117,10 +1117,6 @@ module ActiveRecord #:nodoc:
|
||||
# It's even possible to use all the additional parameters to +find+. For example, the full interface for +find_all_by_amount+
|
||||
# is actually <tt>find_all_by_amount(amount, options)</tt>.
|
||||
#
|
||||
# Also enables dynamic scopes like scoped_by_user_name(user_name) and scoped_by_user_name_and_password(user_name, password) that
|
||||
# are turned into scoped(:conditions => ["user_name = ?", user_name]) and scoped(:conditions => ["user_name = ? AND password = ?", user_name, password])
|
||||
# respectively.
|
||||
#
|
||||
# Each dynamic finder, scope or initializer/creator is also defined in the class after it is first invoked, so that future
|
||||
# attempts to use it do not run through method_missing.
|
||||
def method_missing(method_id, *arguments, &block)
|
||||
@@ -1138,7 +1134,7 @@ module ActiveRecord #:nodoc:
|
||||
attribute_names = match.attribute_names
|
||||
super unless all_attributes_exists?(attribute_names)
|
||||
if match.scope?
|
||||
self.class_eval %{
|
||||
self.class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
||||
def self.#{method_id}(*args) # def self.scoped_by_user_name_and_password(*args)
|
||||
options = args.extract_options! # options = args.extract_options!
|
||||
attributes = construct_attributes_from_arguments( # attributes = construct_attributes_from_arguments(
|
||||
@@ -1147,7 +1143,7 @@ module ActiveRecord #:nodoc:
|
||||
#
|
||||
scoped(:conditions => attributes) # scoped(:conditions => attributes)
|
||||
end # end
|
||||
}, __FILE__, __LINE__
|
||||
METHOD
|
||||
send(method_id, *arguments)
|
||||
end
|
||||
else
|
||||
@@ -1196,12 +1192,12 @@ module ActiveRecord #:nodoc:
|
||||
|
||||
protected
|
||||
# Scope parameters to method calls within the block. Takes a hash of method_name => parameters hash.
|
||||
# method_name may be <tt>:find</tt> or <tt>:create</tt>. <tt>:find</tt> parameters may include the <tt>:conditions</tt>, <tt>:joins</tt>,
|
||||
# <tt>:include</tt>, <tt>:offset</tt>, <tt>:limit</tt>, and <tt>:readonly</tt> options. <tt>:create</tt> parameters are an attributes hash.
|
||||
# method_name may be <tt>:find</tt> or <tt>:create</tt>. <tt>:find</tt> parameter is <tt>Relation</tt> while
|
||||
# <tt>:create</tt> parameters are an attributes hash.
|
||||
#
|
||||
# class Article < ActiveRecord::Base
|
||||
# def self.create_with_scope
|
||||
# with_scope(:find => { :conditions => "blog_id = 1" }, :create => { :blog_id => 1 }) do
|
||||
# with_scope(:find => where(:blog_id => 1), :create => { :blog_id => 1 }) do
|
||||
# find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1
|
||||
# a = create(1)
|
||||
# a.blog_id # => 1
|
||||
@@ -1210,20 +1206,20 @@ module ActiveRecord #:nodoc:
|
||||
# end
|
||||
#
|
||||
# In nested scopings, all previous parameters are overwritten by the innermost rule, with the exception of
|
||||
# <tt>:conditions</tt>, <tt>:include</tt>, and <tt>:joins</tt> options in <tt>:find</tt>, which are merged.
|
||||
# <tt>where</tt>, <tt>includes</tt>, and <tt>joins</tt> operations in <tt>Relation</tt>, which are merged.
|
||||
#
|
||||
# <tt>:joins</tt> options are uniqued so multiple scopes can join in the same table without table aliasing
|
||||
# <tt>joins</tt> operations are uniqued so multiple scopes can join in the same table without table aliasing
|
||||
# problems. If you need to join multiple tables, but still want one of the tables to be uniqued, use the
|
||||
# array of strings format for your joins.
|
||||
#
|
||||
# class Article < ActiveRecord::Base
|
||||
# def self.find_with_scope
|
||||
# with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }, :create => { :blog_id => 1 }) do
|
||||
# with_scope(:find => { :limit => 10 }) do
|
||||
# find(:all) # => SELECT * from articles WHERE blog_id = 1 LIMIT 10
|
||||
# with_scope(:find => where(:blog_id => 1).limit(1), :create => { :blog_id => 1 }) do
|
||||
# with_scope(:find => limit(10)) do
|
||||
# all # => SELECT * from articles WHERE blog_id = 1 LIMIT 10
|
||||
# end
|
||||
# with_scope(:find => { :conditions => "author_id = 3" }) do
|
||||
# find(:all) # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1
|
||||
# with_scope(:find => where(:author_id => 3)) do
|
||||
# all # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
@@ -1233,9 +1229,9 @@ module ActiveRecord #:nodoc:
|
||||
#
|
||||
# class Article < ActiveRecord::Base
|
||||
# def self.find_with_exclusive_scope
|
||||
# with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }) do
|
||||
# with_exclusive_scope(:find => { :limit => 10 })
|
||||
# find(:all) # => SELECT * from articles LIMIT 10
|
||||
# with_scope(:find => where(:blog_id => 1).limit(1)) do
|
||||
# with_exclusive_scope(:find => limit(10))
|
||||
# all # => SELECT * from articles LIMIT 10
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
@@ -1318,9 +1314,9 @@ module ActiveRecord #:nodoc:
|
||||
modularized_name = type_name_with_module(type_name)
|
||||
silence_warnings do
|
||||
begin
|
||||
class_eval(modularized_name, __FILE__, __LINE__)
|
||||
class_eval(modularized_name, __FILE__)
|
||||
rescue NameError
|
||||
class_eval(type_name, __FILE__, __LINE__)
|
||||
class_eval(type_name, __FILE__)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,7 +15,7 @@ module ActiveRecord
|
||||
|
||||
def dirties_query_cache(base, *method_names)
|
||||
method_names.each do |method_name|
|
||||
base.class_eval <<-end_code, __FILE__, __LINE__
|
||||
base.class_eval <<-end_code, __FILE__, __LINE__ + 1
|
||||
def #{method_name}_with_query_dirty(*args) # def update_with_query_dirty(*args)
|
||||
clear_query_cache if @query_cache_enabled # clear_query_cache if @query_cache_enabled
|
||||
#{method_name}_without_query_dirty(*args) # update_without_query_dirty(*args)
|
||||
|
||||
@@ -658,27 +658,6 @@ module ActiveRecord
|
||||
end
|
||||
end
|
||||
|
||||
# Creates a schema for the given user
|
||||
#
|
||||
# Example:
|
||||
# create_schema('products', 'postgres')
|
||||
def create_schema(schema_name, pg_username)
|
||||
execute("CREATE SCHEMA \"#{schema_name}\" AUTHORIZATION \"#{pg_username}\"")
|
||||
end
|
||||
|
||||
# Drops a schema
|
||||
#
|
||||
# Example:
|
||||
# drop_schema('products')
|
||||
def drop_schema(schema_name)
|
||||
execute("DROP SCHEMA \"#{schema_name}\"")
|
||||
end
|
||||
|
||||
# Returns an array of all schemas in the database
|
||||
def all_schemas
|
||||
query('SELECT schema_name FROM information_schema.schemata').flatten
|
||||
end
|
||||
|
||||
# Returns the list of all tables in the schema search path or a specified schema.
|
||||
def tables(name = nil)
|
||||
query(<<-SQL, name).map { |row| row[0] }
|
||||
|
||||
@@ -84,15 +84,9 @@ namespace :db do
|
||||
end
|
||||
end
|
||||
when 'postgresql'
|
||||
@encoding = config['encoding'] || ENV['CHARSET'] || 'utf8'
|
||||
schema_search_path = config['schema_search_path'] || 'public'
|
||||
first_in_schema_search_path = schema_search_path.split(',').first.strip
|
||||
@encoding = config[:encoding] || ENV['CHARSET'] || 'utf8'
|
||||
begin
|
||||
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
|
||||
unless ActiveRecord::Base.connection.all_schemas.include?(first_in_schema_search_path)
|
||||
ActiveRecord::Base.connection.create_schema(first_in_schema_search_path, config['username'])
|
||||
$stderr.puts "Schema #{first_in_schema_search_path} has been created."
|
||||
end
|
||||
ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding))
|
||||
ActiveRecord::Base.establish_connection(config)
|
||||
rescue
|
||||
@@ -452,6 +446,8 @@ namespace :db do
|
||||
end
|
||||
end
|
||||
|
||||
task 'test:prepare' => 'db:test:prepare'
|
||||
|
||||
def drop_database(config)
|
||||
case config['adapter']
|
||||
when 'mysql'
|
||||
|
||||
@@ -3,7 +3,7 @@ module ActiveRecord
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "beta2"
|
||||
BUILD = "beta3"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
end
|
||||
|
||||
@@ -17,13 +17,6 @@ class PostgresqlActiveSchemaTest < Test::Unit::TestCase
|
||||
assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'latin1'), create_database(:aimonetti, :encoding => :latin1)
|
||||
end
|
||||
|
||||
def test_create_schema
|
||||
assert_equal %(CREATE SCHEMA "rizwan" AUTHORIZATION "postgres"), create_schema(:rizwan, :postgres)
|
||||
end
|
||||
|
||||
def test_drop_schema
|
||||
assert_equal %(DROP SCHEMA "rizwan"), drop_schema(:rizwan)
|
||||
end
|
||||
private
|
||||
def method_missing(method_symbol, *arguments)
|
||||
ActiveRecord::Base.connection.send(method_symbol, *arguments)
|
||||
|
||||
@@ -81,12 +81,6 @@ class AdapterTest < ActiveRecord::TestCase
|
||||
def test_encoding
|
||||
assert_not_nil @connection.encoding
|
||||
end
|
||||
|
||||
def test_all_schemas
|
||||
@connection.create_schema(:test_schema, :postgres)
|
||||
assert @connection.all_schemas.include?('test_schema')
|
||||
@connection.drop_schema(:test_schema)
|
||||
end
|
||||
end
|
||||
|
||||
def test_table_alias
|
||||
|
||||
@@ -35,11 +35,11 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
|
||||
def test_belongs_to_with_primary_key_joins_on_correct_column
|
||||
sql = Client.joins(:firm_with_primary_key).to_sql
|
||||
if current_adapter?(:MysqlAdapter)
|
||||
assert_no_match /`firm_with_primary_keys_companies`\.`id`/, sql
|
||||
assert_match /`firm_with_primary_keys_companies`\.`name`/, sql
|
||||
assert_no_match(/`firm_with_primary_keys_companies`\.`id`/, sql)
|
||||
assert_match(/`firm_with_primary_keys_companies`\.`name`/, sql)
|
||||
else
|
||||
assert_no_match /"firm_with_primary_keys_companies"\."id"/, sql
|
||||
assert_match /"firm_with_primary_keys_companies"\."name"/, sql
|
||||
assert_no_match(/"firm_with_primary_keys_companies"\."id"/, sql)
|
||||
assert_match(/"firm_with_primary_keys_companies"\."name"/, sql)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -54,6 +54,89 @@ class DirtyTest < ActiveRecord::TestCase
|
||||
assert_nil pirate.catchphrase_change
|
||||
end
|
||||
|
||||
def test_time_attributes_changes_with_time_zone
|
||||
in_time_zone 'Paris' do
|
||||
target = Class.new(ActiveRecord::Base)
|
||||
target.table_name = 'pirates'
|
||||
|
||||
# New record - no changes.
|
||||
pirate = target.new
|
||||
assert !pirate.created_on_changed?
|
||||
assert_nil pirate.created_on_change
|
||||
|
||||
# Saved - no changes.
|
||||
pirate.catchphrase = 'arrrr, time zone!!'
|
||||
pirate.save!
|
||||
assert !pirate.created_on_changed?
|
||||
assert_nil pirate.created_on_change
|
||||
|
||||
# Change created_on.
|
||||
old_created_on = pirate.created_on
|
||||
pirate.created_on = Time.now - 1.day
|
||||
assert pirate.created_on_changed?
|
||||
assert_kind_of ActiveSupport::TimeWithZone, pirate.created_on_was
|
||||
assert_equal old_created_on, pirate.created_on_was
|
||||
end
|
||||
end
|
||||
|
||||
def test_time_attributes_changes_without_time_zone_by_skip
|
||||
in_time_zone 'Paris' do
|
||||
target = Class.new(ActiveRecord::Base)
|
||||
target.table_name = 'pirates'
|
||||
|
||||
target.skip_time_zone_conversion_for_attributes = [:created_on]
|
||||
|
||||
# New record - no changes.
|
||||
pirate = target.new
|
||||
assert !pirate.created_on_changed?
|
||||
assert_nil pirate.created_on_change
|
||||
|
||||
# Saved - no changes.
|
||||
pirate.catchphrase = 'arrrr, time zone!!'
|
||||
pirate.save!
|
||||
assert !pirate.created_on_changed?
|
||||
assert_nil pirate.created_on_change
|
||||
|
||||
# Change created_on.
|
||||
old_created_on = pirate.created_on
|
||||
pirate.created_on = Time.now + 1.day
|
||||
assert pirate.created_on_changed?
|
||||
# kind_of does not work because
|
||||
# ActiveSupport::TimeWithZone.name == 'Time'
|
||||
assert_equal Time, pirate.created_on_was.class
|
||||
assert_equal old_created_on, pirate.created_on_was
|
||||
end
|
||||
end
|
||||
|
||||
def test_time_attributes_changes_without_time_zone
|
||||
|
||||
target = Class.new(ActiveRecord::Base)
|
||||
target.table_name = 'pirates'
|
||||
|
||||
target.time_zone_aware_attributes = false
|
||||
|
||||
# New record - no changes.
|
||||
pirate = target.new
|
||||
assert !pirate.created_on_changed?
|
||||
assert_nil pirate.created_on_change
|
||||
|
||||
# Saved - no changes.
|
||||
pirate.catchphrase = 'arrrr, time zone!!'
|
||||
pirate.save!
|
||||
assert !pirate.created_on_changed?
|
||||
assert_nil pirate.created_on_change
|
||||
|
||||
# Change created_on.
|
||||
old_created_on = pirate.created_on
|
||||
pirate.created_on = Time.now + 1.day
|
||||
assert pirate.created_on_changed?
|
||||
# kind_of does not work because
|
||||
# ActiveSupport::TimeWithZone.name == 'Time'
|
||||
assert_equal Time, pirate.created_on_was.class
|
||||
assert_equal old_created_on, pirate.created_on_was
|
||||
end
|
||||
|
||||
|
||||
def test_aliased_attribute_changes
|
||||
# the actual attribute here is name, title is an
|
||||
# alias setup via alias_attribute
|
||||
@@ -406,4 +489,16 @@ class DirtyTest < ActiveRecord::TestCase
|
||||
assert_equal %w(parrot_id), pirate.changed
|
||||
assert_nil pirate.parrot_id_was
|
||||
end
|
||||
|
||||
def in_time_zone(zone)
|
||||
old_zone = Time.zone
|
||||
old_tz = ActiveRecord::Base.time_zone_aware_attributes
|
||||
|
||||
Time.zone = zone ? ActiveSupport::TimeZone[zone] : nil
|
||||
ActiveRecord::Base.time_zone_aware_attributes = !zone.nil?
|
||||
yield
|
||||
ensure
|
||||
Time.zone = old_zone
|
||||
ActiveRecord::Base.time_zone_aware_attributes = old_tz
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1136,21 +1136,6 @@ if ActiveRecord::Base.connection.supports_migrations?
|
||||
load(MIGRATIONS_ROOT + "/valid/1_people_have_last_names.rb")
|
||||
end
|
||||
|
||||
def test_migrator_interleaved_migrations
|
||||
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_1")
|
||||
|
||||
assert_nothing_raised do
|
||||
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_2")
|
||||
end
|
||||
|
||||
Person.reset_column_information
|
||||
assert Person.column_methods_hash.include?(:last_name)
|
||||
|
||||
assert_nothing_raised do
|
||||
ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/interleaved/pass_3")
|
||||
end
|
||||
end
|
||||
|
||||
def test_migrator_db_has_no_schema_migrations_table
|
||||
# Oracle adapter raises error if semicolon is present as last character
|
||||
if current_adapter?(:OracleAdapter)
|
||||
@@ -1362,16 +1347,6 @@ if ActiveRecord::Base.connection.supports_migrations?
|
||||
end
|
||||
end
|
||||
|
||||
def test_migration_should_be_run_without_logger
|
||||
previous_logger = ActiveRecord::Base.logger
|
||||
ActiveRecord::Base.logger = nil
|
||||
assert_nothing_raised do
|
||||
ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid")
|
||||
end
|
||||
ensure
|
||||
ActiveRecord::Base.logger = previous_logger
|
||||
end
|
||||
|
||||
protected
|
||||
def with_env_tz(new_tz = 'US/Eastern')
|
||||
old_tz, ENV['TZ'] = ENV['TZ'], new_tz
|
||||
@@ -1457,6 +1432,45 @@ if ActiveRecord::Base.connection.supports_migrations?
|
||||
|
||||
end # SexyMigrationsTest
|
||||
|
||||
class MigrationLoggerTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
Object.send(:remove_const, :InnocentJointable)
|
||||
end
|
||||
|
||||
def test_migration_should_be_run_without_logger
|
||||
previous_logger = ActiveRecord::Base.logger
|
||||
ActiveRecord::Base.logger = nil
|
||||
assert_nothing_raised do
|
||||
ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid")
|
||||
end
|
||||
ensure
|
||||
ActiveRecord::Base.logger = previous_logger
|
||||
end
|
||||
end
|
||||
|
||||
class InterleavedMigrationsTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
Object.send(:remove_const, :PeopleHaveLastNames)
|
||||
end
|
||||
|
||||
def test_migrator_interleaved_migrations
|
||||
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_1")
|
||||
|
||||
assert_nothing_raised do
|
||||
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_2")
|
||||
end
|
||||
|
||||
Person.reset_column_information
|
||||
assert Person.column_methods_hash.include?(:last_name)
|
||||
|
||||
Object.send(:remove_const, :PeopleHaveLastNames)
|
||||
Object.send(:remove_const, :InnocentJointable)
|
||||
assert_nothing_raised do
|
||||
ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/interleaved/pass_3")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ChangeTableMigrationsTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
@connection = Person.connection
|
||||
|
||||
@@ -422,6 +422,16 @@ class NamedScopeTest < ActiveRecord::TestCase
|
||||
post.comments.containing_the_letter_e.all # force load
|
||||
assert_no_queries { post.comments.containing_the_letter_e.all }
|
||||
end
|
||||
|
||||
def test_named_scopes_are_reset_on_association_reload
|
||||
post = posts(:welcome)
|
||||
|
||||
[:destroy_all, :reset, :delete_all].each do |method|
|
||||
before = post.comments.containing_the_letter_e
|
||||
post.comments.send(method)
|
||||
assert before.object_id != post.comments.containing_the_letter_e.object_id, "AssociationCollection##{method} should reset the named scopes cache"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class DynamicScopeMatchTest < ActiveRecord::TestCase
|
||||
|
||||
@@ -130,10 +130,20 @@ class NilXmlSerializationTest < ActiveRecord::TestCase
|
||||
end
|
||||
|
||||
class DatabaseConnectedXmlSerializationTest < ActiveRecord::TestCase
|
||||
fixtures :authors, :posts
|
||||
fixtures :authors, :posts, :projects
|
||||
|
||||
# to_xml used to mess with the hash the user provided which
|
||||
# caused the builder to be reused. This meant the document kept
|
||||
# getting appended to.
|
||||
|
||||
def test_modules
|
||||
projects = MyApplication::Business::Project.all
|
||||
xml = projects.to_xml
|
||||
root = projects.first.class.to_s.underscore.pluralize.tr('/','_').dasherize
|
||||
assert_match "<#{root} type=\"array\">", xml
|
||||
assert_match "</#{root}>", xml
|
||||
end
|
||||
|
||||
def test_passing_hash_shouldnt_reuse_builder
|
||||
options = {:include=>:posts}
|
||||
david = authors(:david)
|
||||
|
||||
@@ -588,11 +588,11 @@ module ActiveResource
|
||||
@prefix_parameters = nil
|
||||
|
||||
# Redefine the new methods.
|
||||
code = <<-end_code
|
||||
code, line = <<-end_code, __LINE__ + 1
|
||||
def prefix_source() "#{value}" end
|
||||
def prefix(options={}) "#{prefix_call}" end
|
||||
end_code
|
||||
silence_warnings { instance_eval code, __FILE__, __LINE__ }
|
||||
silence_warnings { instance_eval code, __FILE__, line }
|
||||
rescue
|
||||
logger.error "Couldn't set prefix: #{$!}\n #{code}" if logger
|
||||
raise
|
||||
|
||||
@@ -57,7 +57,7 @@ module ActiveResource
|
||||
# def post(path, request_headers = {}, body = nil, status = 200, response_headers = {})
|
||||
# @responses[Request.new(:post, path, nil, request_headers)] = Response.new(body || "", status, response_headers)
|
||||
# end
|
||||
module_eval <<-EOE, __FILE__, __LINE__
|
||||
module_eval <<-EOE, __FILE__, __LINE__ + 1
|
||||
def #{method}(path, request_headers = {}, body = nil, status = 200, response_headers = {})
|
||||
@responses << [Request.new(:#{method}, path, nil, request_headers), Response.new(body || "", status, response_headers)]
|
||||
end
|
||||
@@ -125,7 +125,7 @@ module ActiveResource
|
||||
# self.class.requests << request
|
||||
# self.class.responses.assoc(request).try(:second) || raise(InvalidRequestError.new("No response recorded for #{request}"))
|
||||
# end
|
||||
module_eval <<-EOE, __FILE__, __LINE__
|
||||
module_eval <<-EOE, __FILE__, __LINE__ + 1
|
||||
def #{method}(path, #{'body, ' if has_body}headers)
|
||||
request = ActiveResource::Request.new(:#{method}, path, #{has_body ? 'body, ' : 'nil, '}headers)
|
||||
self.class.requests << request
|
||||
|
||||
@@ -3,7 +3,7 @@ module ActiveResource
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "beta2"
|
||||
BUILD = "beta3"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
end
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
*Rails 3.0.0 [beta 3] (pending)*
|
||||
|
||||
* Speed up and add Ruby 1.9 support for ActiveSupport::Multibyte::Chars#tidy_bytes. #4350 [Norman Clarke]
|
||||
|
||||
|
||||
*Rails 3.0.0 [beta 2] (April 1st, 2010)*
|
||||
|
||||
* Reduced load time by deferring configuration of classes using
|
||||
|
||||
@@ -4,7 +4,9 @@ module ActiveSupport
|
||||
# context, so only the relevant lines are included.
|
||||
#
|
||||
# If you need to reconfigure an existing BacktraceCleaner, like the one in Rails, to show as much as possible, you can always
|
||||
# call BacktraceCleaner#remove_silencers!
|
||||
# call BacktraceCleaner#remove_silencers! Also, if you need to reconfigure an existing BacktraceCleaner so that it does not
|
||||
# filter or modify the paths of any lines of the backtrace, you can call BacktraceCleaner#remove_filters! These two methods
|
||||
# will give you a completely untouched backtrace.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
@@ -60,6 +62,10 @@ module ActiveSupport
|
||||
@silencers = []
|
||||
end
|
||||
|
||||
def remove_filters!
|
||||
@filters = []
|
||||
end
|
||||
|
||||
private
|
||||
def filter(backtrace)
|
||||
@filters.each do |f|
|
||||
|
||||
@@ -64,7 +64,7 @@ module ActiveSupport
|
||||
@data.get(key, raw?(options))
|
||||
end
|
||||
rescue MemCache::MemCacheError => e
|
||||
logger.error("MemCacheError (#{e}): #{e.message}")
|
||||
logger.error("MemCacheError (#{e}): #{e.message}") if logger
|
||||
nil
|
||||
end
|
||||
|
||||
@@ -85,7 +85,7 @@ module ActiveSupport
|
||||
response == Response::STORED
|
||||
end
|
||||
rescue MemCache::MemCacheError => e
|
||||
logger.error("MemCacheError (#{e}): #{e.message}")
|
||||
logger.error("MemCacheError (#{e}): #{e.message}") if logger
|
||||
false
|
||||
end
|
||||
|
||||
@@ -95,7 +95,7 @@ module ActiveSupport
|
||||
response == Response::DELETED
|
||||
end
|
||||
rescue MemCache::MemCacheError => e
|
||||
logger.error("MemCacheError (#{e}): #{e.message}")
|
||||
logger.error("MemCacheError (#{e}): #{e.message}") if logger
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ module ActiveSupport
|
||||
def middleware
|
||||
@middleware ||= begin
|
||||
klass = Class.new
|
||||
klass.class_eval(<<-EOS, __FILE__, __LINE__)
|
||||
klass.class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
@@ -387,7 +387,7 @@ module ActiveSupport
|
||||
send("_update_#{symbol}_superclass_callbacks")
|
||||
body = send("_#{symbol}_callbacks").compile(nil)
|
||||
|
||||
body, line = <<-RUBY_EVAL, __LINE__
|
||||
body, line = <<-RUBY_EVAL, __LINE__ + 1
|
||||
def _run_#{symbol}_callbacks(key = nil, &blk)
|
||||
if self.class.send("_update_#{symbol}_superclass_callbacks")
|
||||
self.class.__define_runner(#{symbol.inspect})
|
||||
|
||||
@@ -131,7 +131,7 @@ class Array
|
||||
require 'builder' unless defined?(Builder)
|
||||
|
||||
options = options.dup
|
||||
options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? ActiveSupport::Inflector.pluralize(ActiveSupport::Inflector.underscore(first.class.name)) : "records"
|
||||
options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? ActiveSupport::Inflector.pluralize(ActiveSupport::Inflector.underscore(first.class.name)).tr('/', '_') : "records"
|
||||
options[:children] ||= options[:root].singularize
|
||||
options[:indent] ||= 2
|
||||
options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
||||
|
||||
@@ -61,7 +61,7 @@ class Module
|
||||
# e.subject = "Megastars"
|
||||
# e.title # => "Megastars"
|
||||
def alias_attribute(new_name, old_name)
|
||||
module_eval <<-STR, __FILE__, __LINE__+1
|
||||
module_eval <<-STR, __FILE__, __LINE__ + 1
|
||||
def #{new_name}; self.#{old_name}; end # def subject; self.title; end
|
||||
def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end
|
||||
def #{new_name}=(v); self.#{old_name} = v; end # def subject=(v); self.title = v; end
|
||||
|
||||
@@ -21,7 +21,7 @@ class Module
|
||||
def attr_accessor_with_default(sym, default = nil, &block)
|
||||
raise 'Default value or block required' unless !default.nil? || block
|
||||
define_method(sym, block_given? ? block : Proc.new { default })
|
||||
module_eval(<<-EVAL, __FILE__, __LINE__)
|
||||
module_eval(<<-EVAL, __FILE__, __LINE__ + 1)
|
||||
def #{sym}=(value) # def age=(value)
|
||||
class << self; attr_reader :#{sym} end # class << self; attr_reader :age end
|
||||
@#{sym} = value # @age = value
|
||||
|
||||
@@ -126,7 +126,7 @@ class Module
|
||||
%(raise "#{self}##{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
|
||||
end
|
||||
|
||||
module_eval(<<-EOS, file, line)
|
||||
module_eval(<<-EOS, file, line - 5)
|
||||
if instance_methods(false).map(&:to_s).include?("#{prefix}#{method}")
|
||||
remove_possible_method("#{prefix}#{method}")
|
||||
end
|
||||
|
||||
@@ -28,7 +28,7 @@ class Module
|
||||
raise ArgumentError, "#{method} is already synchronized. Double synchronization is not currently supported."
|
||||
end
|
||||
|
||||
module_eval(<<-EOS, __FILE__, __LINE__)
|
||||
module_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
||||
def #{aliased_method}_with_synchronization#{punctuation}(*args, &block) # def expire_with_synchronization(*args, &block)
|
||||
#{with}.synchronize do # @@lock.synchronize do
|
||||
#{aliased_method}_without_synchronization#{punctuation}(*args, &block) # expire_without_synchronization(*args, &block)
|
||||
|
||||
@@ -19,7 +19,7 @@ module ActiveSupport #:nodoc:
|
||||
# bad.explicit_checking_method "T".mb_chars.downcase.to_s
|
||||
#
|
||||
# The default Chars implementation assumes that the encoding of the string is UTF-8, if you want to handle different
|
||||
# encodings you can write your own multibyte string handler and configure it through
|
||||
# encodings you can write your own multibyte string handler and configure it through
|
||||
# ActiveSupport::Multibyte.proxy_class.
|
||||
#
|
||||
# class CharsForUTF32
|
||||
@@ -458,8 +458,10 @@ module ActiveSupport #:nodoc:
|
||||
end
|
||||
|
||||
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent resulting in a valid UTF-8 string.
|
||||
def tidy_bytes
|
||||
chars(self.class.tidy_bytes(@wrapped_string))
|
||||
#
|
||||
# Passing +true+ will forcibly tidy all bytes, assuming that the string's encoding is entirely CP1252 or ISO-8859-1.
|
||||
def tidy_bytes(force = false)
|
||||
chars(self.class.tidy_bytes(@wrapped_string, force))
|
||||
end
|
||||
|
||||
%w(lstrip rstrip strip reverse upcase downcase tidy_bytes capitalize).each do |method|
|
||||
@@ -528,7 +530,7 @@ module ActiveSupport #:nodoc:
|
||||
unpacked << codepoints[marker..pos-1]
|
||||
marker = pos
|
||||
end
|
||||
end
|
||||
end
|
||||
unpacked
|
||||
end
|
||||
|
||||
@@ -644,33 +646,80 @@ module ActiveSupport #:nodoc:
|
||||
codepoints
|
||||
end
|
||||
|
||||
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent resulting in a valid UTF-8 string.
|
||||
def tidy_bytes(string)
|
||||
string.split(//u).map do |c|
|
||||
c.force_encoding(Encoding::ASCII) if c.respond_to?(:force_encoding)
|
||||
def tidy_byte(byte)
|
||||
if byte < 160
|
||||
[UCD.cp1252[byte] || byte].pack("U").unpack("C*")
|
||||
elsif byte < 192
|
||||
[194, byte]
|
||||
else
|
||||
[195, byte - 64]
|
||||
end
|
||||
end
|
||||
private :tidy_byte
|
||||
|
||||
if !ActiveSupport::Multibyte::VALID_CHARACTER['UTF-8'].match(c)
|
||||
n = c.unpack('C')[0]
|
||||
n < 128 ? n.chr :
|
||||
n < 160 ? [UCD.cp1252[n] || n].pack('U') :
|
||||
n < 192 ? "\xC2" + n.chr : "\xC3" + (n-64).chr
|
||||
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent resulting in a valid UTF-8 string.
|
||||
#
|
||||
# Passing +true+ will forcibly tidy all bytes, assuming that the string's encoding is entirely CP-1252 or ISO-8859-1.
|
||||
def tidy_bytes(string, force = false)
|
||||
if force
|
||||
return string.unpack("C*").map do |b|
|
||||
tidy_byte(b)
|
||||
end.flatten.compact.pack("C*").unpack("U*").pack("U*")
|
||||
end
|
||||
|
||||
bytes = string.unpack("C*")
|
||||
conts_expected = 0
|
||||
last_lead = 0
|
||||
|
||||
bytes.each_index do |i|
|
||||
|
||||
byte = bytes[i]
|
||||
is_ascii = byte < 128
|
||||
is_cont = byte > 127 && byte < 192
|
||||
is_lead = byte > 191 && byte < 245
|
||||
is_unused = byte > 240
|
||||
is_restricted = byte > 244
|
||||
|
||||
# Impossible or highly unlikely byte? Clean it.
|
||||
if is_unused || is_restricted
|
||||
bytes[i] = tidy_byte(byte)
|
||||
elsif is_cont
|
||||
# Not expecting contination byte? Clean up. Otherwise, now expect one less.
|
||||
conts_expected == 0 ? bytes[i] = tidy_byte(byte) : conts_expected -= 1
|
||||
else
|
||||
c
|
||||
if conts_expected > 0
|
||||
# Expected continuation, but got ASCII or leading? Clean backwards up to
|
||||
# the leading byte.
|
||||
(1..(i - last_lead)).each {|j| bytes[i - j] = tidy_byte(bytes[i - j])}
|
||||
conts_expected = 0
|
||||
end
|
||||
if is_lead
|
||||
# Final byte is leading? Clean it.
|
||||
if i == bytes.length - 1
|
||||
bytes[i] = tidy_byte(bytes.last)
|
||||
else
|
||||
# Valid leading byte? Expect continuations determined by position of
|
||||
# first zero bit, with max of 3.
|
||||
conts_expected = byte < 224 ? 1 : byte < 240 ? 2 : 3
|
||||
last_lead = i
|
||||
end
|
||||
end
|
||||
end
|
||||
end.join
|
||||
end
|
||||
bytes.empty? ? "" : bytes.flatten.compact.pack("C*").unpack("U*").pack("U*")
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
|
||||
def translate_offset(byte_offset) #:nodoc:
|
||||
return nil if byte_offset.nil?
|
||||
return 0 if @wrapped_string == ''
|
||||
|
||||
|
||||
if @wrapped_string.respond_to?(:force_encoding)
|
||||
@wrapped_string = @wrapped_string.dup.force_encoding(Encoding::ASCII_8BIT)
|
||||
end
|
||||
|
||||
|
||||
begin
|
||||
@wrapped_string[0...byte_offset].unpack('U*').length
|
||||
rescue ArgumentError => e
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
require 'yaml'
|
||||
|
||||
YAML.add_builtin_type("omap") do |type, val|
|
||||
ActiveSupport::OrderedHash[val.map(&:to_a).map(&:first)]
|
||||
end
|
||||
|
||||
# OrderedHash is namespaced to prevent conflicts with other implementations
|
||||
module ActiveSupport
|
||||
# Hash is ordered in Ruby 1.9!
|
||||
if RUBY_VERSION >= '1.9'
|
||||
class OrderedHash < ::Hash #:nodoc:
|
||||
class OrderedHash < ::Hash #:nodoc:
|
||||
def to_yaml_type
|
||||
"!tag:yaml.org,2002:omap"
|
||||
end
|
||||
else
|
||||
class OrderedHash < Hash #:nodoc:
|
||||
|
||||
def to_yaml(opts = {})
|
||||
YAML.quick_emit(self, opts) do |out|
|
||||
out.seq(taguri, to_yaml_style) do |seq|
|
||||
each do |k, v|
|
||||
seq.add(k => v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Hash is ordered in Ruby 1.9!
|
||||
if RUBY_VERSION < '1.9'
|
||||
def initialize(*args, &block)
|
||||
super
|
||||
@keys = []
|
||||
@@ -55,7 +70,7 @@ module ActiveSupport
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
|
||||
def delete_if
|
||||
super
|
||||
sync_keys!
|
||||
@@ -134,31 +149,10 @@ module ActiveSupport
|
||||
"#<OrderedHash #{super}>"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sync_keys!
|
||||
@keys.delete_if {|k| !has_key?(k)}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class OrderedHash #:nodoc:
|
||||
def to_yaml_type
|
||||
"!tag:yaml.org,2002:omap"
|
||||
end
|
||||
|
||||
def to_yaml(opts = {})
|
||||
YAML.quick_emit(self, opts) do |out|
|
||||
out.seq(taguri, to_yaml_style) do |seq|
|
||||
each do |k, v|
|
||||
seq.add(k => v)
|
||||
end
|
||||
private
|
||||
def sync_keys!
|
||||
@keys.delete_if {|k| !has_key?(k)}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
YAML.add_builtin_type("omap") do |type, val|
|
||||
ActiveSupport::OrderedHash[val.map(&:to_a).map(&:first)]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,7 +3,7 @@ module ActiveSupport
|
||||
MAJOR = 3
|
||||
MINOR = 0
|
||||
TINY = 0
|
||||
BUILD = "beta2"
|
||||
BUILD = "beta3"
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
|
||||
end
|
||||
|
||||
@@ -9,6 +9,11 @@ class BacktraceCleanerFilterTest < ActiveSupport::TestCase
|
||||
test "backtrace should not contain prefix when it has been filtered out" do
|
||||
assert_equal "/my/class.rb", @bc.clean([ "/my/prefix/my/class.rb" ]).first
|
||||
end
|
||||
|
||||
test "backtrace cleaner should allow removing filters" do
|
||||
@bc.remove_filters!
|
||||
assert_equal "/my/prefix/my/class.rb", @bc.clean(["/my/prefix/my/class.rb"]).first
|
||||
end
|
||||
|
||||
test "backtrace should contain unaltered lines if they dont match a filter" do
|
||||
assert_equal "/my/other_prefix/my/class.rb", @bc.clean([ "/my/other_prefix/my/class.rb" ]).first
|
||||
@@ -44,4 +49,4 @@ class BacktraceCleanerFilterAndSilencerTest < ActiveSupport::TestCase
|
||||
test "backtrace should not silence lines that has first had their silence hook filtered out" do
|
||||
assert_equal [ "/class.rb" ], @bc.clean([ "/mongrel/class.rb" ])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -107,7 +107,7 @@ class MultibyteCharsUTF8BehaviourTest < Test::Unit::TestCase
|
||||
# Ruby 1.9 only supports basic whitespace
|
||||
@whitespace = "\n\t ".force_encoding(Encoding::UTF_8)
|
||||
end
|
||||
|
||||
|
||||
@byte_order_mark = [65279].pack('U')
|
||||
end
|
||||
|
||||
@@ -468,14 +468,6 @@ end
|
||||
class MultibyteCharsExtrasTest < Test::Unit::TestCase
|
||||
include MultibyteTestHelpers
|
||||
|
||||
if RUBY_VERSION >= '1.9'
|
||||
def test_tidy_bytes_is_broken_on_1_9_0
|
||||
assert_raise(ArgumentError) do
|
||||
assert_equal_codepoints [0xfffd].pack('U'), chars("\xef\xbf\xbd").tidy_bytes
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_upcase_should_be_unicode_aware
|
||||
assert_equal "АБВГД\0F", chars("аБвгд\0f").upcase
|
||||
assert_equal 'こにちわ', chars('こにちわ').upcase
|
||||
@@ -504,7 +496,7 @@ class MultibyteCharsExtrasTest < Test::Unit::TestCase
|
||||
def test_limit_should_work_on_a_multibyte_string
|
||||
example = chars(UNICODE_STRING)
|
||||
bytesize = UNICODE_STRING.respond_to?(:bytesize) ? UNICODE_STRING.bytesize : UNICODE_STRING.size
|
||||
|
||||
|
||||
assert_equal UNICODE_STRING, example.limit(bytesize)
|
||||
assert_equal '', example.limit(0)
|
||||
assert_equal '', example.limit(1)
|
||||
@@ -531,7 +523,7 @@ class MultibyteCharsExtrasTest < Test::Unit::TestCase
|
||||
assert example.limit(limit).to_s.length <= limit
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def test_composition_exclusion_is_set_up_properly
|
||||
# Normalization of DEVANAGARI LETTER QA breaks when composition exclusion isn't used correctly
|
||||
qa = [0x915, 0x93c].pack('U*')
|
||||
@@ -607,28 +599,57 @@ class MultibyteCharsExtrasTest < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
def test_tidy_bytes_should_tidy_bytes
|
||||
|
||||
single_byte_cases = {
|
||||
"\x21" => "!", # Valid ASCII byte, low
|
||||
"\x41" => "A", # Valid ASCII byte, mid
|
||||
"\x7E" => "~", # Valid ASCII byte, high
|
||||
"\x80" => "€", # Continuation byte, low (cp125)
|
||||
"\x94" => "”", # Continuation byte, mid (cp125)
|
||||
"\x9F" => "Ÿ", # Continuation byte, high (cp125)
|
||||
"\xC0" => "À", # Overlong encoding, start of 2-byte sequence, but codepoint < 128
|
||||
"\xC1" => "Á", # Overlong encoding, start of 2-byte sequence, but codepoint < 128
|
||||
"\xC2" => "Â", # Start of 2-byte sequence, low
|
||||
"\xC8" => "È", # Start of 2-byte sequence, mid
|
||||
"\xDF" => "ß", # Start of 2-byte sequence, high
|
||||
"\xE0" => "à", # Start of 3-byte sequence, low
|
||||
"\xE8" => "è", # Start of 3-byte sequence, mid
|
||||
"\xEF" => "ï", # Start of 3-byte sequence, high
|
||||
"\xF0" => "ð", # Start of 4-byte sequence
|
||||
"\xF1" => "ñ", # Unused byte
|
||||
"\xFF" => "ÿ", # Restricted byte
|
||||
"\x00" => "\x00" # null char
|
||||
}
|
||||
|
||||
single_byte_cases.each do |bad, good|
|
||||
assert_equal good, chars(bad).tidy_bytes.to_s
|
||||
assert_equal "#{good}#{good}", chars("#{bad}#{bad}").tidy_bytes
|
||||
assert_equal "#{good}#{good}#{good}", chars("#{bad}#{bad}#{bad}").tidy_bytes
|
||||
assert_equal "#{good}a", chars("#{bad}a").tidy_bytes
|
||||
assert_equal "#{good}á", chars("#{bad}á").tidy_bytes
|
||||
assert_equal "a#{good}a", chars("a#{bad}a").tidy_bytes
|
||||
assert_equal "á#{good}á", chars("á#{bad}á").tidy_bytes
|
||||
assert_equal "a#{good}", chars("a#{bad}").tidy_bytes
|
||||
assert_equal "á#{good}", chars("á#{bad}").tidy_bytes
|
||||
end
|
||||
|
||||
byte_string = "\270\236\010\210\245"
|
||||
tidy_string = [0xb8, 0x17e, 0x8, 0x2c6, 0xa5].pack('U*')
|
||||
ascii_padding = 'aa'
|
||||
utf8_padding = 'éé'
|
||||
|
||||
assert_equal_codepoints tidy_string, chars(byte_string).tidy_bytes
|
||||
|
||||
assert_equal_codepoints ascii_padding.dup.insert(1, tidy_string),
|
||||
chars(ascii_padding.dup.insert(1, byte_string)).tidy_bytes
|
||||
assert_equal_codepoints utf8_padding.dup.insert(2, tidy_string),
|
||||
chars(utf8_padding.dup.insert(2, byte_string)).tidy_bytes
|
||||
assert_nothing_raised { chars(byte_string).tidy_bytes.to_s.unpack('U*') }
|
||||
|
||||
assert_equal_codepoints "\xC3\xA7", chars("\xE7").tidy_bytes # iso_8859_1: small c cedilla
|
||||
assert_equal_codepoints "\xE2\x80\x9C", chars("\x93").tidy_bytes # win_1252: left smart quote
|
||||
assert_equal_codepoints "\xE2\x82\xAC", chars("\x80").tidy_bytes # win_1252: euro
|
||||
assert_equal_codepoints "\x00", chars("\x00").tidy_bytes # null char
|
||||
assert_equal_codepoints [0xfffd].pack('U'), chars("\xef\xbf\xbd").tidy_bytes # invalid char
|
||||
rescue ArgumentError => e
|
||||
raise e if RUBY_VERSION < '1.9'
|
||||
# UTF-8 leading byte followed by too few continuation bytes
|
||||
assert_equal_codepoints "\xc3\xb0\xc2\xa5\xc2\xa4\x21", chars("\xf0\xa5\xa4\x21").tidy_bytes
|
||||
end
|
||||
|
||||
def test_tidy_bytes_should_forcibly_tidy_bytes_if_specified
|
||||
byte_string = "\xF0\xA5\xA4\xA4" # valid as both CP-1252 and UTF-8, but with different interpretations.
|
||||
assert_not_equal "𥤤", chars(byte_string).tidy_bytes
|
||||
# Forcible conversion to UTF-8
|
||||
assert_equal "𥤤", chars(byte_string).tidy_bytes(true)
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def string_from_classes(classes)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
* A new application now comes with a layout and a stylesheet. [JV]
|
||||
|
||||
* Renamed config.cookie_secret to config.secret_token and pass it as env key. [JV]
|
||||
|
||||
*Rails 3.0.0 [beta 2] (April 1st, 2010)*
|
||||
|
||||
@@ -437,7 +437,7 @@ div.code_container, div.important, div.caution, div.warning, div.note, div.info
|
||||
/* Remove bottom margin of paragraphs in special boxes, otherwise they get a
|
||||
spurious blank area below with the box background. */
|
||||
div.important p, div.caution p, div.warning p, div.note p, div.info p {
|
||||
margin-bottom: 0px;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
/* Edge Badge
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -79,6 +79,10 @@ module Rails
|
||||
@_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development")
|
||||
end
|
||||
|
||||
def env=(environment)
|
||||
@_env = ActiveSupport::StringInquirer.new(environment)
|
||||
end
|
||||
|
||||
def cache
|
||||
RAILS_CACHE
|
||||
end
|
||||
@@ -88,11 +92,12 @@ module Rails
|
||||
end
|
||||
|
||||
def public_path
|
||||
@@public_path ||= self.root ? File.join(self.root, "public") : "public"
|
||||
application && application.paths.public.to_a.first
|
||||
end
|
||||
|
||||
def public_path=(path)
|
||||
@@public_path = path
|
||||
ActiveSupport::Deprecation.warn "Setting Rails.public_path= is deprecated. " <<
|
||||
"Please set paths.public = in config/application.rb instead.", caller
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,21 +6,29 @@ module Rails
|
||||
include ::Rails::Configuration::Deprecated
|
||||
|
||||
attr_accessor :allow_concurrency, :cache_classes, :cache_store,
|
||||
:secret_token, :consider_all_requests_local, :dependency_loading,
|
||||
:encoding, :consider_all_requests_local, :dependency_loading,
|
||||
:filter_parameters, :log_level, :logger, :metals,
|
||||
:plugins, :preload_frameworks, :reload_engines, :reload_plugins,
|
||||
:serve_static_assets, :time_zone, :whiny_nils
|
||||
:secret_token, :serve_static_assets, :time_zone, :whiny_nils
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
@allow_concurrency = false
|
||||
@filter_parameters = []
|
||||
@dependency_loading = true
|
||||
@allow_concurrency = false
|
||||
@consider_all_requests_local = false
|
||||
@encoding = "utf-8"
|
||||
@filter_parameters = []
|
||||
@dependency_loading = true
|
||||
@serve_static_assets = true
|
||||
@time_zone = "UTC"
|
||||
@consider_all_requests_local = true
|
||||
@session_store = :cookie_store
|
||||
@session_options = {}
|
||||
@time_zone = "UTC"
|
||||
end
|
||||
|
||||
def encoding=(value)
|
||||
@encoding = value
|
||||
if defined?(Encoding) && Encoding.respond_to?(:default_external=)
|
||||
Encoding.default_external = value
|
||||
end
|
||||
end
|
||||
|
||||
def middleware
|
||||
@@ -129,7 +137,7 @@ module Rails
|
||||
|
||||
def default_middleware_stack
|
||||
ActionDispatch::MiddlewareStack.new.tap do |middleware|
|
||||
middleware.use('::ActionDispatch::Static', lambda { Rails.public_path }, :if => lambda { serve_static_assets })
|
||||
middleware.use('::ActionDispatch::Static', lambda { paths.public.to_a.first }, :if => lambda { serve_static_assets })
|
||||
middleware.use('::Rack::Lock', :if => lambda { !allow_concurrency })
|
||||
middleware.use('::Rack::Runtime')
|
||||
middleware.use('::Rails::Rack::Logger')
|
||||
|
||||
@@ -43,7 +43,7 @@ module Rails
|
||||
end
|
||||
|
||||
def load_once_paths
|
||||
@eager_load_paths ||= paths.load_once
|
||||
@load_once_paths ||= paths.load_once
|
||||
end
|
||||
|
||||
def load_paths
|
||||
|
||||
@@ -26,6 +26,7 @@ module Rails
|
||||
:orm => '-o',
|
||||
:resource_controller => '-c',
|
||||
:scaffold_controller => '-c',
|
||||
:stylesheets => '-y',
|
||||
:template_engine => '-e',
|
||||
:test_framework => '-t'
|
||||
},
|
||||
@@ -50,6 +51,7 @@ module Rails
|
||||
:resource_controller => :controller,
|
||||
:scaffold_controller => :scaffold_controller,
|
||||
:singleton => false,
|
||||
:stylesheets => true,
|
||||
:test_framework => nil,
|
||||
:template_engine => :erb
|
||||
},
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
<%%= form_for(@<%= singular_name %>) do |f| %>
|
||||
<%%= f.error_messages %>
|
||||
<%% if @<%= singular_name %>.errors.any? %>
|
||||
<div id="errorExplanation">
|
||||
<h2><%%= pluralize(@<%= singular_name %>.errors.count, "error") %> prohibited this <%= singular_name %> from being saved:</h2>
|
||||
<ul>
|
||||
<%% @<%= singular_name %>.errors.full_messages.each do |msg| %>
|
||||
<li><%%= msg %></li>
|
||||
<%% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<%% end %>
|
||||
|
||||
<% for attribute in attributes -%>
|
||||
<div class="field">
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<p class="notice"><%%= notice %></p>
|
||||
|
||||
<% for attribute in attributes -%>
|
||||
<p>
|
||||
<b><%= attribute.human_name %>:</b>
|
||||
|
||||
@@ -78,7 +78,7 @@ module Rails::Generators
|
||||
end
|
||||
|
||||
def create_app_files
|
||||
directory "app"
|
||||
directory 'app'
|
||||
end
|
||||
|
||||
def create_config_files
|
||||
@@ -137,7 +137,7 @@ module Rails::Generators
|
||||
end
|
||||
|
||||
def create_public_stylesheets_files
|
||||
directory "public/stylesheets"
|
||||
empty_directory_with_gitkeep "public/stylesheets"
|
||||
end
|
||||
|
||||
def create_prototype_files
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><%= controller_name.humanize %>: <%= action_name %></title>
|
||||
<%= stylesheet_link_tag 'application' %>
|
||||
<%= javascript_include_tag :defaults %>
|
||||
<%= csrf_meta_tag %>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p class="notice"><%= notice %></p>
|
||||
<p class="alert"><%= alert %></p>
|
||||
|
||||
<%=raw yield %>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><%= app_const_base %></title>
|
||||
<%%= stylesheet_link_tag :all %>
|
||||
<%%= javascript_include_tag :defaults %>
|
||||
<%%= csrf_meta_tag %>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<%%= yield %>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -46,7 +46,10 @@ module <%= app_const_base %>
|
||||
# g.test_framework :test_unit, :fixture => true
|
||||
# end
|
||||
|
||||
# Configure the default encoding used in templates for Ruby 1.9.
|
||||
config.encoding = "utf-8"
|
||||
|
||||
# Configure sensitive parameters which will be filtered from the log file.
|
||||
config.filter_parameters << :password
|
||||
config.filter_parameters += [:password]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
document.observe("dom:loaded", function() {
|
||||
var authToken = $$('meta[name=csrf-token]').first().readAttribute('content'),
|
||||
authParam = $$('meta[name=csrf-param]').first().readAttribute('content'),
|
||||
formTemplate = '<form method="#{method}" action="#{action}">\
|
||||
#{realmethod}<input name="#{param}" value="#{token}" type="hidden">\
|
||||
</form>',
|
||||
realmethodTemplate = '<input name="_method" value="#{method}" type="hidden">';
|
||||
|
||||
function handleRemote(element) {
|
||||
var method, url, params;
|
||||
|
||||
if (element.tagName.toLowerCase() == 'form') {
|
||||
if (element.tagName.toLowerCase() === 'form') {
|
||||
method = element.readAttribute('method') || 'post';
|
||||
url = element.readAttribute('action');
|
||||
params = element.serialize(true);
|
||||
@@ -39,65 +32,81 @@ document.observe("dom:loaded", function() {
|
||||
element.fire("ajax:after");
|
||||
}
|
||||
|
||||
function handleMethod(element) {
|
||||
var method, url, token_name, token;
|
||||
|
||||
method = element.readAttribute('data-method');
|
||||
url = element.readAttribute('href');
|
||||
csrf_param = $$('meta[name=csrf-param]').first();
|
||||
csrf_token = $$('meta[name=csrf-token]').first();
|
||||
|
||||
var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
|
||||
element.parentNode.appendChild(form);
|
||||
|
||||
if (method != 'post') {
|
||||
var field = new Element('input', { type: 'hidden', name: '_method', value: method });
|
||||
form.appendChild(field);
|
||||
}
|
||||
|
||||
if (csrf_param) {
|
||||
var param = csrf_param.readAttribute('content');
|
||||
var token = csrf_token.readAttribute('content');
|
||||
var field = new Element('input', { type: 'hidden', name: param, value: token });
|
||||
form.appendChild(field);
|
||||
}
|
||||
|
||||
form.submit();
|
||||
}
|
||||
|
||||
$(document.body).observe("click", function(event) {
|
||||
var message = event.element().readAttribute('data-confirm');
|
||||
var message = event.findElement().readAttribute('data-confirm');
|
||||
if (message && !confirm(message)) {
|
||||
event.stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
var element = event.findElement("a[data-remote=true]");
|
||||
var element = event.findElement("a[data-remote]");
|
||||
if (element) {
|
||||
handleRemote(element);
|
||||
event.stop();
|
||||
return true;
|
||||
}
|
||||
|
||||
var element = event.findElement("a[data-method]");
|
||||
if (element && element.readAttribute('data-remote') != 'true') {
|
||||
var method = element.readAttribute('data-method'),
|
||||
piggyback = method.toLowerCase() != 'post',
|
||||
formHTML = formTemplate.interpolate({
|
||||
method: 'POST',
|
||||
realmethod: piggyback ? realmethodTemplate.interpolate({ method: method }) : '',
|
||||
action: element.readAttribute('href'),
|
||||
token: authToken,
|
||||
param: authParam
|
||||
});
|
||||
|
||||
var form = new Element('div').update(formHTML).down().hide();
|
||||
this.insert({ bottom: form });
|
||||
|
||||
form.submit();
|
||||
if (element) {
|
||||
handleMethod(element);
|
||||
event.stop();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: I don't think submit bubbles in IE
|
||||
$(document.body).observe("submit", function(event) {
|
||||
var message = event.element().readAttribute('data-confirm');
|
||||
var element = event.findElement(),
|
||||
message = element.readAttribute('data-confirm');
|
||||
if (message && !confirm(message)) {
|
||||
event.stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
var inputs = event.element().select("input[type=submit][data-disable-with]");
|
||||
var inputs = element.select("input[type=submit][data-disable-with]");
|
||||
inputs.each(function(input) {
|
||||
input.disabled = true;
|
||||
input.writeAttribute('data-original-value', input.value);
|
||||
input.value = input.readAttribute('data-disable-with');
|
||||
});
|
||||
|
||||
var element = event.findElement("form[data-remote=true]");
|
||||
var element = event.findElement("form[data-remote]");
|
||||
if (element) {
|
||||
handleRemote(element);
|
||||
event.stop();
|
||||
}
|
||||
});
|
||||
|
||||
$(document.body).observe("ajax:complete", function(event) {
|
||||
var element = event.element();
|
||||
$(document.body).observe("ajax:after", function(event) {
|
||||
var element = event.findElement();
|
||||
|
||||
if (element.tagName.toLowerCase() == 'form') {
|
||||
if (element.tagName.toLowerCase() === 'form') {
|
||||
var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
|
||||
inputs.each(function(input) {
|
||||
input.value = input.readAttribute('data-original-value');
|
||||
@@ -106,4 +115,4 @@ document.observe("dom:loaded", function() {
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,11 +3,13 @@ require File.expand_path('../../config/environment', __FILE__)
|
||||
require 'rails/test_help'
|
||||
|
||||
class ActiveSupport::TestCase
|
||||
<% unless options[:skip_activerecord] -%>
|
||||
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
|
||||
#
|
||||
# Note: You'll currently still have to declare fixtures explicitly in integration tests
|
||||
# -- they do not yet inherit this setting
|
||||
fixtures :all
|
||||
|
||||
<% end -%>
|
||||
# Add more helper methods to be used by all tests here...
|
||||
end
|
||||
@@ -7,6 +7,7 @@ module Rails
|
||||
remove_class_option :actions
|
||||
|
||||
hook_for :scaffold_controller, :required => true
|
||||
hook_for :stylesheets
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
5
railties/lib/rails/generators/rails/stylesheets/USAGE
Normal file
5
railties/lib/rails/generators/rails/stylesheets/USAGE
Normal file
@@ -0,0 +1,5 @@
|
||||
Description:
|
||||
Copies scaffold stylesheets to public/stylesheets/.
|
||||
|
||||
Examples:
|
||||
`rails generate stylesheets`
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user