mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Merge branch 'master' of github.com:rails/rails
This commit is contained in:
@@ -253,7 +253,7 @@ module ActionMailer #:nodoc:
|
||||
class Base
|
||||
include AdvAttrAccessor, PartContainer, Quoting, Utils
|
||||
|
||||
include AbstractController::RenderingController
|
||||
include AbstractController::Rendering
|
||||
include AbstractController::LocalizedCache
|
||||
include AbstractController::Layouts
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
*Edge*
|
||||
|
||||
* Added ActionDispatch::Request#authorization to access the http authentication header regardless of its proxy hiding [DHH]
|
||||
|
||||
* Added :alert, :notice, and :flash as options to ActionController::Base#redirect_to that'll automatically set the proper flash before the redirection [DHH]. Examples:
|
||||
|
||||
flash[:notice] = 'Post was created'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
|
||||
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
|
||||
|
||||
require 'active_support'
|
||||
require 'active_support/ruby/shim'
|
||||
require 'active_support/core_ext/module/attr_internal'
|
||||
require 'active_support/core_ext/module/delegation'
|
||||
|
||||
@@ -15,6 +15,6 @@ module AbstractController
|
||||
autoload :Layouts
|
||||
autoload :LocalizedCache
|
||||
autoload :Logger
|
||||
autoload :RenderingController
|
||||
autoload :Rendering
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ module AbstractController
|
||||
class Base
|
||||
attr_internal :response_body
|
||||
attr_internal :action_name
|
||||
attr_internal :formats
|
||||
|
||||
class << self
|
||||
attr_reader :abstract
|
||||
|
||||
@@ -4,7 +4,7 @@ module AbstractController
|
||||
module Helpers
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include RenderingController
|
||||
include Rendering
|
||||
|
||||
def self.next_serial
|
||||
@helper_serial ||= 0
|
||||
|
||||
@@ -2,7 +2,7 @@ module AbstractController
|
||||
module Layouts
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include RenderingController
|
||||
include Rendering
|
||||
|
||||
included do
|
||||
extlib_inheritable_accessor(:_layout_conditions) { Hash.new }
|
||||
|
||||
@@ -10,13 +10,12 @@ module AbstractController
|
||||
end
|
||||
end
|
||||
|
||||
module RenderingController
|
||||
module Rendering
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include AbstractController::Logger
|
||||
|
||||
included do
|
||||
attr_internal :formats
|
||||
extlib_inheritable_accessor :_view_paths
|
||||
self._view_paths ||= ActionView::PathSet.new
|
||||
end
|
||||
@@ -80,7 +79,7 @@ module AbstractController
|
||||
#
|
||||
# :api: plugin
|
||||
def render_to_string(options = {})
|
||||
AbstractController::RenderingController.body_to_s(render_to_body(options))
|
||||
AbstractController::Rendering.body_to_s(render_to_body(options))
|
||||
end
|
||||
|
||||
# Renders the template from an object.
|
||||
@@ -1,6 +1,6 @@
|
||||
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
|
||||
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
|
||||
require 'active_support'
|
||||
require 'active_support/ruby/shim'
|
||||
|
||||
module ActionController
|
||||
extend ActiveSupport::Autoload
|
||||
@@ -22,14 +22,13 @@ module ActionController
|
||||
autoload :HideActions
|
||||
autoload :Layouts
|
||||
autoload :MimeResponds
|
||||
autoload :RackConvenience
|
||||
autoload :RackDelegation
|
||||
autoload :Compatibility
|
||||
autoload :Redirector
|
||||
autoload :RenderingController
|
||||
autoload :RenderOptions
|
||||
autoload :Redirecting
|
||||
autoload :Rendering
|
||||
autoload :Renderers
|
||||
autoload :Rescue
|
||||
autoload :Responder
|
||||
autoload :Session
|
||||
autoload :SessionManagement
|
||||
autoload :UrlFor
|
||||
autoload :Verification
|
||||
|
||||
@@ -8,12 +8,12 @@ module ActionController
|
||||
include ActionController::Helpers
|
||||
include ActionController::HideActions
|
||||
include ActionController::UrlFor
|
||||
include ActionController::Redirector
|
||||
include ActionController::RenderingController
|
||||
include ActionController::RenderOptions::All
|
||||
include ActionController::Redirecting
|
||||
include ActionController::Rendering
|
||||
include ActionController::Renderers::All
|
||||
include ActionController::Layouts
|
||||
include ActionController::ConditionalGet
|
||||
include ActionController::RackConvenience
|
||||
include ActionController::RackDelegation
|
||||
include ActionController::Benchmarking
|
||||
include ActionController::Configuration
|
||||
|
||||
@@ -26,7 +26,6 @@ module ActionController
|
||||
include ActionController::Compatibility
|
||||
|
||||
include ActionController::Cookies
|
||||
include ActionController::Session
|
||||
include ActionController::Flash
|
||||
include ActionController::Verification
|
||||
include ActionController::RequestForgeryProtection
|
||||
@@ -90,7 +89,7 @@ module ActionController
|
||||
end
|
||||
|
||||
if options[:status]
|
||||
options[:status] = _interpret_status(options[:status])
|
||||
options[:status] = ActionDispatch::StatusCodes[options[:status]]
|
||||
end
|
||||
|
||||
options[:update] = blk if block_given?
|
||||
|
||||
@@ -45,7 +45,7 @@ module ActionController
|
||||
|
||||
# The details below can be overridden to support a specific
|
||||
# Request and Response object. The default ActionController::Base
|
||||
# implementation includes RackConvenience, which makes a request
|
||||
# implementation includes RackDelegation, which makes a request
|
||||
# and response object available. You might wish to control the
|
||||
# environment and response manually for performance reasons.
|
||||
|
||||
@@ -57,7 +57,7 @@ module ActionController
|
||||
end
|
||||
|
||||
# Basic implementations for content_type=, location=, and headers are
|
||||
# provided to reduce the dependency on the RackConvenience module
|
||||
# provided to reduce the dependency on the RackDelegation module
|
||||
# in Renderer and Redirector.
|
||||
|
||||
def content_type=(type)
|
||||
@@ -68,6 +68,10 @@ module ActionController
|
||||
headers["Location"] = url
|
||||
end
|
||||
|
||||
def status=(status)
|
||||
@_status = ActionDispatch::StatusCodes[status]
|
||||
end
|
||||
|
||||
# :api: private
|
||||
def dispatch(name, env)
|
||||
@_env = env
|
||||
@@ -92,6 +96,7 @@ module ActionController
|
||||
|
||||
def initialize(controller, action)
|
||||
@controller, @action = controller, action
|
||||
@_formats = [Mime::HTML]
|
||||
end
|
||||
|
||||
def call(env)
|
||||
|
||||
@@ -2,7 +2,7 @@ module ActionController
|
||||
module ConditionalGet
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include RackConvenience
|
||||
include RackDelegation
|
||||
include Head
|
||||
|
||||
# Sets the etag, last_modified, or both on the response and renders a
|
||||
|
||||
@@ -46,7 +46,7 @@ module ActionController #:nodoc:
|
||||
module Cookies
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include RackConvenience
|
||||
include RackDelegation
|
||||
|
||||
included do
|
||||
helper_method :cookies
|
||||
|
||||
@@ -28,8 +28,6 @@ module ActionController #:nodoc:
|
||||
module Flash
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include Session
|
||||
|
||||
included do
|
||||
helper_method :alert, :notice
|
||||
end
|
||||
@@ -155,7 +153,7 @@ module ActionController #:nodoc:
|
||||
def alert
|
||||
flash[:alert]
|
||||
end
|
||||
|
||||
|
||||
# Convenience accessor for flash[:alert]=
|
||||
def alert=(message)
|
||||
flash[:alert] = message
|
||||
@@ -165,7 +163,7 @@ module ActionController #:nodoc:
|
||||
def notice
|
||||
flash[:notice]
|
||||
end
|
||||
|
||||
|
||||
# Convenience accessor for flash[:notice]=
|
||||
def notice=(message)
|
||||
flash[:notice] = message
|
||||
@@ -193,11 +191,11 @@ module ActionController #:nodoc:
|
||||
if notice = response_status_and_flash.delete(:notice)
|
||||
flash[:notice] = notice
|
||||
end
|
||||
|
||||
|
||||
if other_flashes = response_status_and_flash.delete(:flash)
|
||||
flash.update(other_flashes)
|
||||
end
|
||||
|
||||
|
||||
super(options, response_status_and_flash)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
module ActionController
|
||||
module Head
|
||||
include UrlFor
|
||||
|
||||
# Return a response that has no content (merely headers). The options
|
||||
# argument is interpreted to be a hash of header names and values.
|
||||
# This allows you to easily return a response that consists only of
|
||||
@@ -21,7 +23,10 @@ module ActionController
|
||||
headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
|
||||
end
|
||||
|
||||
render :nothing => true, :status => status, :location => location
|
||||
self.status = status
|
||||
self.location = url_for(location) if location
|
||||
self.content_type = Mime[formats.first]
|
||||
self.response_body = " "
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -158,7 +158,7 @@ module ActionController
|
||||
module Layouts
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include ActionController::RenderingController
|
||||
include ActionController::Rendering
|
||||
include AbstractController::Layouts
|
||||
|
||||
module ClassMethods
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
module ActionController
|
||||
module RackConvenience
|
||||
module RackDelegation
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
delegate :session, :reset_session, :to => "@_request"
|
||||
delegate :headers, :status=, :location=, :content_type=,
|
||||
:status, :location, :content_type, :to => "@_response"
|
||||
attr_internal :request
|
||||
@@ -7,7 +7,7 @@ module ActionController
|
||||
end
|
||||
end
|
||||
|
||||
module Redirector
|
||||
module Redirecting
|
||||
extend ActiveSupport::Concern
|
||||
include AbstractController::Logger
|
||||
|
||||
@@ -62,9 +62,9 @@ module ActionController
|
||||
private
|
||||
def _extract_redirect_to_status(options, response_status)
|
||||
status = if options.is_a?(Hash) && options.key?(:status)
|
||||
_interpret_status(options.delete(:status))
|
||||
ActionDispatch::StatusCodes[options.delete(:status)]
|
||||
elsif response_status.key?(:status)
|
||||
_interpret_status(response_status[:status])
|
||||
ActionDispatch::StatusCodes[response_status[:status]]
|
||||
else
|
||||
302
|
||||
end
|
||||
@@ -86,13 +86,5 @@ module ActionController
|
||||
url_for(options)
|
||||
end.gsub(/[\r\n]/, '')
|
||||
end
|
||||
|
||||
def _interpret_status(status)
|
||||
if status.is_a?(Symbol)
|
||||
(ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[status] || 500)
|
||||
else
|
||||
status.to_i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,10 +1,9 @@
|
||||
module ActionController
|
||||
|
||||
def self.add_renderer(key, &block)
|
||||
RenderOptions.add(key, &block)
|
||||
Renderers.add(key, &block)
|
||||
end
|
||||
|
||||
module RenderOptions
|
||||
module Renderers
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
@@ -52,7 +51,7 @@ module ActionController
|
||||
|
||||
module All
|
||||
extend ActiveSupport::Concern
|
||||
include RenderOptions
|
||||
include Renderers
|
||||
|
||||
INCLUDED = []
|
||||
included do
|
||||
@@ -1,9 +1,9 @@
|
||||
module ActionController
|
||||
module RenderingController
|
||||
module Rendering
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
include AbstractController::RenderingController
|
||||
include AbstractController::Rendering
|
||||
include AbstractController::LocalizedCache
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@ module ActionController #:nodoc:
|
||||
module RequestForgeryProtection
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include AbstractController::Helpers, Session
|
||||
include AbstractController::Helpers
|
||||
|
||||
included do
|
||||
# Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+
|
||||
@@ -19,31 +19,31 @@ module ActionController #:nodoc:
|
||||
helper_method :form_authenticity_token
|
||||
helper_method :protect_against_forgery?
|
||||
end
|
||||
|
||||
# Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
|
||||
# web application, not a forged link from another site, is done by embedding a token based on a random
|
||||
|
||||
# Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
|
||||
# web application, not a forged link from another site, is done by embedding a token based on a random
|
||||
# string stored in the session (which an attacker wouldn't know) in all forms and Ajax requests generated
|
||||
# by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
|
||||
# requests are checked, so this will not protect your XML API (presumably you'll have a different
|
||||
# authentication scheme there anyway). Also, GET requests are not protected as these should be
|
||||
# by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
|
||||
# requests are checked, so this will not protect your XML API (presumably you'll have a different
|
||||
# authentication scheme there anyway). Also, GET requests are not protected as these should be
|
||||
# idempotent anyway.
|
||||
#
|
||||
# This is turned on with the <tt>protect_from_forgery</tt> method, which will check the token and raise an
|
||||
# ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
|
||||
# ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
|
||||
# error message in production by editing public/422.html. A call to this method in ApplicationController is
|
||||
# generated by default in post-Rails 2.0 applications.
|
||||
#
|
||||
# The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
|
||||
# manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
|
||||
# include a hidden field named like that and set its value to what is returned by
|
||||
# The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
|
||||
# manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
|
||||
# include a hidden field named like that and set its value to what is returned by
|
||||
# <tt>form_authenticity_token</tt>.
|
||||
#
|
||||
# Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
|
||||
# Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
|
||||
# 1.x, add this to config/environments/test.rb:
|
||||
#
|
||||
# # Disable request forgery protection in test environment
|
||||
# config.action_controller.allow_forgery_protection = false
|
||||
#
|
||||
#
|
||||
# == Learn more about CSRF (Cross-Site Request Forgery) attacks
|
||||
#
|
||||
# Here are some resources:
|
||||
@@ -52,11 +52,11 @@ module ActionController #:nodoc:
|
||||
#
|
||||
# Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
|
||||
# There are a few guidelines you should follow:
|
||||
#
|
||||
#
|
||||
# * Keep your GET requests safe and idempotent. More reading material:
|
||||
# * http://www.xml.com/pub/a/2002/04/24/deviant.html
|
||||
# * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
|
||||
# * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
|
||||
# * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
|
||||
# for "Expires: at end of session"
|
||||
#
|
||||
module ClassMethods
|
||||
@@ -92,7 +92,7 @@ module ActionController #:nodoc:
|
||||
# * is it a GET request? Gets should be safe and idempotent
|
||||
# * Does the form_authenticity_token match the given token value from the params?
|
||||
def verified_request?
|
||||
!protect_against_forgery? || request.forgery_whitelisted? ||
|
||||
!protect_against_forgery? || request.forgery_whitelisted? ||
|
||||
form_authenticity_token == params[request_forgery_protection_token]
|
||||
end
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
module ActionController
|
||||
module Session
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include RackConvenience
|
||||
|
||||
def session
|
||||
@_request.session
|
||||
end
|
||||
|
||||
def reset_session
|
||||
@_request.reset_session
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -4,7 +4,7 @@ module ActionController #:nodoc:
|
||||
module Streaming
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include ActionController::RenderingController
|
||||
include ActionController::Rendering
|
||||
|
||||
DEFAULT_SEND_FILE_OPTIONS = {
|
||||
:type => 'application/octet-stream'.freeze,
|
||||
|
||||
@@ -2,7 +2,7 @@ module ActionController
|
||||
module Testing
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include RackConvenience
|
||||
include RackDelegation
|
||||
|
||||
# OMG MEGA HAX
|
||||
def process_with_new_base_test(request, response)
|
||||
|
||||
@@ -2,7 +2,7 @@ module ActionController
|
||||
module UrlFor
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include RackConvenience
|
||||
include RackDelegation
|
||||
|
||||
# Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in
|
||||
# the form of a hash, just like the one you would use for url_for directly. Example:
|
||||
|
||||
@@ -2,7 +2,7 @@ module ActionController #:nodoc:
|
||||
module Verification #:nodoc:
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include AbstractController::Callbacks, Session, Flash, RenderingController
|
||||
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
|
||||
@@ -35,7 +35,7 @@ module ActionController #:nodoc:
|
||||
# :add_flash => { "alert" => "Failed to create your message" },
|
||||
# :redirect_to => :category_url
|
||||
#
|
||||
# Note that these prerequisites are not business rules. They do not examine
|
||||
# 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
|
||||
@@ -43,40 +43,40 @@ module ActionController #:nodoc:
|
||||
# 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>
|
||||
# <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>
|
||||
# <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
|
||||
# <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
|
||||
# <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
|
||||
# <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
|
||||
# <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
|
||||
# <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>::
|
||||
# <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
|
||||
# <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
|
||||
# <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
|
||||
@@ -94,31 +94,31 @@ module ActionController #:nodoc:
|
||||
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_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 != 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])
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
|
||||
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
|
||||
require 'active_support'
|
||||
require 'active_support/ruby/shim'
|
||||
|
||||
require 'rack'
|
||||
|
||||
@@ -38,7 +38,6 @@ module ActionDispatch
|
||||
autoload :Request
|
||||
autoload :Response
|
||||
autoload :StatusCodes
|
||||
autoload :Utils
|
||||
end
|
||||
|
||||
deferrable do
|
||||
|
||||
@@ -465,6 +465,15 @@ EOM
|
||||
session['flash'] || {}
|
||||
end
|
||||
|
||||
# Returns the authorization header regardless of whether it was specified directly or through one of the
|
||||
# proxy alternatives.
|
||||
def authorization
|
||||
@env['HTTP_AUTHORIZATION'] ||
|
||||
@env['X-HTTP_AUTHORIZATION'] ||
|
||||
@env['X_HTTP_AUTHORIZATION'] ||
|
||||
@env['REDIRECT_X_HTTP_AUTHORIZATION']
|
||||
end
|
||||
|
||||
# Receives an array of mimes and return the first user sent mime that
|
||||
# matches the order array.
|
||||
#
|
||||
|
||||
@@ -60,7 +60,7 @@ module ActionDispatch # :nodoc:
|
||||
end
|
||||
|
||||
def status=(status)
|
||||
@status = status.to_i
|
||||
@status = ActionDispatch::StatusCodes[status]
|
||||
end
|
||||
|
||||
# The response code of the request
|
||||
|
||||
@@ -14,6 +14,14 @@ module ActionDispatch
|
||||
510 => "Not Extended"
|
||||
}).freeze
|
||||
|
||||
def self.[](status)
|
||||
if status.is_a?(Symbol)
|
||||
SYMBOL_TO_STATUS_CODE[status] || 500
|
||||
else
|
||||
status.to_i
|
||||
end
|
||||
end
|
||||
|
||||
# Provides a symbol-to-fixnum lookup for converting a symbol (like
|
||||
# :created or :not_implemented) into its corresponding HTTP status
|
||||
# code (like 200 or 501).
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
module ActionDispatch
|
||||
module Utils
|
||||
# TODO: Pull this into rack core
|
||||
# http://github.com/halorgium/rack/commit/feaf071c1de743fbd10bc316830180a9af607278
|
||||
def parse_config(config)
|
||||
if config =~ /\.ru$/
|
||||
cfgfile = ::File.read(config)
|
||||
if cfgfile[/^#\\(.*)/]
|
||||
opts.parse! $1.split(/\s+/)
|
||||
end
|
||||
inner_app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
|
||||
nil, config
|
||||
else
|
||||
require config
|
||||
inner_app = Object.const_get(::File.basename(config, '.rb').capitalize)
|
||||
end
|
||||
end
|
||||
module_function :parse_config
|
||||
end
|
||||
end
|
||||
@@ -31,41 +31,39 @@ module ActionDispatch
|
||||
return false unless strategy
|
||||
|
||||
case strategy
|
||||
when Proc
|
||||
strategy.call(request.raw_post)
|
||||
when :xml_simple, :xml_node
|
||||
request.body.size == 0 ? {} : Hash.from_xml(request.body).with_indifferent_access
|
||||
when :yaml
|
||||
YAML.load(request.body)
|
||||
when :json
|
||||
if request.body.size == 0
|
||||
{}
|
||||
else
|
||||
data = ActiveSupport::JSON.decode(request.body)
|
||||
data = {:_json => data} unless data.is_a?(Hash)
|
||||
data.with_indifferent_access
|
||||
end
|
||||
when Proc
|
||||
strategy.call(request.raw_post)
|
||||
when :xml_simple, :xml_node
|
||||
request.body.size == 0 ? {} : Hash.from_xml(request.body).with_indifferent_access
|
||||
when :yaml
|
||||
YAML.load(request.body)
|
||||
when :json
|
||||
if request.body.size == 0
|
||||
{}
|
||||
else
|
||||
false
|
||||
data = ActiveSupport::JSON.decode(request.body)
|
||||
data = {:_json => data} unless data.is_a?(Hash)
|
||||
data.with_indifferent_access
|
||||
end
|
||||
else
|
||||
false
|
||||
end
|
||||
rescue Exception => e # YAML, XML or Ruby code block errors
|
||||
logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
|
||||
|
||||
raise
|
||||
{ "body" => request.raw_post,
|
||||
"content_type" => request.content_type,
|
||||
{ "body" => request.raw_post,
|
||||
"content_type" => request.content_type,
|
||||
"content_length" => request.content_length,
|
||||
"exception" => "#{e.message} (#{e.class})",
|
||||
"backtrace" => e.backtrace }
|
||||
"exception" => "#{e.message} (#{e.class})",
|
||||
"backtrace" => e.backtrace }
|
||||
end
|
||||
|
||||
def content_type_from_legacy_post_data_format_header(env)
|
||||
if x_post_format = env['HTTP_X_POST_DATA_FORMAT']
|
||||
case x_post_format.to_s.downcase
|
||||
when 'yaml'
|
||||
return Mime::YAML
|
||||
when 'xml'
|
||||
return Mime::XML
|
||||
when 'yaml' then return Mime::YAML
|
||||
when 'xml' then return Mime::XML
|
||||
end
|
||||
end
|
||||
|
||||
@@ -76,4 +74,4 @@ module ActionDispatch
|
||||
defined?(Rails.logger) ? Rails.logger : Logger.new($stderr)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -39,9 +39,13 @@ module ActionDispatch
|
||||
end
|
||||
|
||||
def match(*args)
|
||||
options = args.extract_options!
|
||||
|
||||
path = args.first
|
||||
if args.one? && args.first.is_a?(Hash)
|
||||
path = args.first.keys.first
|
||||
options = { :to => args.first.values.first }
|
||||
else
|
||||
path = args.first
|
||||
options = args.extract_options!
|
||||
end
|
||||
|
||||
conditions, defaults = {}, {}
|
||||
|
||||
@@ -132,13 +136,19 @@ module ActionDispatch
|
||||
map_method(:delete, *args, &block)
|
||||
end
|
||||
|
||||
def redirect(path, options = {})
|
||||
def redirect(*args, &block)
|
||||
options = args.last.is_a?(Hash) ? args.pop : {}
|
||||
|
||||
path = args.shift || block
|
||||
path_proc = path.is_a?(Proc) ? path : proc {|params| path % params }
|
||||
status = options[:status] || 301
|
||||
lambda { |env|
|
||||
|
||||
lambda do |env|
|
||||
req = Rack::Request.new(env)
|
||||
url = req.scheme + '://' + req.host + path
|
||||
params = path_proc.call(env["action_dispatch.request.path_parameters"])
|
||||
url = req.scheme + '://' + req.host + params
|
||||
[status, {'Location' => url, 'Content-Type' => 'text/html'}, ['Moved Permanently']]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
|
||||
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
|
||||
require 'active_support'
|
||||
require 'active_support/ruby/shim'
|
||||
require 'active_support/core_ext/class/attribute_accessors'
|
||||
|
||||
require 'action_pack'
|
||||
|
||||
@@ -28,7 +28,7 @@ module AbstractController
|
||||
# Test Render mixin
|
||||
# ====
|
||||
class RenderingController < AbstractController::Base
|
||||
include ::AbstractController::RenderingController
|
||||
include ::AbstractController::Rendering
|
||||
|
||||
def _prefix() end
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ module AbstractController
|
||||
module Testing
|
||||
|
||||
class ControllerWithHelpers < AbstractController::Base
|
||||
include AbstractController::RenderingController
|
||||
include AbstractController::Rendering
|
||||
include Helpers
|
||||
|
||||
def with_module
|
||||
|
||||
@@ -6,7 +6,7 @@ module AbstractControllerTests
|
||||
|
||||
# Base controller for these tests
|
||||
class Base < AbstractController::Base
|
||||
include AbstractController::RenderingController
|
||||
include AbstractController::Rendering
|
||||
include AbstractController::Layouts
|
||||
|
||||
self.view_paths = [ActionView::FixtureResolver.new(
|
||||
|
||||
@@ -4,7 +4,7 @@ module AbstractController
|
||||
module Testing
|
||||
|
||||
class CachedController < AbstractController::Base
|
||||
include AbstractController::RenderingController
|
||||
include AbstractController::Rendering
|
||||
include AbstractController::LocalizedCache
|
||||
|
||||
self.view_paths = [ActionView::FixtureResolver.new(
|
||||
|
||||
@@ -4,7 +4,7 @@ module AbstractController
|
||||
module Testing
|
||||
|
||||
class ControllerRenderer < AbstractController::Base
|
||||
include AbstractController::RenderingController
|
||||
include AbstractController::Rendering
|
||||
|
||||
self.view_paths = [ActionView::FixtureResolver.new(
|
||||
"default.erb" => "With Default",
|
||||
|
||||
@@ -22,8 +22,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
|
||||
delete 'logout', :to => :destroy, :as => :logout
|
||||
end
|
||||
|
||||
match 'account/logout' => redirect("/logout")
|
||||
match 'account/login', :to => redirect("/login")
|
||||
|
||||
match 'account/modulo/:name', :to => redirect("/%{name}s")
|
||||
match 'account/proc/:name', :to => redirect {|params| "/#{params[:name].pluralize}" }
|
||||
|
||||
match 'openid/login', :via => [:get, :post], :to => "openid#login"
|
||||
|
||||
controller(:global) do
|
||||
@@ -34,11 +38,11 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
constraints(:ip => /192\.168\.1\.\d\d\d/) do
|
||||
get 'admin', :to => "queenbee#index"
|
||||
get 'admin' => "queenbee#index"
|
||||
end
|
||||
|
||||
constraints ::TestRoutingMapper::IpRestrictor do
|
||||
get 'admin/accounts', :to => "queenbee#accounts"
|
||||
get 'admin/accounts' => "queenbee#accounts"
|
||||
end
|
||||
|
||||
resources :projects, :controller => :project do
|
||||
@@ -82,7 +86,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
match 'sprockets.js', :to => ::TestRoutingMapper::SprocketsApp
|
||||
match 'sprockets.js' => ::TestRoutingMapper::SprocketsApp
|
||||
|
||||
match 'people/:id/update', :to => 'people#update', :as => :update_person
|
||||
match '/projects/:project_id/people/:id/update', :to => 'people#update', :as => :update_project_person
|
||||
@@ -145,6 +149,33 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
def test_logout_redirect_without_to
|
||||
with_test_routes do
|
||||
get '/account/logout'
|
||||
assert_equal 301, @response.status
|
||||
assert_equal 'http://www.example.com/logout', @response.headers['Location']
|
||||
assert_equal 'Moved Permanently', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
def test_redirect_modulo
|
||||
with_test_routes do
|
||||
get '/account/modulo/name'
|
||||
assert_equal 301, @response.status
|
||||
assert_equal 'http://www.example.com/names', @response.headers['Location']
|
||||
assert_equal 'Moved Permanently', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
def test_redirect_proc
|
||||
with_test_routes do
|
||||
get '/account/proc/person'
|
||||
assert_equal 301, @response.status
|
||||
assert_equal 'http://www.example.com/people', @response.headers['Location']
|
||||
assert_equal 'Moved Permanently', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
def test_openid
|
||||
with_test_routes do
|
||||
get '/openid/login'
|
||||
|
||||
@@ -37,7 +37,8 @@ module ActiveResource
|
||||
autoload :Connection
|
||||
autoload :CustomMethods
|
||||
autoload :Formats
|
||||
autoload :Observing
|
||||
autoload :Validations
|
||||
autoload :HttpMock
|
||||
autoload :Observing
|
||||
autoload :Schema
|
||||
autoload :Validations
|
||||
end
|
||||
|
||||
@@ -241,6 +241,124 @@ module ActiveResource
|
||||
cattr_accessor :logger
|
||||
|
||||
class << self
|
||||
# Creates a schema for this resource - setting the attributes that are
|
||||
# known prior to fetching an instance from the remote system.
|
||||
#
|
||||
# The schema helps define the set of <tt>known_attributes</tt> of the
|
||||
# current resource.
|
||||
#
|
||||
# There is no need to specify a schema for your Active Resource. If
|
||||
# you do not, the <tt>known_attributes</tt> will be guessed from the
|
||||
# instance attributes returned when an instance is fetched from the
|
||||
# remote system.
|
||||
#
|
||||
# example:
|
||||
# class Person < ActiveResource::Base
|
||||
# schema do
|
||||
# # define each attribute separately
|
||||
# attribute 'name', :string
|
||||
#
|
||||
# # or use the convenience methods and pass >=1 attribute names
|
||||
# string 'eye_colour', 'hair_colour'
|
||||
# integer 'age'
|
||||
# float 'height', 'weight'
|
||||
#
|
||||
# # unsupported types should be left as strings
|
||||
# # overload the accessor methods if you need to convert them
|
||||
# attribute 'created_at', 'string'
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# p = Person.new
|
||||
# p.respond_to? :name # => true
|
||||
# p.respond_to? :age # => true
|
||||
# p.name # => nil
|
||||
# p.age # => nil
|
||||
#
|
||||
# j = Person.find_by_name('John') # <person><name>John</name><age>34</age><num_children>3</num_children></person>
|
||||
# j.respond_to? :name # => true
|
||||
# j.respond_to? :age # => true
|
||||
# j.name # => 'John'
|
||||
# j.age # => '34' # note this is a string!
|
||||
# j.num_children # => '3' # note this is a string!
|
||||
#
|
||||
# p.num_children # => NoMethodError
|
||||
#
|
||||
# Attribute-types must be one of:
|
||||
# string, integer, float
|
||||
#
|
||||
# Note: at present the attribute-type doesn't do anything, but stay
|
||||
# tuned...
|
||||
# Shortly it will also *cast* the value of the returned attribute.
|
||||
# ie:
|
||||
# j.age # => 34 # cast to an integer
|
||||
# j.weight # => '65' # still a string!
|
||||
#
|
||||
def schema(&block)
|
||||
if block_given?
|
||||
schema_definition = Schema.new
|
||||
schema_definition.instance_eval(&block)
|
||||
|
||||
# skip out if we didn't define anything
|
||||
return unless schema_definition.attrs.present?
|
||||
|
||||
@schema ||= {}.with_indifferent_access
|
||||
@known_attributes ||= []
|
||||
|
||||
schema_definition.attrs.each do |k,v|
|
||||
@schema[k] = v
|
||||
@known_attributes << k
|
||||
end
|
||||
|
||||
schema
|
||||
else
|
||||
@schema ||= nil
|
||||
end
|
||||
end
|
||||
|
||||
# Alternative, direct way to specify a <tt>schema</tt> for this
|
||||
# Resource. <tt>schema</tt> is more flexible, but this is quick
|
||||
# for a very simple schema.
|
||||
#
|
||||
# Pass the schema as a hash with the keys being the attribute-names
|
||||
# and the value being one of the accepted attribute types (as defined
|
||||
# in <tt>schema</tt>)
|
||||
#
|
||||
# example:
|
||||
#
|
||||
# class Person < ActiveResource::Base
|
||||
# schema = {'name' => :string, 'age' => :integer }
|
||||
# end
|
||||
#
|
||||
# The keys/values can be strings or symbols. They will be converted to
|
||||
# strings.
|
||||
#
|
||||
def schema=(the_schema)
|
||||
unless the_schema.present?
|
||||
# purposefully nulling out the schema
|
||||
@schema = nil
|
||||
@known_attributes = []
|
||||
return
|
||||
end
|
||||
|
||||
raise ArgumentError, "Expected a hash" unless the_schema.kind_of? Hash
|
||||
|
||||
schema do
|
||||
the_schema.each {|k,v| attribute(k,v) }
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the list of known attributes for this resource, gathered
|
||||
# from the provided <tt>schema</tt>
|
||||
# Attributes that are known will cause your resource to return 'true'
|
||||
# when <tt>respond_to?</tt> is called on them. A known attribute will
|
||||
# return nil if not set (rather than <t>MethodNotFound</tt>); thus
|
||||
# known attributes can be used with <tt>validates_presence_of</tt>
|
||||
# without a getter-method.
|
||||
def known_attributes
|
||||
@known_attributes ||= []
|
||||
end
|
||||
|
||||
# Gets the URI of the REST resources to map for this class. The site variable is required for
|
||||
# Active Resource's mapping to work.
|
||||
def site
|
||||
@@ -776,6 +894,21 @@ module ActiveResource
|
||||
attr_accessor :attributes #:nodoc:
|
||||
attr_accessor :prefix_options #:nodoc:
|
||||
|
||||
# If no schema has been defined for the class (see
|
||||
# <tt>ActiveResource::schema=</tt>), the default automatic schema is
|
||||
# generated from the current instance's attributes
|
||||
def schema
|
||||
self.class.schema || self.attributes
|
||||
end
|
||||
|
||||
# This is a list of known attributes for this resource. Either
|
||||
# gathered fromthe provided <tt>schema</tt>, or from the attributes
|
||||
# set on this instance after it has been fetched from the remote system.
|
||||
def known_attributes
|
||||
self.class.known_attributes + self.attributes.keys.map(&:to_s)
|
||||
end
|
||||
|
||||
|
||||
# Constructor method for \new resources; the optional +attributes+ parameter takes a \hash
|
||||
# of attributes for the \new resource.
|
||||
#
|
||||
@@ -1157,7 +1290,7 @@ module ActiveResource
|
||||
method_name = method.to_s
|
||||
if attributes.nil?
|
||||
super
|
||||
elsif attributes.has_key?(method_name)
|
||||
elsif known_attributes.include?(method_name)
|
||||
true
|
||||
elsif method_name =~ /(?:=|\?)$/ && attributes.include?($`)
|
||||
true
|
||||
@@ -1262,7 +1395,10 @@ module ActiveResource
|
||||
attributes[$`]
|
||||
end
|
||||
else
|
||||
attributes.include?(method_name) ? attributes[method_name] : super
|
||||
return attributes[method_name] if attributes.include?(method_name)
|
||||
# not set right now but we know about it
|
||||
return nil if known_attributes.include?(method_name)
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
55
activeresource/lib/active_resource/schema.rb
Normal file
55
activeresource/lib/active_resource/schema.rb
Normal file
@@ -0,0 +1,55 @@
|
||||
require 'active_resource/exceptions'
|
||||
|
||||
module ActiveResource # :nodoc:
|
||||
class Schema # :nodoc:
|
||||
# attributes can be known to be one of these types. They are easy to
|
||||
# cast to/from.
|
||||
KNOWN_ATTRIBUTE_TYPES = %w( string integer float )
|
||||
|
||||
# An array of attribute definitions, representing the attributes that
|
||||
# have been defined.
|
||||
attr_accessor :attrs
|
||||
|
||||
# The internals of an Active Resource Schema are very simple -
|
||||
# unlike an Active Record TableDefinition (on which it is based).
|
||||
# It provides a set of convenience methods for people to define their
|
||||
# schema using the syntax:
|
||||
# schema do
|
||||
# string :foo
|
||||
# integer :bar
|
||||
# end
|
||||
#
|
||||
# The schema stores the name and type of each attribute. That is then
|
||||
# read out by the schema method to populate the actual
|
||||
# Resource's schema
|
||||
def initialize
|
||||
@attrs = {}
|
||||
end
|
||||
|
||||
def attribute(name, type, options = {})
|
||||
raise ArgumentError, "Unknown Attribute type: #{type.inspect} for key: #{name.inspect}" unless type.nil? || Schema::KNOWN_ATTRIBUTE_TYPES.include?(type.to_s)
|
||||
|
||||
the_type = type.to_s
|
||||
# TODO: add defaults
|
||||
#the_attr = [type.to_s]
|
||||
#the_attr << options[:default] if options.has_key? :default
|
||||
@attrs[name.to_s] = the_type
|
||||
self
|
||||
end
|
||||
|
||||
# The following are the attribute types supported by Active Resource
|
||||
# migrations.
|
||||
# TODO: We should eventually support all of these:
|
||||
# %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |attr_type|
|
||||
KNOWN_ATTRIBUTE_TYPES.each do |attr_type|
|
||||
class_eval <<-EOV
|
||||
def #{attr_type.to_s}(*args)
|
||||
options = args.extract_options!
|
||||
attr_names = args
|
||||
|
||||
attr_names.each { |name| attribute(name, '#{attr_type}', options) }
|
||||
end
|
||||
EOV
|
||||
end
|
||||
end
|
||||
end
|
||||
419
activeresource/test/cases/base/schema_test.rb
Normal file
419
activeresource/test/cases/base/schema_test.rb
Normal file
@@ -0,0 +1,419 @@
|
||||
require 'abstract_unit'
|
||||
require "fixtures/person"
|
||||
require "fixtures/street_address"
|
||||
|
||||
########################################################################
|
||||
# Testing the schema of your Active Resource models
|
||||
########################################################################
|
||||
class SchemaTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person')
|
||||
@david = { :id => 2, :name => 'David' }.to_xml(:root => 'person')
|
||||
@greg = { :id => 3, :name => 'Greg' }.to_xml(:root => 'person')
|
||||
@addy = { :id => 1, :street => '12345 Street', :country => 'Australia' }.to_xml(:root => 'address')
|
||||
@default_request_headers = { 'Content-Type' => 'application/xml' }
|
||||
@rick = { :name => "Rick", :age => 25 }.to_xml(:root => "person")
|
||||
@people = [{ :id => 1, :name => 'Matz' }, { :id => 2, :name => 'David' }].to_xml(:root => 'people')
|
||||
@people_david = [{ :id => 2, :name => 'David' }].to_xml(:root => 'people')
|
||||
@addresses = [{ :id => 1, :street => '12345 Street', :country => 'Australia' }].to_xml(:root => 'addresses')
|
||||
|
||||
ActiveResource::HttpMock.respond_to do |mock|
|
||||
mock.get "/people/1.xml", {}, @matz
|
||||
mock.get "/people/2.xml", {}, @david
|
||||
mock.get "/people/Greg.xml", {}, @greg
|
||||
mock.get "/people/4.xml", {'key' => 'value'}, nil, 404
|
||||
mock.get "/people/5.xml", {}, @rick
|
||||
mock.put "/people/1.xml", {}, nil, 204
|
||||
mock.delete "/people/1.xml", {}, nil, 200
|
||||
mock.delete "/people/2.xml", {}, nil, 400
|
||||
mock.get "/people/99.xml", {}, nil, 404
|
||||
mock.post "/people.xml", {}, @rick, 201, 'Location' => '/people/5.xml'
|
||||
mock.get "/people.xml", {}, @people
|
||||
mock.get "/people/1/addresses.xml", {}, @addresses
|
||||
mock.get "/people/1/addresses/1.xml", {}, @addy
|
||||
mock.get "/people/1/addresses/2.xml", {}, nil, 404
|
||||
mock.get "/people/2/addresses/1.xml", {}, nil, 404
|
||||
mock.get "/people/Greg/addresses/1.xml", {}, @addy
|
||||
mock.put "/people/1/addresses/1.xml", {}, nil, 204
|
||||
mock.delete "/people/1/addresses/1.xml", {}, nil, 200
|
||||
mock.post "/people/1/addresses.xml", {}, nil, 201, 'Location' => '/people/1/addresses/5'
|
||||
mock.get "/people//addresses.xml", {}, nil, 404
|
||||
mock.get "/people//addresses/1.xml", {}, nil, 404
|
||||
mock.put "/people//addressaddresseses/1.xml", {}, nil, 404
|
||||
mock.delete "/people//addresses/1.xml", {}, nil, 404
|
||||
mock.post "/people//addresses.xml", {}, nil, 404
|
||||
mock.head "/people/1.xml", {}, nil, 200
|
||||
mock.head "/people/Greg.xml", {}, nil, 200
|
||||
mock.head "/people/99.xml", {}, nil, 404
|
||||
mock.head "/people/1/addresses/1.xml", {}, nil, 200
|
||||
mock.head "/people/1/addresses/2.xml", {}, nil, 404
|
||||
mock.head "/people/2/addresses/1.xml", {}, nil, 404
|
||||
mock.head "/people/Greg/addresses/1.xml", {}, nil, 200
|
||||
end
|
||||
|
||||
Person.user = nil
|
||||
Person.password = nil
|
||||
end
|
||||
def teardown
|
||||
Person.schema = nil # hack to stop test bleedthrough...
|
||||
end
|
||||
|
||||
|
||||
#####################################################
|
||||
# Passing in a schema directly and returning it
|
||||
####
|
||||
|
||||
test "schema on a new model should be empty" do
|
||||
assert Person.schema.blank?, "should have a blank class schema"
|
||||
assert Person.new.schema.blank?, "should have a blank instance schema"
|
||||
end
|
||||
|
||||
test "schema should only accept a hash" do
|
||||
["blahblah", ['one','two'], [:age, :name], Person.new].each do |bad_schema|
|
||||
assert_raises(ArgumentError,"should only accept a hash (or nil), but accepted: #{bad_schema.inspect}") do
|
||||
Person.schema = bad_schema
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "schema should accept a simple hash" do
|
||||
new_schema = {'age' => 'integer', 'name' => 'string'}
|
||||
|
||||
assert_nothing_raised { Person.schema = new_schema }
|
||||
assert_equal new_schema, Person.schema
|
||||
end
|
||||
|
||||
test "schema should accept a hash with simple values" do
|
||||
new_schema = {'age' => 'integer', 'name' => 'string', 'height' => 'float', 'mydatetime' => 'string'}
|
||||
|
||||
assert_nothing_raised { Person.schema = new_schema }
|
||||
assert_equal new_schema, Person.schema
|
||||
end
|
||||
|
||||
test "schema should accept all known attribute types as values" do
|
||||
# I'd prefer to use here...
|
||||
ActiveResource::Schema::KNOWN_ATTRIBUTE_TYPES.each do |the_type|
|
||||
assert_nothing_raised("should have accepted #{the_type.inspect}"){ Person.schema = {'my_key' => the_type }}
|
||||
end
|
||||
end
|
||||
|
||||
test "schema should not accept unknown values" do
|
||||
bad_values = [ :oogle, :blob, 'thing']
|
||||
|
||||
bad_values.each do |bad_value|
|
||||
assert_raises(ArgumentError,"should only accept a known attribute type, but accepted: #{bad_value.inspect}") do
|
||||
Person.schema = {'key' => bad_value}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "schema should accept nil and remove the schema" do
|
||||
new_schema = {'age' => 'integer', 'name' => 'string'}
|
||||
assert_nothing_raised { Person.schema = new_schema }
|
||||
assert_equal new_schema, Person.schema # sanity check
|
||||
|
||||
|
||||
assert_nothing_raised { Person.schema = nil }
|
||||
assert_nil Person.schema, "should have nulled out the schema, but still had: #{Person.schema.inspect}"
|
||||
end
|
||||
|
||||
|
||||
test "schema should be with indifferent access" do
|
||||
new_schema = {:age => :integer, 'name' => 'string'}
|
||||
new_schema_syms = new_schema.keys
|
||||
|
||||
assert_nothing_raised { Person.schema = new_schema }
|
||||
new_schema_syms.each do |col|
|
||||
assert Person.new.respond_to?(col.to_s), "should respond to the schema's string key, but failed on: #{col.to_s}"
|
||||
assert Person.new.respond_to?(col.to_sym), "should respond to the schema's symbol key, but failed on: #{col.to_sym}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
test "schema on a fetched resource should return all the attributes of that model instance" do
|
||||
p = Person.find(1)
|
||||
s = p.schema
|
||||
|
||||
assert s.present?, "should have found a non-empty schema!"
|
||||
|
||||
p.attributes.each do |the_attr, val|
|
||||
assert s.has_key?(the_attr), "should have found attr: #{the_attr} in schema, but only had: #{s.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
test "with two instances, default schema should match the attributes of the individual instances - even if they differ" do
|
||||
matz = Person.find(1)
|
||||
rick = Person.find(5)
|
||||
|
||||
m_attrs = matz.attributes.keys.sort
|
||||
r_attrs = rick.attributes.keys.sort
|
||||
|
||||
assert_not_equal m_attrs, r_attrs, "should have different attributes on each model"
|
||||
|
||||
assert_not_equal matz.schema, rick.schema, "should have had different schemas too"
|
||||
end
|
||||
|
||||
test "defining a schema should return it when asked" do
|
||||
assert Person.schema.blank?, "should have a blank class schema"
|
||||
new_schema = {'name' => 'string', 'age' => 'integer', 'height' => 'float', 'weight' => 'float'}
|
||||
assert_nothing_raised {
|
||||
Person.schema = new_schema
|
||||
assert_equal new_schema, Person.schema, "should have saved the schema on the class"
|
||||
assert_equal new_schema, Person.new.schema, "should have mde the schema available to every instance"
|
||||
}
|
||||
end
|
||||
|
||||
test "defining a schema, then fetching a model should still match the defined schema" do
|
||||
# sanity checks
|
||||
assert Person.schema.blank?, "should have a blank class schema"
|
||||
new_schema = {'name' => 'string', 'age' => 'integer', 'height' => 'float', 'weight' => 'float'}
|
||||
|
||||
matz = Person.find(1)
|
||||
assert !matz.schema.blank?, "should have some sort of schema on an instance variable"
|
||||
assert_not_equal new_schema, matz.schema, "should not have the class-level schema until it's been added to the class!"
|
||||
|
||||
assert_nothing_raised {
|
||||
Person.schema = new_schema
|
||||
assert_equal new_schema, matz.schema, "class-level schema should override instance-level schema"
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
#####################################################
|
||||
# Using the schema syntax
|
||||
####
|
||||
|
||||
test "should be able to use schema" do
|
||||
assert Person.respond_to?(:schema), "should at least respond to the schema method"
|
||||
|
||||
assert_nothing_raised("Should allow the schema to take a block") do
|
||||
Person.schema { }
|
||||
end
|
||||
end
|
||||
|
||||
test "schema definition should store and return attribute set" do
|
||||
assert_nothing_raised do
|
||||
s = nil
|
||||
Person.schema do
|
||||
s = self
|
||||
attribute :foo, :string
|
||||
end
|
||||
assert s.respond_to?(:attrs), "should return attributes in theory"
|
||||
assert_equal({'foo' => 'string' }, s.attrs, "should return attributes in practice")
|
||||
end
|
||||
end
|
||||
|
||||
test "should be able to add attributes through schema" do
|
||||
assert_nothing_raised do
|
||||
s = nil
|
||||
Person.schema do
|
||||
s = self
|
||||
attribute('foo', 'string')
|
||||
end
|
||||
assert s.attrs.has_key?('foo'), "should have saved the attribute name"
|
||||
assert_equal 'string', s.attrs['foo'], "should have saved the attribute type"
|
||||
end
|
||||
end
|
||||
|
||||
test "should convert symbol attributes to strings" do
|
||||
assert_nothing_raised do
|
||||
s = nil
|
||||
Person.schema do
|
||||
attribute(:foo, :integer)
|
||||
s = self
|
||||
end
|
||||
|
||||
assert s.attrs.has_key?('foo'), "should have saved the attribute name as a string"
|
||||
assert_equal 'integer', s.attrs['foo'], "should have saved the attribute type as a string"
|
||||
end
|
||||
end
|
||||
|
||||
test "should be able to add all known attribute types" do
|
||||
assert_nothing_raised do
|
||||
ActiveResource::Schema::KNOWN_ATTRIBUTE_TYPES.each do |the_type|
|
||||
s = nil
|
||||
Person.schema do
|
||||
s = self
|
||||
attribute('foo', the_type)
|
||||
end
|
||||
assert s.attrs.has_key?('foo'), "should have saved the attribute name"
|
||||
assert_equal the_type.to_s, s.attrs['foo'], "should have saved the attribute type of: #{the_type}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "attributes should not accept unknown values" do
|
||||
bad_values = [ :oogle, :blob, 'thing']
|
||||
|
||||
bad_values.each do |bad_value|
|
||||
s = nil
|
||||
assert_raises(ArgumentError,"should only accept a known attribute type, but accepted: #{bad_value.inspect}") do
|
||||
Person.schema do
|
||||
s = self
|
||||
attribute 'key', bad_value
|
||||
end
|
||||
end
|
||||
assert !self.respond_to?(bad_value), "should only respond to a known attribute type, but accepted: #{bad_value.inspect}"
|
||||
assert_raises(NoMethodError,"should only have methods for known attribute types, but accepted: #{bad_value.inspect}") do
|
||||
Person.schema do
|
||||
send bad_value, 'key'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
test "should accept attribute types as the type's name as the method" do
|
||||
ActiveResource::Schema::KNOWN_ATTRIBUTE_TYPES.each do |the_type|
|
||||
s = nil
|
||||
Person.schema do
|
||||
s = self
|
||||
send(the_type,'foo')
|
||||
end
|
||||
assert s.attrs.has_key?('foo'), "should now have saved the attribute name"
|
||||
assert_equal the_type.to_s, s.attrs['foo'], "should have saved the attribute type of: #{the_type}"
|
||||
end
|
||||
end
|
||||
|
||||
test "should accept multiple attribute names for an attribute method" do
|
||||
names = ['foo','bar','baz']
|
||||
s = nil
|
||||
Person.schema do
|
||||
s = self
|
||||
string(*names)
|
||||
end
|
||||
names.each do |the_name|
|
||||
assert s.attrs.has_key?(the_name), "should now have saved the attribute name: #{the_name}"
|
||||
assert_equal 'string', s.attrs[the_name], "should have saved the attribute as a string"
|
||||
end
|
||||
end
|
||||
|
||||
#####################################################
|
||||
# What a schema does for us
|
||||
####
|
||||
|
||||
# respond_to?
|
||||
|
||||
test "should respond positively to attributes that are only in the schema" do
|
||||
new_attr_name = :my_new_schema_attribute
|
||||
new_attr_name_two = :another_new_schema_attribute
|
||||
assert Person.schema.blank?, "sanity check - should have a blank class schema"
|
||||
|
||||
assert !Person.new.respond_do?(new_attr_name), "sanity check - should not respond to the brand-new attribute yet"
|
||||
assert !Person.new.respond_do?(new_attr_name_two), "sanity check - should not respond to the brand-new attribute yet"
|
||||
|
||||
assert_nothing_raised do
|
||||
Person.schema = {new_attr_name.to_s => 'string'}
|
||||
Person.schema { string new_attr_name_two }
|
||||
end
|
||||
|
||||
assert Person.new.respond_to?(new_attr_name), "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}"
|
||||
assert Person.new.respond_to?(new_attr_name_two), "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}"
|
||||
end
|
||||
|
||||
test "should not care about ordering of schema definitions" do
|
||||
new_attr_name = :my_new_schema_attribute
|
||||
new_attr_name_two = :another_new_schema_attribute
|
||||
|
||||
assert Person.schema.blank?, "sanity check - should have a blank class schema"
|
||||
|
||||
assert !Person.new.respond_do?(new_attr_name), "sanity check - should not respond to the brand-new attribute yet"
|
||||
assert !Person.new.respond_do?(new_attr_name_two), "sanity check - should not respond to the brand-new attribute yet"
|
||||
|
||||
assert_nothing_raised do
|
||||
Person.schema { string new_attr_name_two }
|
||||
Person.schema = {new_attr_name.to_s => 'string'}
|
||||
end
|
||||
|
||||
assert Person.new.respond_to?(new_attr_name), "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}"
|
||||
assert Person.new.respond_to?(new_attr_name_two), "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}"
|
||||
end
|
||||
|
||||
# method_missing effects
|
||||
|
||||
test "should not give method_missing for attribute only in schema" do
|
||||
new_attr_name = :another_new_schema_attribute
|
||||
new_attr_name_two = :another_new_schema_attribute
|
||||
|
||||
assert Person.schema.blank?, "sanity check - should have a blank class schema"
|
||||
|
||||
assert_raises(NoMethodError, "should not have found the attribute: #{new_attr_name} as a method") do
|
||||
Person.new.send(new_attr_name)
|
||||
end
|
||||
assert_raises(NoMethodError, "should not have found the attribute: #{new_attr_name_two} as a method") do
|
||||
Person.new.send(new_attr_name_two)
|
||||
end
|
||||
|
||||
Person.schema = {new_attr_name.to_s => :float}
|
||||
Person.schema { string new_attr_name_two }
|
||||
|
||||
assert_nothing_raised do
|
||||
Person.new.send(new_attr_name)
|
||||
Person.new.send(new_attr_name_two)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
########
|
||||
# Known attributes
|
||||
#
|
||||
# Attributes can be known to be attributes even if they aren't actually
|
||||
# 'set' on a particular instance.
|
||||
# This will only differ from 'attributes' if a schema has been set.
|
||||
|
||||
test "new model should have no known attributes" do
|
||||
assert Person.known_attributes.blank?, "should have no known attributes"
|
||||
assert Person.new.known_attributes.blank?, "should have no known attributes on a new instance"
|
||||
end
|
||||
|
||||
test "setting schema should set known attributes on class and instance" do
|
||||
new_schema = {'age' => 'integer', 'name' => 'string'}
|
||||
|
||||
assert_nothing_raised { Person.schema = new_schema }
|
||||
|
||||
assert_equal new_schema.keys, Person.known_attributes
|
||||
assert_equal new_schema.keys, Person.new.known_attributes
|
||||
end
|
||||
|
||||
test "known attributes on a fetched resource should return all the attributes of the instance" do
|
||||
p = Person.find(1)
|
||||
attrs = p.known_attributes
|
||||
|
||||
assert attrs.present?, "should have found some attributes!"
|
||||
|
||||
p.attributes.each do |the_attr, val|
|
||||
assert attrs.include?(the_attr), "should have found attr: #{the_attr} in known attributes, but only had: #{attrs.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
test "with two instances, known attributes should match the attributes of the individual instances - even if they differ" do
|
||||
matz = Person.find(1)
|
||||
rick = Person.find(5)
|
||||
|
||||
m_attrs = matz.attributes.keys.sort
|
||||
r_attrs = rick.attributes.keys.sort
|
||||
|
||||
assert_not_equal m_attrs, r_attrs, "should have different attributes on each model"
|
||||
|
||||
assert_not_equal matz.known_attributes, rick.known_attributes, "should have had different known attributes too"
|
||||
end
|
||||
|
||||
test "setting schema then fetching should add schema attributes to the intance attributes" do
|
||||
# an attribute in common with fetched instance and one that isn't
|
||||
new_schema = {'name' => 'string', 'my_strange_attribute' => 'string'}
|
||||
|
||||
assert_nothing_raised { Person.schema = new_schema }
|
||||
|
||||
matz = Person.find(1)
|
||||
known_attrs = matz.known_attributes
|
||||
|
||||
matz.attributes.keys.each do |the_attr|
|
||||
assert known_attrs.include?(the_attr), "should have found instance attr: #{the_attr} in known attributes, but only had: #{known_attrs.inspect}"
|
||||
end
|
||||
new_schema.keys.each do |the_attr|
|
||||
assert known_attrs.include?(the_attr), "should have found schema attr: #{the_attr} in known attributes, but only had: #{known_attrs.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -1,3 +1,4 @@
|
||||
require 'date'
|
||||
require 'active_support/duration'
|
||||
require 'active_support/core_ext/time/zones'
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
require 'date'
|
||||
require 'active_support/inflector'
|
||||
|
||||
class Date
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
require 'active_support/duration'
|
||||
require 'active_support/core_ext/date/acts_like'
|
||||
require 'active_support/core_ext/date/calculations'
|
||||
|
||||
class Time
|
||||
|
||||
@@ -14,5 +14,6 @@ require 'active_support/core_ext/date_time/conversions'
|
||||
require 'active_support/core_ext/enumerable'
|
||||
require 'active_support/core_ext/process/daemon'
|
||||
require 'active_support/core_ext/string/conversions'
|
||||
require 'active_support/core_ext/string/interpolation'
|
||||
require 'active_support/core_ext/rexml'
|
||||
require 'active_support/core_ext/time/conversions'
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
# Likewise, all the methods added will be available for all controllers.
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
helper :all # include all helpers, all the time
|
||||
protect_from_forgery # See ActionController::RequestForgeryProtection for details
|
||||
|
||||
# Scrub sensitive parameters from your log
|
||||
# filter_parameter_logging :password
|
||||
helper :all
|
||||
protect_from_forgery
|
||||
filter_parameter_logging :password, :password_confirmation
|
||||
end
|
||||
|
||||
@@ -3,7 +3,7 @@ ActionController::Routing::Routes.draw do |map|
|
||||
# first created -> highest priority.
|
||||
|
||||
# Sample of regular route:
|
||||
# match 'products/:id', :to => 'catalog#view'
|
||||
# match 'products/:id' => 'catalog#view'
|
||||
# Keep in mind you can assign values other than :controller and :action
|
||||
|
||||
# Sample of named route:
|
||||
@@ -52,9 +52,7 @@ ActionController::Routing::Routes.draw do |map|
|
||||
|
||||
# See how all your routes lay out with "rake routes"
|
||||
|
||||
# Install the default route as the lowest priority.
|
||||
# Note: The default route make all actions in every controller accessible
|
||||
# via GET requests. You should consider removing or commenting it out if
|
||||
# you're using named routes and resources.
|
||||
match ':controller(/:action(/:id(.:format)))'
|
||||
# This is a legacy wild controller route that's not recommended for RESTful applications.
|
||||
# Note: This route will make all actions in every controller accessible via GET requests.
|
||||
# match ':controller(/:action(/:id(.:format)))'
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user