diff --git a/README.rdoc b/README.rdoc index 0b209cf56f247..216a122c66cf7 100644 --- a/README.rdoc +++ b/README.rdoc @@ -48,7 +48,7 @@ more separate. Each of these packages can be used independently outside of "Welcome aboard: You're riding Ruby on Rails!" -5. Follow the guidelines to start developing your application. You can find the following resources handy: +5. Follow the guidelines to start developing your application. You may find the following resources handy: * The README file created within your application. * The {Getting Started with Rails}[http://guides.rubyonrails.org/getting_started.html]. diff --git a/actionmailer/README.rdoc b/actionmailer/README.rdoc index 0fa18d751b231..9b206fbcc7d4f 100644 --- a/actionmailer/README.rdoc +++ b/actionmailer/README.rdoc @@ -32,7 +32,7 @@ This can be as simple as: end The body of the email is created by using an Action View template (regular -ERb) that has the instance variables that are declared in the mailer action. +ERB) that has the instance variables that are declared in the mailer action. So the corresponding body template for the method above could look like this: @@ -72,6 +72,19 @@ Or you can just chain the methods together like: Notifier.welcome.deliver # Creates the email and sends it immediately +== Setting defaults + +It is possible to set default values that will be used in every method in your Action Mailer class. To implement this functionality, you just call the public class method default which you get for free from ActionMailer::Base. This method accepts a Hash as the parameter. You can use any of the headers e-mail messages has, like :from as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer does this out of the box for you, so you wont need to worry about that. Finally it is also possible to pass in a Proc that will get evaluated when it is needed. + +Note that every value you set with this method will get over written if you use the same key in your mailer method. + +Example: + + class Authenticationmailer < ActionMailer::Base + default :from => "awesome@application.com", :subject => Proc.new { "E-mail was generated at #{Time.now}" } + ..... + end + == Receiving emails To receive emails, you need to implement a public instance method called receive that takes an diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index 2ae85f8b5757d..ee02cf69459a2 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -17,8 +17,6 @@ Gem::Specification.new do |s| s.require_path = 'lib' s.requirements << 'none' - s.has_rdoc = true - s.add_dependency('actionpack', version) s.add_dependency('mail', '~> 2.2.15') end diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 16fcf112b7909..cd7638393141a 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -4,6 +4,7 @@ require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/proc' +require 'active_support/core_ext/string/inflections' require 'action_mailer/log_subscriber' module ActionMailer #:nodoc: @@ -349,9 +350,6 @@ class Base < AbstractController::Base helper ActionMailer::MailHelper include ActionMailer::OldApi - delegate :register_observer, :to => Mail - delegate :register_interceptor, :to => Mail - private_class_method :new #:nodoc: class_attribute :default_params @@ -363,6 +361,32 @@ class Base < AbstractController::Base }.freeze class << self + # Register one or more Observers which will be notified when mail is delivered. + def register_observers(*observers) + observers.flatten.compact.each { |observer| register_observer(observer) } + end + + # Register one or more Interceptors which will be called before mail is sent. + def register_interceptors(*interceptors) + interceptors.flatten.compact.each { |interceptor| register_interceptor(interceptor) } + end + + # Register an Observer which will be notified when mail is delivered. + # Either a class or a string can be passed in as the Observer. If a string is passed in + # it will be constantized. + def register_observer(observer) + delivery_observer = (observer.is_a?(String) ? observer.constantize : observer) + Mail.register_observer(delivery_observer) + end + + # Register an Inteceptor which will be called before mail is sent. + # Either a class or a string can be passed in as the Observer. If a string is passed in + # it will be constantized. + def register_interceptor(interceptor) + delivery_interceptor = (interceptor.is_a?(String) ? interceptor.constantize : interceptor) + Mail.register_interceptor(delivery_interceptor) + end + def mailer_name @mailer_name ||= name.underscore end diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb index 4ec478067ff86..444754d0e9f37 100644 --- a/actionmailer/lib/action_mailer/railtie.rb +++ b/actionmailer/lib/action_mailer/railtie.rb @@ -19,13 +19,17 @@ class Railtie < Rails::Railtie options.stylesheets_dir ||= paths["public/stylesheets"].first # make sure readers methods get compiled - options.asset_path ||= app.config.asset_path - options.asset_host ||= app.config.asset_host + options.asset_path ||= app.config.asset_path + options.asset_host ||= app.config.asset_host ActiveSupport.on_load(:action_mailer) do include AbstractController::UrlFor extend ::AbstractController::Railties::RoutesHelpers.with(app.routes) include app.routes.mounted_helpers + + register_interceptors(options.delete(:interceptors)) + register_observers(options.delete(:observers)) + options.each { |k,v| send("#{k}=", v) } end end diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb index 6a7931da8c268..9fdd0e1cedf81 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -478,6 +478,11 @@ def self.delivered_email(mail) end end + class MySecondObserver + def self.delivered_email(mail) + end + end + test "you can register an observer to the mail object that gets informed on email delivery" do ActionMailer::Base.register_observer(MyObserver) mail = BaseMailer.welcome @@ -485,11 +490,31 @@ def self.delivered_email(mail) mail.deliver end + test "you can register an observer using its stringified name to the mail object that gets informed on email delivery" do + ActionMailer::Base.register_observer("BaseTest::MyObserver") + mail = BaseMailer.welcome + MyObserver.expects(:delivered_email).with(mail) + mail.deliver + end + + test "you can register multiple observers to the mail object that both get informed on email delivery" do + ActionMailer::Base.register_observers("BaseTest::MyObserver", MySecondObserver) + mail = BaseMailer.welcome + MyObserver.expects(:delivered_email).with(mail) + MySecondObserver.expects(:delivered_email).with(mail) + mail.deliver + end + class MyInterceptor def self.delivering_email(mail) end end + class MySecondInterceptor + def self.delivering_email(mail) + end + end + test "you can register an interceptor to the mail object that gets passed the mail object before delivery" do ActionMailer::Base.register_interceptor(MyInterceptor) mail = BaseMailer.welcome @@ -497,6 +522,21 @@ def self.delivering_email(mail) mail.deliver end + test "you can register an interceptor using its stringified name to the mail object that gets passed the mail object before delivery" do + ActionMailer::Base.register_interceptor("BaseTest::MyInterceptor") + mail = BaseMailer.welcome + MyInterceptor.expects(:delivering_email).with(mail) + mail.deliver + end + + test "you can register multiple interceptors to the mail object that both get passed the mail object before delivery" do + ActionMailer::Base.register_interceptors("BaseTest::MyInterceptor", MySecondInterceptor) + mail = BaseMailer.welcome + MyInterceptor.expects(:delivering_email).with(mail) + MySecondInterceptor.expects(:delivering_email).with(mail) + mail.deliver + end + test "being able to put proc's into the defaults hash and they get evaluated on mail sending" do mail1 = ProcMailer.welcome yesterday = 1.day.ago diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 3eba2281c42e7..25e2d27a01dd1 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.1.0 (unreleased)* +* Implicit actions named not_implemented can be rendered [Santiago Pastorino] + * Wildcard route will always matching the optional format segment by default. For example if you have this route: map '*pages' => 'pages#show' diff --git a/actionpack/README.rdoc b/actionpack/README.rdoc index 3661d27d51465..b900962d32c52 100644 --- a/actionpack/README.rdoc +++ b/actionpack/README.rdoc @@ -19,7 +19,7 @@ It consists of several modules: * Action View, which handles view template lookup and rendering, and provides view helpers that assist when building HTML forms, Atom feeds and more. - Template formats that Action View handles are ERb (embedded Ruby, typically + Template formats that Action View handles are ERB (embedded Ruby, typically used to inline short Ruby snippets inside HTML), XML Builder and RJS (dynamically generated JavaScript from Ruby code). @@ -57,7 +57,7 @@ A short rundown of some of the major features: {Learn more}[link:classes/ActionController/Base.html] -* ERb templates (static content mixed with dynamic output from ruby) +* ERB templates (static content mixed with dynamic output from ruby) <% for post in @posts %> Title: <%= post.title %> diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 651f3b164ac66..d3c66800d9b36 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -17,8 +17,6 @@ Gem::Specification.new do |s| s.require_path = 'lib' s.requirements << 'none' - s.has_rdoc = true - s.add_dependency('activesupport', version) s.add_dependency('activemodel', version) s.add_dependency('rack-cache', '~> 1.0.0') @@ -28,5 +26,5 @@ Gem::Specification.new do |s| s.add_dependency('rack-test', '~> 0.5.7') s.add_dependency('rack-mount', '~> 0.7.1') s.add_dependency('tzinfo', '~> 0.3.23') - s.add_dependency('erubis', '~> 2.6.6') + s.add_dependency('erubis', '~> 2.7.0') end diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index 07ff5ad9f353d..0951267fea63a 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -1,3 +1,4 @@ +require 'erubis' require 'active_support/configurable' require 'active_support/descendants_tracker' require 'active_support/core_ext/module/anonymous' @@ -18,6 +19,7 @@ class Base include ActiveSupport::Configurable extend ActiveSupport::DescendantsTracker + undef_method :not_implemented class << self attr_reader :abstract alias_method :abstract?, :abstract diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index 95992c2698ad2..f7b2b7ff53d18 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -29,7 +29,7 @@ module ClassMethods # # ==== Options # * only - The callback should be run only for this action - # * except - The callback should be run for all actions except this action + # * except - The callback should be run for all actions except this action def _normalize_callback_options(options) if only = options[:only] only = Array(only).map {|o| "action_name == '#{o}'"}.join(" || ") diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index e6523e56d20d1..5f9e082cd3ac6 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -105,7 +105,7 @@ module ActionController # == Renders # # Action Controller sends content to the user by using one of five rendering methods. The most versatile and common is the rendering - # of a template. Included in the Action Pack is the Action View, which enables rendering of ERb templates. It's automatically configured. + # of a template. Included in the Action Pack is the Action View, which enables rendering of ERB templates. It's automatically configured. # The controller passes objects to the view by assigning instance variables: # # def show @@ -128,7 +128,7 @@ module ActionController # end # end # - # Read more about writing ERb and Builder templates in ActionView::Base. + # Read more about writing ERB and Builder templates in ActionView::Base. # # == Redirects # diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index e5db31061b256..585bd5e5abd5f 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -201,19 +201,23 @@ def to_a #:nodoc: class_attribute :middleware_stack self.middleware_stack = ActionController::MiddlewareStack.new - def self.inherited(base) + def self.inherited(base) #nodoc: base.middleware_stack = self.middleware_stack.dup super end + # Adds given middleware class and its args to bottom of middleware_stack def self.use(*args, &block) middleware_stack.use(*args, &block) end + # Alias for middleware_stack def self.middleware middleware_stack end + # Makes the controller a rack endpoint that points to the action in + # the given env's action_dispatch.request.path_parameters key. def self.call(env) action(env['action_dispatch.request.path_parameters'][:action]).call(env) end diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index b98429792d7a2..1d6df89007520 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -67,7 +67,7 @@ module HttpAuthentication # class PostsController < ApplicationController # REALM = "SuperSecret" # USERS = {"dhh" => "secret", #plain text password - # "dap" => Digest:MD5::hexdigest(["dap",REALM,"secret"].join(":")) #ha1 digest password + # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":")) #ha1 digest password # # before_filter :authenticate, :except => [:index] # diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb index 678f4ca763451..3ec0c4c6a4b50 100644 --- a/actionpack/lib/action_controller/metal/implicit_render.rb +++ b/actionpack/lib/action_controller/metal/implicit_render.rb @@ -10,8 +10,8 @@ def send_action(method, *args) end end - def default_render - render + def default_render(*args) + render(*args) end def action_method?(action_name) diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index a2e06fe0a65d7..618a6cdb7d5ce 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -1,8 +1,9 @@ require 'abstract_controller/collector' require 'active_support/core_ext/class/attribute' +require 'active_support/core_ext/object/inclusion' module ActionController #:nodoc: - module MimeResponds #:nodoc: + module MimeResponds extend ActiveSupport::Concern included do @@ -189,7 +190,7 @@ def respond_to(*mimes, &block) raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given? if response = retrieve_response_from_mimes(mimes, &block) - response.call + response.call(nil) end end @@ -222,6 +223,9 @@ def respond_to(*mimes, &block) # is quite simple (it just needs to respond to call), you can even give # a proc to it. # + # In order to use respond_with, first you need to declare the formats your + # controller responds to in the class level with a call to respond_to. + # def respond_with(*resources, &block) raise "In order to use respond_with, first you need to declare the formats your " << "controller responds to in the class level" if self.class.mimes_for_respond_to.empty? @@ -245,9 +249,9 @@ def collect_mimes_from_class_level #:nodoc: config = self.class.mimes_for_respond_to[mime] if config[:except] - !config[:except].include?(action) + !action.in?(config[:except]) elsif config[:only] - config[:only].include?(action) + action.in?(config[:only]) else true end @@ -257,9 +261,9 @@ def collect_mimes_from_class_level #:nodoc: # Collects mimes and return the response for the negotiated format. Returns # nil if :not_acceptable was sent to the client. # - def retrieve_response_from_mimes(mimes=nil, &block) + def retrieve_response_from_mimes(mimes=nil, &block) #:nodoc: mimes ||= collect_mimes_from_class_level - collector = Collector.new(mimes) { default_render } + collector = Collector.new(mimes) { |options| default_render(options || {}) } block.call(collector) if block_given? if format = request.negotiate_mime(collector.order) diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index 4b45413cf8005..59a3621f72cb1 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -77,6 +77,37 @@ module ActionController #:nodoc: # # respond_with(@project, :manager, @task) # + # === Custom options + # + # respond_with also allow you to pass options that are forwarded + # to the underlying render call. Those options are only applied success + # scenarios. For instance, you can do the following in the create method above: + # + # def create + # @project = Project.find(params[:project_id]) + # @task = @project.comments.build(params[:task]) + # flash[:notice] = 'Task was successfully created.' if @task.save + # respond_with(@project, @task, :status => 201) + # end + # + # This will return status 201 if the task was saved with success. If not, + # it will simply ignore the given options and return status 422 and the + # resource errors. To customize the failure scenario, you can pass a + # a block to respond_with: + # + # def create + # @project = Project.find(params[:project_id]) + # @task = @project.comments.build(params[:task]) + # respond_with(@project, @task, :status => 201) do |format| + # if @task.save + # flash[:notice] = 'Task was successfully created.' + # else + # format.html { render "some_special_template" } + # end + # end + # end + # + # Using respond_with with a block follows the same syntax as respond_to. class Responder attr_reader :controller, :request, :format, :resource, :resources, :options @@ -131,7 +162,11 @@ def to_html # responds to :to_format and display it. # def to_format - default_render + if get? || !has_errors? + default_render + else + display_errors + end rescue ActionView::MissingTemplate => e api_behavior(e) end @@ -155,8 +190,6 @@ def api_behavior(error) if get? display resource - elsif has_errors? - display resource.errors, :status => :unprocessable_entity elsif post? display resource, :status => :created, :location => api_location elsif has_empty_resource_definition? @@ -185,7 +218,7 @@ def resource_location # controller. # def default_render - @default_response.call + @default_response.call(options) end # Display is just a shortcut to render a resource with the current format. @@ -209,6 +242,10 @@ def display(resource, given_options={}) controller.render given_options.merge!(options).merge!(format => resource) end + def display_errors + controller.render format => resource.errors, :status => :unprocessable_entity + end + # Check whether the resource has errors. # def has_errors? diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 49971fc9f88a1..7f972fc2816d6 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -60,6 +60,7 @@ module ActionDispatch autoload :Static end + autoload :ClosedError, 'action_dispatch/middleware/closed_error' autoload :MiddlewareStack, 'action_dispatch/middleware/stack' autoload :Routing diff --git a/actionpack/lib/action_dispatch/middleware/closed_error.rb b/actionpack/lib/action_dispatch/middleware/closed_error.rb new file mode 100644 index 0000000000000..0a4db47f4b87b --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/closed_error.rb @@ -0,0 +1,7 @@ +module ActionDispatch + class ClosedError < StandardError #:nodoc: + def initialize(kind) + super "Cannot modify #{kind} because it was closed. This means it was already streamed back to the client or converted to HTTP headers." + end + end +end diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 7ac608f0a8977..24ebb8fed71bc 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -83,7 +83,7 @@ class Cookies # Raised when storing more than 4K of session data. class CookieOverflow < StandardError; end - class CookieJar < Hash #:nodoc: + class CookieJar #:nodoc: # This regular expression is used to split the levels of a domain. # The top level domain can be any string without a period or @@ -115,13 +115,22 @@ def initialize(secret = nil, host = nil, secure = false) @delete_cookies = {} @host = host @secure = secure - - super() + @closed = false + @cookies = {} end + attr_reader :closed + alias :closed? :closed + def close!; @closed = true end + # Returns the value of the cookie by +name+, or +nil+ if no such cookie exists. def [](name) - super(name.to_s) + @cookies[name.to_s] + end + + def update(other_hash) + @cookies.update other_hash + self end def handle_options(options) #:nodoc: @@ -145,6 +154,7 @@ def handle_options(options) #:nodoc: # Sets the cookie named +name+. The second argument may be the very cookie # value, or a hash of options as documented above. def []=(key, options) + raise ClosedError, :cookies if closed? if options.is_a?(Hash) options.symbolize_keys! value = options[:value] @@ -153,7 +163,7 @@ def []=(key, options) options = { :value => value } end - value = super(key.to_s, value) + value = @cookies[key.to_s] = value handle_options(options) @@ -170,7 +180,7 @@ def delete(key, options = {}) handle_options(options) - value = super(key.to_s) + value = @cookies.delete(key.to_s) @delete_cookies[key] = options value end @@ -225,6 +235,7 @@ def initialize(parent_jar, secret) end def []=(key, options) + raise ClosedError, :cookies if closed? if options.is_a?(Hash) options.symbolize_keys! else @@ -263,6 +274,7 @@ def [](name) end def []=(key, options) + raise ClosedError, :cookies if closed? if options.is_a?(Hash) options.symbolize_keys! options[:value] = @verifier.generate(options[:value]) @@ -305,6 +317,7 @@ def initialize(app) end def call(env) + cookie_jar = nil status, headers, body = @app.call(env) if cookie_jar = env['action_dispatch.cookies'] @@ -315,6 +328,9 @@ def call(env) end [status, headers, body] + ensure + cookie_jar = ActionDispatch::Request.new(env).cookie_jar unless cookie_jar + cookie_jar.close! end end end diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb index 21aeeb217afec..027ff7f8ac5d1 100644 --- a/actionpack/lib/action_dispatch/middleware/flash.rb +++ b/actionpack/lib/action_dispatch/middleware/flash.rb @@ -43,9 +43,15 @@ class Flash class FlashNow #:nodoc: def initialize(flash) @flash = flash + @closed = false end + attr_reader :closed + alias :closed? :closed + def close!; @closed = true end + def []=(k, v) + raise ClosedError, :flash if closed? @flash[k] = v @flash.discard(k) v @@ -66,27 +72,70 @@ def notice=(message) end end - class FlashHash < Hash + class FlashHash + include Enumerable + def initialize #:nodoc: - super - @used = Set.new + @used = Set.new + @closed = false + @flashes = {} end + attr_reader :closed + alias :closed? :closed + def close!; @closed = true end + def []=(k, v) #:nodoc: + raise ClosedError, :flash if closed? keep(k) - super + @flashes[k] = v + end + + def [](k) + @flashes[k] end def update(h) #:nodoc: h.keys.each { |k| keep(k) } - super + @flashes.update h + self + end + + def keys + @flashes.keys + end + + def key?(name) + @flashes.key? name + end + + def delete(key) + @flashes.delete key + self + end + + def to_hash + @flashes.dup + end + + def empty? + @flashes.empty? + end + + def clear + @flashes.clear + end + + def each(&block) + @flashes.each(&block) end alias :merge! :update def replace(h) #:nodoc: @used = Set.new - super + @flashes.replace h + self end # Sets a flash that will not be available to the next action, only to the current. @@ -100,7 +149,7 @@ def replace(h) #:nodoc: # # Entries set via now are accessed the same way as standard entries: flash['my-key']. def now - FlashNow.new(self) + @now ||= FlashNow.new(self) end # Keeps either the entire current flash or a specific flash entry available for the next action: @@ -184,8 +233,11 @@ def call(env) session = env['rack.session'] || {} flash_hash = env['action_dispatch.request.flash_hash'] - if flash_hash && (!flash_hash.empty? || session.key?('flash')) + if flash_hash + if !flash_hash.empty? || session.key?('flash') session["flash"] = flash_hash + end + flash_hash.close! end if session.key?('flash') && session['flash'].empty? diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 35be0b3a27982..13aef18ee1268 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1,6 +1,7 @@ require 'erb' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/object/inclusion' require 'active_support/inflector' require 'action_dispatch/routing/redirection' @@ -1345,11 +1346,11 @@ def scope_action_options #:nodoc: end def resource_scope? #:nodoc: - [:resource, :resources].include?(@scope[:scope_level]) + @scope[:scope_level].among?(:resource, :resources) end def resource_method_scope? #:nodoc: - [:collection, :member, :new].include?(@scope[:scope_level]) + @scope[:scope_level].among?(:collection, :member, :new) end def with_exclusive_scope diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 77a15f3e97943..16a6b93ce8e38 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/object/inclusion' + module ActionDispatch module Assertions # A small suite of assertions that test responses from \Rails applications. @@ -33,7 +35,7 @@ module ResponseAssertions def assert_response(type, message = nil) validate_request! - if [ :success, :missing, :redirect, :error ].include?(type) && @response.send("#{type}?") + if type.among?(:success, :missing, :redirect, :error) && @response.send("#{type}?") assert_block("") { true } # to count the assertion elsif type.is_a?(Fixnum) && @response.response_code == type assert_block("") { true } # to count the assertion diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 2b862fb7d68ed..f41d3e5ddba6a 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -1,4 +1,5 @@ require 'action_controller/vendor/html-scanner' +require 'active_support/core_ext/object/inclusion' #-- # Copyright (c) 2006 Assaf Arkin (http://labnotes.org) @@ -441,7 +442,7 @@ def assert_select_rjs(*args, &block) if matches assert_block("") { true } # to count the assertion - if block_given? && !([:remove, :show, :hide, :toggle].include? rjs_type) + if block_given? && !rjs_type.among?(:remove, :show, :hide, :toggle) begin @selected ||= nil in_scope, @selected = @selected, matches diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 5c6416a19e37b..174babb9aae6c 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -1,6 +1,7 @@ require 'stringio' require 'uri' require 'active_support/core_ext/kernel/singleton_class' +require 'active_support/core_ext/object/inclusion' require 'active_support/core_ext/object/try' require 'rack/test' require 'test/unit/assertions' @@ -26,31 +27,31 @@ module RequestHelpers # object's @response instance variable will point to the same # response object. # - # You can also perform POST, PUT, DELETE, and HEAD requests with +post+, - # +put+, +delete+, and +head+. + # You can also perform POST, PUT, DELETE, and HEAD requests with +#post+, + # +#put+, +#delete+, and +#head+. def get(path, parameters = nil, headers = nil) process :get, path, parameters, headers end - # Performs a POST request with the given parameters. See get() for more + # Performs a POST request with the given parameters. See +#get+ for more # details. def post(path, parameters = nil, headers = nil) process :post, path, parameters, headers end - # Performs a PUT request with the given parameters. See get() for more + # Performs a PUT request with the given parameters. See +#get+ for more # details. def put(path, parameters = nil, headers = nil) process :put, path, parameters, headers end - # Performs a DELETE request with the given parameters. See get() for + # Performs a DELETE request with the given parameters. See +#get+ for # more details. def delete(path, parameters = nil, headers = nil) process :delete, path, parameters, headers end - # Performs a HEAD request with the given parameters. See get() for more + # Performs a HEAD request with the given parameters. See +#get+ for more # details. def head(path, parameters = nil, headers = nil) process :head, path, parameters, headers @@ -59,7 +60,7 @@ def head(path, parameters = nil, headers = nil) # Performs an XMLHttpRequest request with the given parameters, mirroring # a request from the Prototype library. # - # The request_method is :get, :post, :put, :delete or :head; the + # The request_method is +:get+, +:post+, +:put+, +:delete+ or +:head+; the # parameters are +nil+, a hash, or a url-encoded or multipart string; # the headers are a hash. Keys are automatically upcased and prefixed # with 'HTTP_' if not already. @@ -243,7 +244,8 @@ def _mock_session end # Performs the actual request. - def process(method, path, parameters = nil, rack_environment = nil) + def process(method, path, parameters = nil, env = nil) + env ||= {} if path =~ %r{://} location = URI.parse(path) https! URI::HTTPS === location if location.scheme @@ -259,7 +261,7 @@ def process(method, path, parameters = nil, rack_environment = nil) hostname, port = host.split(':') - env = { + default_env = { :method => method, :params => parameters, @@ -277,9 +279,7 @@ def process(method, path, parameters = nil, rack_environment = nil) session = Rack::Test::Session.new(_mock_session) - (rack_environment || {}).each do |key, value| - env[key] = value - end + env.reverse_merge!(default_env) # NOTE: rack-test v0.5 doesn't build a default uri correctly # Make sure requested path is always a full uri @@ -321,7 +321,7 @@ def reset! define_method(method) do |*args| reset! unless integration_session # reset the html_document variable, but only for new get/post calls - @html_document = nil unless %w(cookies assigns).include?(method) + @html_document = nil unless method.among?("cookies", "assigns") integration_session.__send__(method, *args).tap do copy_session_variables! end @@ -384,7 +384,7 @@ def integration_session end end - # An test that spans multiple controllers and actions, + # An integration test spans multiple controllers and actions, # tying them all together to ensure they work together as expected. It tests # more completely than either unit or functional tests do, exercising the # entire stack, from the dispatcher to the database. diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index ab8c6259c5461..55191036276d3 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -8,13 +8,13 @@ module ActionView #:nodoc: # = Action View Base # - # Action View templates can be written in three ways. If the template file has a .erb (or .rhtml) extension then it uses a mixture of ERb + # Action View templates can be written in three ways. If the template file has a .erb (or .rhtml) extension then it uses a mixture of ERB # (included in Ruby) and HTML. If the template file has a .builder (or .rxml) extension then Jim Weirich's Builder::XmlMarkup library is used. # If the template file has a .rjs extension then it will use ActionView::Helpers::PrototypeHelper::JavaScriptGenerator. # - # == ERb + # == ERB # - # You trigger ERb by using embeddings such as <% %>, <% -%>, and <%= %>. The <%= %> tag set is used when you want output. Consider the + # You trigger ERB by using embeddings such as <% %>, <% -%>, and <%= %>. The <%= %> tag set is used when you want output. Consider the # following loop for names: # # Names of all the people @@ -23,7 +23,7 @@ module ActionView #:nodoc: # <% end %> # # The loop is setup in regular embedding tags <% %> and the name is written using the output embedding tag <%= %>. Note that this - # is not just a usage suggestion. Regular output functions like print or puts won't work with ERb templates. So this would be wrong: + # is not just a usage suggestion. Regular output functions like print or puts won't work with ERB templates. So this would be wrong: # # <%# WRONG %> # Hi, Mr. <% puts "Frodo" %> @@ -81,7 +81,7 @@ module ActionView #:nodoc: # # == Builder # - # Builder templates are a more programmatic alternative to ERb. They are especially useful for generating XML content. An XmlMarkup object + # Builder templates are a more programmatic alternative to ERB. They are especially useful for generating XML content. An XmlMarkup object # named +xml+ is automatically made available to templates with a .builder extension. # # Here are some basic examples: diff --git a/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/actionpack/lib/action_view/helpers/atom_feed_helper.rb index db9d7a08ff637..96e572225285a 100644 --- a/actionpack/lib/action_view/helpers/atom_feed_helper.rb +++ b/actionpack/lib/action_view/helpers/atom_feed_helper.rb @@ -4,7 +4,7 @@ module ActionView # = Action View Atom Feed Helpers module Helpers #:nodoc: module AtomFeedHelper - # Adds easy defaults to writing Atom feeds with the Builder template engine (this does not work on ERb or any other + # Adds easy defaults to writing Atom feeds with the Builder template engine (this does not work on ERB or any other # template languages). # # Full usage example: diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index c88bd1efd5b2a..9ac7dff1ec5cd 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -14,7 +14,7 @@ module CaptureHelper # variable. You can then use this variable anywhere in your templates or layout. # # ==== Examples - # The capture method can be used in ERb templates... + # The capture method can be used in ERB templates... # # <% @greeting = capture do %> # Welcome to my shiny new web page! The date and time is diff --git a/actionpack/lib/action_view/helpers/csrf_helper.rb b/actionpack/lib/action_view/helpers/csrf_helper.rb index 65c8debc76bbf..1f2bc28cac5f8 100644 --- a/actionpack/lib/action_view/helpers/csrf_helper.rb +++ b/actionpack/lib/action_view/helpers/csrf_helper.rb @@ -17,10 +17,12 @@ module CsrfHelper # Note that regular forms generate hidden fields, and that Ajax calls are whitelisted, # so they do not use these tags. def csrf_meta_tags - <<-METAS.strip_heredoc.chomp.html_safe if protect_against_forgery? - - - METAS + if protect_against_forgery? + [ + tag('meta', :name => 'csrf-param', :content => request_forgery_protection_token), + tag('meta', :name => 'csrf-token', :content => form_authenticity_token) + ].join("\n").html_safe + end end # For backwards compatibility. diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 18e303778c219..506db24dc236d 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -584,7 +584,7 @@ def update_page(&block) # Works like update_page but wraps the generated JavaScript in a # \