Merge branch 'master' of github.com:lifo/docrails
* 'master' of github.com:lifo/docrails: (57 commits) Made the defaults section a little more readable and more to the point, giving a overview of the possibilities. Added information about default values added .'s to headings in the initialization textile page s/ERb/ERB/g (part II) s/ERb/ERB/g Bump up erubis to 2.7.0 Implicit actions named not_implemented can be rendered Gem::Specification#has_rdoc= is deprecated since rubygems 1.7.0 default_executable is deprecated since rubygems 1.7.0 Trivial fix to HTTP Digest auth MD5 example Moved Turn activation/dependency to railties fix typo Direct logging of Active Record to STDOUT so it's shown inline with the results in the console [DHH] Add using Turn with natural language test case names if the library is available (which it will be in Rails 3.1) [DHH] require turn only for minitest Use Turn to format all Rails tests and enable the natural language case names Improve docs. pass respond_with options to controller render when using a template for api navigation only try to display an api template in responders if the request is a get or there are no errors when using respond_with with an invalid resource and custom options, the default response status and error messages should be returned ...
This commit is contained in:
commit
92e6255b58
@ -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 <tt>default</tt> 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 <tt>:from</tt> 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 <tt>receive</tt> that takes an
|
||||
|
@ -17,8 +17,6 @@
|
||||
s.require_path = 'lib'
|
||||
s.requirements << 'none'
|
||||
|
||||
s.has_rdoc = true
|
||||
|
||||
s.add_dependency('actionpack', version)
|
||||
s.add_dependency('mail', '~> 2.2.15')
|
||||
end
|
||||
|
@ -1,5 +1,52 @@
|
||||
*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'
|
||||
|
||||
by requesting '/foo/bar.json', your `params[:pages]` will be equals to "foo/bar" with the request format of JSON. If you want the old 3.0.x behavior back, you could supply `:format => false` like this:
|
||||
|
||||
map '*pages' => 'pages#show', :format => false
|
||||
|
||||
* Added Base.http_basic_authenticate_with to do simple http basic authentication with a single class method call [DHH]
|
||||
|
||||
class PostsController < ApplicationController
|
||||
USER_NAME, PASSWORD = "dhh", "secret"
|
||||
|
||||
before_filter :authenticate, :except => [ :index ]
|
||||
|
||||
def index
|
||||
render :text => "Everyone can see me!"
|
||||
end
|
||||
|
||||
def edit
|
||||
render :text => "I'm only accessible if you know the password"
|
||||
end
|
||||
|
||||
private
|
||||
def authenticate
|
||||
authenticate_or_request_with_http_basic do |user_name, password|
|
||||
user_name == USER_NAME && password == PASSWORD
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
..can now be written as
|
||||
|
||||
class PostsController < ApplicationController
|
||||
http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index
|
||||
|
||||
def index
|
||||
render :text => "Everyone can see me!"
|
||||
end
|
||||
|
||||
def edit
|
||||
render :text => "I'm only accessible if you know the password"
|
||||
end
|
||||
end
|
||||
|
||||
* Allow you to add `force_ssl` into controller to force browser to transfer data via HTTPS protocol on that particular controller. You can also specify `:only` or `:except` to specific it to particular action. [DHH and Prem Sichanugrist]
|
||||
|
||||
* Allow FormHelper#form_for to specify the :method as a direct option instead of through the :html hash [DHH]
|
||||
|
@ -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 %>
|
||||
|
@ -17,8 +17,6 @@
|
||||
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')
|
||||
@ -26,7 +24,7 @@
|
||||
s.add_dependency('i18n', '~> 0.5.0')
|
||||
s.add_dependency('rack', '~> 1.2.1')
|
||||
s.add_dependency('rack-test', '~> 0.5.7')
|
||||
s.add_dependency('rack-mount', '~> 0.6.13')
|
||||
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
|
||||
|
@ -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
|
||||
@ -128,20 +130,23 @@ def action_methods
|
||||
self.class.action_methods
|
||||
end
|
||||
|
||||
private
|
||||
# Returns true if the name can be considered an action. This can
|
||||
# be overridden in subclasses to modify the semantics of what
|
||||
# can be considered an action.
|
||||
#
|
||||
# For instance, this is overriden by ActionController to add
|
||||
# the implicit rendering feature.
|
||||
#
|
||||
# ==== Parameters
|
||||
# * <tt>name</tt> - The name of an action to be tested
|
||||
#
|
||||
# ==== Returns
|
||||
# * <tt>TrueClass</tt>, <tt>FalseClass</tt>
|
||||
def action_method?(name)
|
||||
self.class.action_methods.include?(name)
|
||||
end
|
||||
|
||||
# Returns true if the name can be considered an action. This can
|
||||
# be overridden in subclasses to modify the semantics of what
|
||||
# can be considered an action.
|
||||
#
|
||||
# ==== Parameters
|
||||
# * <tt>name</tt> - The name of an action to be tested
|
||||
#
|
||||
# ==== Returns
|
||||
# * <tt>TrueClass</tt>, <tt>FalseClass</tt>
|
||||
def action_method?(name)
|
||||
self.class.action_methods.include?(name)
|
||||
end
|
||||
private
|
||||
|
||||
# Call the action. Override this in a subclass to modify the
|
||||
# behavior around processing an action. This, and not #process,
|
||||
@ -160,8 +165,8 @@ def process_action(method_name, *args)
|
||||
# If the action name was not found, but a method called "action_missing"
|
||||
# was found, #method_for_action will return "_handle_action_missing".
|
||||
# This method calls #action_missing with the current action name.
|
||||
def _handle_action_missing
|
||||
action_missing(@_action_name)
|
||||
def _handle_action_missing(*args)
|
||||
action_missing(@_action_name, *args)
|
||||
end
|
||||
|
||||
# Takes an action name and returns the name of the method that will
|
||||
|
@ -14,7 +14,7 @@ module Callbacks
|
||||
# Override AbstractController::Base's process_action to run the
|
||||
# process_action callbacks around the normal behavior.
|
||||
def process_action(method_name, *args)
|
||||
run_callbacks(:process_action, action_name) do
|
||||
run_callbacks(:process_action, method_name) do
|
||||
super
|
||||
end
|
||||
end
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -8,9 +8,7 @@ module HttpAuthentication
|
||||
# === Simple \Basic example
|
||||
#
|
||||
# class PostsController < ApplicationController
|
||||
# USER_NAME, PASSWORD = "dhh", "secret"
|
||||
#
|
||||
# before_filter :authenticate, :except => [ :index ]
|
||||
# http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index
|
||||
#
|
||||
# def index
|
||||
# render :text => "Everyone can see me!"
|
||||
@ -19,15 +17,7 @@ module HttpAuthentication
|
||||
# def edit
|
||||
# render :text => "I'm only accessible if you know the password"
|
||||
# end
|
||||
#
|
||||
# private
|
||||
# def authenticate
|
||||
# authenticate_or_request_with_http_basic do |user_name, password|
|
||||
# user_name == USER_NAME && password == PASSWORD
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
# === Advanced \Basic example
|
||||
#
|
||||
@ -77,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]
|
||||
#
|
||||
@ -115,6 +105,18 @@ module Basic
|
||||
extend self
|
||||
|
||||
module ControllerMethods
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
def http_basic_authenticate_with(options = {})
|
||||
before_filter(options.except(:name, :password, :realm)) do
|
||||
authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
|
||||
name == options[:name] && password == options[:password]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def authenticate_or_request_with_http_basic(realm = "Application", &login_procedure)
|
||||
authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm)
|
||||
end
|
||||
@ -378,7 +380,6 @@ def opaque(secret_key)
|
||||
#
|
||||
# RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
|
||||
module Token
|
||||
|
||||
extend self
|
||||
|
||||
module ControllerMethods
|
||||
@ -458,6 +459,5 @@ def authentication_request(controller, realm)
|
||||
controller.__send__ :render, :text => "HTTP Token: Access denied.\n", :status => :unauthorized
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,21 +1,21 @@
|
||||
module ActionController
|
||||
module ImplicitRender
|
||||
def send_action(*)
|
||||
ret = super
|
||||
default_render unless response_body
|
||||
ret
|
||||
end
|
||||
|
||||
def default_render
|
||||
render
|
||||
end
|
||||
|
||||
def method_for_action(action_name)
|
||||
super || begin
|
||||
if template_exists?(action_name.to_s, _prefixes)
|
||||
"default_render"
|
||||
end
|
||||
def send_action(method, *args)
|
||||
if respond_to?(method, true)
|
||||
ret = super
|
||||
default_render unless response_body
|
||||
ret
|
||||
else
|
||||
default_render
|
||||
end
|
||||
end
|
||||
|
||||
def default_render(*args)
|
||||
render(*args)
|
||||
end
|
||||
|
||||
def action_method?(action_name)
|
||||
super || template_exists?(action_name.to_s, _prefixes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -189,7 +189,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 +222,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 <tt>respond_to</tt>.
|
||||
#
|
||||
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?
|
||||
@ -259,7 +262,7 @@ def collect_mimes_from_class_level #:nodoc:
|
||||
#
|
||||
def retrieve_response_from_mimes(mimes=nil, &block)
|
||||
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)
|
||||
|
@ -77,6 +77,37 @@ module ActionController #:nodoc:
|
||||
#
|
||||
# respond_with(@project, :manager, @task)
|
||||
#
|
||||
# === Custom options
|
||||
#
|
||||
# <code>respond_with</code> 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 <code>respond_with</code>:
|
||||
#
|
||||
# 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 <code>respond_with</code> with a block follows the same syntax as <code>respond_to</code>.
|
||||
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?
|
||||
|
@ -104,10 +104,16 @@ def normalize_path(path)
|
||||
@options.reverse_merge!(:controller => /.+?/)
|
||||
end
|
||||
|
||||
# Add a constraint for wildcard route to make it non-greedy and match the
|
||||
# optional format part of the route by default
|
||||
if path.match(/\*([^\/]+)$/) && @options[:format] != false
|
||||
@options.reverse_merge!(:"#{$1}" => /.+?/)
|
||||
end
|
||||
|
||||
if @options[:format] == false
|
||||
@options.delete(:format)
|
||||
path
|
||||
elsif path.include?(":format") || path.end_with?('/') || path.match(/^\/?\*/)
|
||||
elsif path.include?(":format") || path.end_with?('/')
|
||||
path
|
||||
else
|
||||
"#{path}(.:format)"
|
||||
|
@ -46,7 +46,7 @@ def assert_recognizes(expected_options, path, extras={}, message=nil)
|
||||
expected_options.stringify_keys!
|
||||
msg = build_message(message, "The recognized options <?> did not match <?>, difference: <?>",
|
||||
request.path_parameters, expected_options, expected_options.diff(request.path_parameters))
|
||||
assert_block(msg) { request.path_parameters == expected_options }
|
||||
assert_equal(expected_options, request.path_parameters, msg)
|
||||
end
|
||||
|
||||
# Asserts that the provided options can be used to generate the provided path. This is the inverse of +assert_recognizes+.
|
||||
@ -84,11 +84,11 @@ def assert_generates(expected_path, options, defaults={}, extras = {}, message=n
|
||||
found_extras = options.reject {|k, v| ! extra_keys.include? k}
|
||||
|
||||
msg = build_message(message, "found extras <?>, not <?>", found_extras, extras)
|
||||
assert_block(msg) { found_extras == extras }
|
||||
assert_equal(extras, found_extras, msg)
|
||||
|
||||
msg = build_message(message, "The generated path <?> did not match <?>", generated_path,
|
||||
expected_path)
|
||||
assert_block(msg) { expected_path == generated_path }
|
||||
assert_equal(expected_path, generated_path, msg)
|
||||
end
|
||||
|
||||
# Asserts that path and options match both ways; in other words, it verifies that <tt>path</tt> generates
|
||||
|
@ -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 <tt>.erb</tt> (or <tt>.rhtml</tt>) extension then it uses a mixture of ERb
|
||||
# Action View templates can be written in three ways. If the template file has a <tt>.erb</tt> (or <tt>.rhtml</tt>) extension then it uses a mixture of ERB
|
||||
# (included in Ruby) and HTML. If the template file has a <tt>.builder</tt> (or <tt>.rxml</tt>) extension then Jim Weirich's Builder::XmlMarkup library is used.
|
||||
# If the template file has a <tt>.rjs</tt> 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:
|
||||
#
|
||||
# <b>Names of all the people</b>
|
||||
@ -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 <tt>.builder</tt> extension.
|
||||
#
|
||||
# Here are some basic examples:
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -584,7 +584,7 @@ def update_page(&block)
|
||||
|
||||
# Works like update_page but wraps the generated JavaScript in a
|
||||
# <tt>\<script></tt> tag. Use this to include generated JavaScript in an
|
||||
# ERb template. See JavaScriptGenerator for more information.
|
||||
# ERB template. See JavaScriptGenerator for more information.
|
||||
#
|
||||
# +html_options+ may be a hash of <tt>\<script></tt> attributes to be
|
||||
# passed to ActionView::Helpers::JavaScriptHelper#javascript_tag.
|
||||
|
@ -186,7 +186,7 @@ def url_for(options = {})
|
||||
# link_to "Profiles", :controller => "profiles"
|
||||
# # => <a href="/profiles">Profiles</a>
|
||||
#
|
||||
# You can use a block as well if your link target is hard to fit into the name parameter. ERb example:
|
||||
# You can use a block as well if your link target is hard to fit into the name parameter. ERB example:
|
||||
#
|
||||
# <%= link_to(@profile) do %>
|
||||
# <strong><%= @profile.name %></strong> -- <span>Check it out!</span>
|
||||
|
@ -55,7 +55,7 @@ def add_postamble(src)
|
||||
|
||||
class ERB
|
||||
# Specify trim mode for the ERB compiler. Defaults to '-'.
|
||||
# See ERb documentation for suitable values.
|
||||
# See ERB documentation for suitable values.
|
||||
class_attribute :erb_trim_mode
|
||||
self.erb_trim_mode = '-'
|
||||
|
||||
|
@ -6,6 +6,8 @@ class DummyController < ActionController::Base
|
||||
before_filter :authenticate_with_request, :only => :display
|
||||
before_filter :authenticate_long_credentials, :only => :show
|
||||
|
||||
http_basic_authenticate_with :name => "David", :password => "Goliath", :only => :search
|
||||
|
||||
def index
|
||||
render :text => "Hello Secret"
|
||||
end
|
||||
@ -17,6 +19,10 @@ def display
|
||||
def show
|
||||
render :text => 'Only for loooooong credentials'
|
||||
end
|
||||
|
||||
def search
|
||||
render :text => 'All inline'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@ -104,6 +110,16 @@ def authenticate_long_credentials
|
||||
assert assigns(:logged_in)
|
||||
assert_equal 'Definitely Maybe', @response.body
|
||||
end
|
||||
|
||||
test "authenticate with class method" do
|
||||
@request.env['HTTP_AUTHORIZATION'] = encode_credentials('David', 'Goliath')
|
||||
get :search
|
||||
assert_response :success
|
||||
|
||||
@request.env['HTTP_AUTHORIZATION'] = encode_credentials('David', 'WRONG!')
|
||||
get :search
|
||||
assert_response :unauthorized
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
@ -558,6 +558,15 @@ def using_resource_with_status_and_location
|
||||
respond_with(resource, :location => "http://test.host/", :status => :created)
|
||||
end
|
||||
|
||||
def using_invalid_resource_with_template
|
||||
respond_with(resource)
|
||||
end
|
||||
|
||||
def using_options_with_template
|
||||
@customer = resource
|
||||
respond_with(@customer, :status => 123, :location => "http://test.host/")
|
||||
end
|
||||
|
||||
def using_resource_with_responder
|
||||
responder = proc { |c, r, o| c.render :text => "Resource name is #{r.first.name}" }
|
||||
respond_with(resource, :responder => responder)
|
||||
@ -953,6 +962,54 @@ def test_using_resource_with_status_and_location
|
||||
assert_equal 201, @response.status
|
||||
end
|
||||
|
||||
def test_using_resource_with_status_and_location_with_invalid_resource
|
||||
errors = { :name => :invalid }
|
||||
Customer.any_instance.stubs(:errors).returns(errors)
|
||||
|
||||
@request.accept = "text/xml"
|
||||
|
||||
post :using_resource_with_status_and_location
|
||||
assert_equal errors.to_xml, @response.body
|
||||
assert_equal 422, @response.status
|
||||
assert_equal nil, @response.location
|
||||
|
||||
put :using_resource_with_status_and_location
|
||||
assert_equal errors.to_xml, @response.body
|
||||
assert_equal 422, @response.status
|
||||
assert_equal nil, @response.location
|
||||
end
|
||||
|
||||
def test_using_invalid_resource_with_template
|
||||
errors = { :name => :invalid }
|
||||
Customer.any_instance.stubs(:errors).returns(errors)
|
||||
|
||||
@request.accept = "text/xml"
|
||||
|
||||
post :using_invalid_resource_with_template
|
||||
assert_equal errors.to_xml, @response.body
|
||||
assert_equal 422, @response.status
|
||||
assert_equal nil, @response.location
|
||||
|
||||
put :using_invalid_resource_with_template
|
||||
assert_equal errors.to_xml, @response.body
|
||||
assert_equal 422, @response.status
|
||||
assert_equal nil, @response.location
|
||||
end
|
||||
|
||||
def test_using_options_with_template
|
||||
@request.accept = "text/xml"
|
||||
|
||||
post :using_options_with_template
|
||||
assert_equal "<customer-name>david</customer-name>", @response.body
|
||||
assert_equal 123, @response.status
|
||||
assert_equal "http://test.host/", @response.location
|
||||
|
||||
put :using_options_with_template
|
||||
assert_equal "<customer-name>david</customer-name>", @response.body
|
||||
assert_equal 123, @response.status
|
||||
assert_equal "http://test.host/", @response.location
|
||||
end
|
||||
|
||||
def test_using_resource_with_responder
|
||||
get :using_resource_with_responder
|
||||
assert_equal "Resource name is david", @response.body
|
||||
|
@ -3,8 +3,9 @@
|
||||
module RenderImplicitAction
|
||||
class SimpleController < ::ApplicationController
|
||||
self.view_paths = [ActionView::FixtureResolver.new(
|
||||
"render_implicit_action/simple/hello_world.html.erb" => "Hello world!",
|
||||
"render_implicit_action/simple/hyphen-ated.html.erb" => "Hello hyphen-ated!"
|
||||
"render_implicit_action/simple/hello_world.html.erb" => "Hello world!",
|
||||
"render_implicit_action/simple/hyphen-ated.html.erb" => "Hello hyphen-ated!",
|
||||
"render_implicit_action/simple/not_implemented.html.erb" => "Not Implemented"
|
||||
)]
|
||||
|
||||
def hello_world() end
|
||||
@ -24,5 +25,18 @@ class RenderImplicitActionTest < Rack::TestCase
|
||||
assert_body "Hello hyphen-ated!"
|
||||
assert_status 200
|
||||
end
|
||||
|
||||
test "render an action called not_implemented" do
|
||||
get "/render_implicit_action/simple/not_implemented"
|
||||
|
||||
assert_body "Not Implemented"
|
||||
assert_status 200
|
||||
end
|
||||
|
||||
test "action_method? returns true for implicit actions" do
|
||||
assert SimpleController.new.action_method?(:hello_world)
|
||||
assert SimpleController.new.action_method?(:"hyphen-ated")
|
||||
assert SimpleController.new.action_method?(:not_implemented)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -25,6 +25,10 @@ def add_route(*args)
|
||||
def conditions
|
||||
routes.map { |x| x[1] }
|
||||
end
|
||||
|
||||
def requirements
|
||||
routes.map { |x| x[2] }
|
||||
end
|
||||
end
|
||||
|
||||
def test_initialize
|
||||
@ -50,8 +54,34 @@ def test_map_more_slashes
|
||||
def test_map_wildcard
|
||||
fakeset = FakeSet.new
|
||||
mapper = Mapper.new fakeset
|
||||
mapper.match '/*path', :to => 'pages#show', :as => :page
|
||||
mapper.match '/*path', :to => 'pages#show'
|
||||
assert_equal '/*path(.:format)', fakeset.conditions.first[:path_info]
|
||||
assert_equal(/.+?/, fakeset.requirements.first[:path])
|
||||
end
|
||||
|
||||
def test_map_wildcard_with_other_element
|
||||
fakeset = FakeSet.new
|
||||
mapper = Mapper.new fakeset
|
||||
mapper.match '/*path/foo/:bar', :to => 'pages#show'
|
||||
assert_equal '/*path/foo/:bar(.:format)', fakeset.conditions.first[:path_info]
|
||||
assert_nil fakeset.requirements.first[:path]
|
||||
end
|
||||
|
||||
def test_map_wildcard_with_multiple_wildcard
|
||||
fakeset = FakeSet.new
|
||||
mapper = Mapper.new fakeset
|
||||
mapper.match '/*foo/*bar', :to => 'pages#show'
|
||||
assert_equal '/*foo/*bar(.:format)', fakeset.conditions.first[:path_info]
|
||||
assert_nil fakeset.requirements.first[:foo]
|
||||
assert_equal(/.+?/, fakeset.requirements.first[:bar])
|
||||
end
|
||||
|
||||
def test_map_wildcard_with_format_false
|
||||
fakeset = FakeSet.new
|
||||
mapper = Mapper.new fakeset
|
||||
mapper.match '/*path', :to => 'pages#show', :format => false
|
||||
assert_equal '/*path', fakeset.conditions.first[:path_info]
|
||||
assert_nil fakeset.requirements.first[:path]
|
||||
end
|
||||
end
|
||||
end
|
1
actionpack/test/fixtures/respond_with/using_invalid_resource_with_template.xml.erb
vendored
Normal file
1
actionpack/test/fixtures/respond_with/using_invalid_resource_with_template.xml.erb
vendored
Normal file
@ -0,0 +1 @@
|
||||
<content>I should not be displayed</content>
|
1
actionpack/test/fixtures/respond_with/using_options_with_template.xml.erb
vendored
Normal file
1
actionpack/test/fixtures/respond_with/using_options_with_template.xml.erb
vendored
Normal file
@ -0,0 +1 @@
|
||||
<customer-name><%= @customer.name %></customer-name>
|
@ -2720,11 +2720,11 @@ def test_time_tag_with_time
|
||||
end
|
||||
|
||||
def test_time_tag_pubdate_option
|
||||
assert_match /<time.*pubdate="pubdate">.*<\/time>/, time_tag(Time.now, :pubdate => true)
|
||||
assert_match(/<time.*pubdate="pubdate">.*<\/time>/, time_tag(Time.now, :pubdate => true))
|
||||
end
|
||||
|
||||
def test_time_tag_with_given_text
|
||||
assert_match /<time.*>Right now<\/time>/, time_tag(Time.now, 'Right now')
|
||||
assert_match(/<time.*>Right now<\/time>/, time_tag(Time.now, 'Right now'))
|
||||
end
|
||||
|
||||
def test_time_tag_with_different_format
|
||||
|
@ -17,8 +17,6 @@
|
||||
s.files = Dir['CHANGELOG', 'MIT-LICENSE', 'README.rdoc', 'lib/**/*']
|
||||
s.require_path = 'lib'
|
||||
|
||||
s.has_rdoc = true
|
||||
|
||||
s.add_dependency('activesupport', version)
|
||||
s.add_dependency('builder', '~> 3.0.0')
|
||||
s.add_dependency('i18n', '~> 0.5.0')
|
||||
|
@ -294,8 +294,8 @@ def generate_message(attribute, type = :invalid, options = {})
|
||||
type = options.delete(:message) if options[:message].is_a?(Symbol)
|
||||
|
||||
defaults = @base.class.lookup_ancestors.map do |klass|
|
||||
[ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.attributes.#{attribute}.#{type}",
|
||||
:"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.#{type}" ]
|
||||
[ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
|
||||
:"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
|
||||
end
|
||||
|
||||
defaults << options.delete(:message)
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
module ActiveModel
|
||||
class Name < String
|
||||
attr_reader :singular, :plural, :element, :collection, :partial_path, :route_key, :param_key
|
||||
attr_reader :singular, :plural, :element, :collection, :partial_path, :route_key, :param_key, :i18n_key
|
||||
alias_method :cache_key, :collection
|
||||
|
||||
def initialize(klass, namespace = nil)
|
||||
@ -20,6 +20,7 @@ def initialize(klass, namespace = nil)
|
||||
@partial_path = "#{@collection}/#{@element}".freeze
|
||||
@param_key = (namespace ? _singularize(@unnamespaced) : @singular).freeze
|
||||
@route_key = (namespace ? ActiveSupport::Inflector.pluralize(@param_key) : @plural).freeze
|
||||
@i18n_key = self.underscore.to_sym
|
||||
end
|
||||
|
||||
# Transform the model name into a more humane format, using I18n. By default,
|
||||
@ -33,7 +34,7 @@ def human(options={})
|
||||
@klass.respond_to?(:i18n_scope)
|
||||
|
||||
defaults = @klass.lookup_ancestors.map do |klass|
|
||||
klass.model_name.underscore.to_sym
|
||||
klass.model_name.i18n_key
|
||||
end
|
||||
|
||||
defaults << options[:default] if options[:default]
|
||||
@ -44,9 +45,10 @@ def human(options={})
|
||||
end
|
||||
|
||||
private
|
||||
def _singularize(str)
|
||||
ActiveSupport::Inflector.underscore(str).tr('/', '_')
|
||||
end
|
||||
|
||||
def _singularize(string, replacement='_')
|
||||
ActiveSupport::Inflector.underscore(string).tr('/', replacement)
|
||||
end
|
||||
end
|
||||
|
||||
# == Active Model Naming
|
||||
@ -62,6 +64,9 @@ def _singularize(str)
|
||||
# BookCover.model_name # => "BookCover"
|
||||
# BookCover.model_name.human # => "Book cover"
|
||||
#
|
||||
# BookCover.model_name.i18n_key # => "book_cover"
|
||||
# BookModule::BookCover.model_name.i18n_key # => "book_module.book_cover"
|
||||
#
|
||||
# Providing the functionality that ActiveModel::Naming provides in your object
|
||||
# is required to pass the Active Model Lint test. So either extending the provided
|
||||
# method below, or rolling your own is required.
|
||||
|
@ -44,7 +44,7 @@ def lookup_ancestors
|
||||
# Specify +options+ with additional translating options.
|
||||
def human_attribute_name(attribute, options = {})
|
||||
defaults = lookup_ancestors.map do |klass|
|
||||
:"#{self.i18n_scope}.attributes.#{klass.model_name.underscore}.#{attribute}"
|
||||
:"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute}"
|
||||
end
|
||||
|
||||
defaults << :"attributes.#{attribute}"
|
||||
|
@ -1,5 +1,17 @@
|
||||
*Rails 3.1.0 (unreleased)*
|
||||
|
||||
* ConnectionManagement middleware is changed to clean up the connection pool
|
||||
after the rack body has been flushed.
|
||||
|
||||
* Added an update_column method on ActiveRecord. This new method updates a given attribute on an object, skipping validations and callbacks.
|
||||
It is recommended to use #update_attribute unless you are sure you do not want to execute any callback, including the modification of
|
||||
the updated_at column. It should not be called on new records.
|
||||
Example:
|
||||
|
||||
User.first.update_column(:name, "sebastian") # => true
|
||||
|
||||
[Sebastian Martinez]
|
||||
|
||||
* Associations with a :through option can now use *any* association as the
|
||||
through or source association, including other associations which have a
|
||||
:through option and has_and_belongs_to_many associations
|
||||
|
@ -17,7 +17,6 @@
|
||||
s.files = Dir['CHANGELOG', 'README.rdoc', 'examples/**/*', 'lib/**/*']
|
||||
s.require_path = 'lib'
|
||||
|
||||
s.has_rdoc = true
|
||||
s.extra_rdoc_files = %w( README.rdoc )
|
||||
s.rdoc_options.concat ['--main', 'README.rdoc']
|
||||
|
||||
|
@ -34,8 +34,7 @@ def delete(method = options[:dependent])
|
||||
when :destroy
|
||||
target.destroy
|
||||
when :nullify
|
||||
target.send("#{reflection.foreign_key}=", nil)
|
||||
target.save(:validations => false)
|
||||
target.update_attribute(reflection.foreign_key, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -22,7 +22,7 @@ def initialize(active_record)
|
||||
end
|
||||
|
||||
def aliased_table
|
||||
Arel::Nodes::TableAlias.new aliased_table_name, table
|
||||
Arel::Nodes::TableAlias.new table, aliased_table_name
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
|
@ -17,6 +17,11 @@ def primary_key
|
||||
@primary_key ||= reset_primary_key
|
||||
end
|
||||
|
||||
# Returns a quoted version of the primary key name, used to construct SQL statements.
|
||||
def quoted_primary_key
|
||||
@quoted_primary_key ||= connection.quote_column_name(primary_key)
|
||||
end
|
||||
|
||||
def reset_primary_key #:nodoc:
|
||||
key = self == base_class ? get_primary_key(base_class.name) :
|
||||
base_class.primary_key
|
||||
@ -43,7 +48,12 @@ def get_primary_key(base_name) #:nodoc:
|
||||
end
|
||||
|
||||
attr_accessor :original_primary_key
|
||||
attr_writer :primary_key
|
||||
|
||||
# Attribute writer for the primary key column
|
||||
def primary_key=(value)
|
||||
@quoted_primary_key = nil
|
||||
@primary_key = value
|
||||
end
|
||||
|
||||
# Sets the name of the primary key column to use to the given value,
|
||||
# or (if the value is nil or false) to the value returned by the given
|
||||
@ -53,6 +63,7 @@ def get_primary_key(base_name) #:nodoc:
|
||||
# set_primary_key "sysid"
|
||||
# end
|
||||
def set_primary_key(value = nil, &block)
|
||||
@quoted_primary_key = nil
|
||||
@primary_key ||= ''
|
||||
self.original_primary_key = @primary_key
|
||||
value &&= value.to_s
|
||||
|
@ -32,6 +32,7 @@ def write_attribute(attr_name, value)
|
||||
@attributes[attr_name] = value
|
||||
end
|
||||
end
|
||||
alias_method :raw_write_attribute, :write_attribute
|
||||
|
||||
private
|
||||
# Handle *= for method_missing.
|
||||
|
@ -437,9 +437,10 @@ class Base
|
||||
self._attr_readonly = []
|
||||
|
||||
class << self # Class methods
|
||||
delegate :find, :first, :last, :all, :destroy, :destroy_all, :exists?, :delete, :delete_all, :update, :update_all, :to => :scoped
|
||||
delegate :find, :first, :first!, :last, :last!, :all, :exists?, :any?, :many?, :to => :scoped
|
||||
delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :scoped
|
||||
delegate :find_each, :find_in_batches, :to => :scoped
|
||||
delegate :select, :group, :order, :except, :limit, :offset, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :to => :scoped
|
||||
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :to => :scoped
|
||||
delegate :count, :average, :minimum, :maximum, :sum, :calculate, :to => :scoped
|
||||
|
||||
# Executes a custom SQL query against your database and returns all the results. The results will
|
||||
|
@ -151,6 +151,12 @@ def connection
|
||||
@reserved_connections[current_connection_id] ||= checkout
|
||||
end
|
||||
|
||||
# Check to see if there is an active connection in this connection
|
||||
# pool.
|
||||
def active_connection?
|
||||
@reserved_connections.key? current_connection_id
|
||||
end
|
||||
|
||||
# Signal that the thread is finished with the current connection.
|
||||
# #release_connection releases the connection-thread association
|
||||
# and returns the connection to the pool.
|
||||
@ -346,6 +352,12 @@ def establish_connection(name, spec)
|
||||
@connection_pools[name] = ConnectionAdapters::ConnectionPool.new(spec)
|
||||
end
|
||||
|
||||
# Returns true if there are any active connections among the connection
|
||||
# pools that the ConnectionHandler is managing.
|
||||
def active_connections?
|
||||
connection_pools.values.any? { |pool| pool.active_connection? }
|
||||
end
|
||||
|
||||
# Returns any connections in use by the current thread back to the pool,
|
||||
# and also returns connections to the pool cached by threads that are no
|
||||
# longer alive.
|
||||
@ -405,18 +417,40 @@ def retrieve_connection_pool(klass)
|
||||
end
|
||||
|
||||
class ConnectionManagement
|
||||
class Proxy # :nodoc:
|
||||
attr_reader :body, :testing
|
||||
|
||||
def initialize(body, testing = false)
|
||||
@body = body
|
||||
@testing = testing
|
||||
end
|
||||
|
||||
def each(&block)
|
||||
body.each(&block)
|
||||
end
|
||||
|
||||
def close
|
||||
body.close if body.respond_to?(:close)
|
||||
|
||||
# Don't return connection (and perform implicit rollback) if
|
||||
# this request is a part of integration test
|
||||
ActiveRecord::Base.clear_active_connections! unless testing
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@app.call(env)
|
||||
ensure
|
||||
# Don't return connection (and perform implicit rollback) if
|
||||
# this request is a part of integration test
|
||||
unless env.key?("rack.test")
|
||||
ActiveRecord::Base.clear_active_connections!
|
||||
end
|
||||
testing = env.key?('rack.test')
|
||||
|
||||
status, headers, body = @app.call(env)
|
||||
|
||||
[status, headers, Proxy.new(body, testing)]
|
||||
rescue
|
||||
ActiveRecord::Base.clear_active_connections! unless testing
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -116,7 +116,11 @@ def remove_connection(klass = self)
|
||||
connection_handler.remove_connection(klass)
|
||||
end
|
||||
|
||||
delegate :clear_active_connections!, :clear_reloadable_connections!,
|
||||
def clear_active_connections!
|
||||
connection_handler.clear_active_connections!
|
||||
end
|
||||
|
||||
delegate :clear_reloadable_connections!,
|
||||
:clear_all_connections!,:verify_active_connections!, :to => :connection_handler
|
||||
end
|
||||
end
|
||||
|
@ -222,7 +222,7 @@ def rollback_db_transaction #:nodoc:
|
||||
|
||||
# SCHEMA STATEMENTS ========================================
|
||||
|
||||
def tables(name = nil) #:nodoc:
|
||||
def tables(name = 'SCHEMA') #:nodoc:
|
||||
sql = <<-SQL
|
||||
SELECT name
|
||||
FROM sqlite_master
|
||||
@ -350,7 +350,7 @@ def select(sql, name = nil, binds = []) #:nodoc:
|
||||
end
|
||||
|
||||
def table_structure(table_name)
|
||||
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})").to_hash
|
||||
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA').to_hash
|
||||
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
||||
structure
|
||||
end
|
||||
|
@ -173,10 +173,10 @@ class FixturesFileNotFound < StandardError; end
|
||||
# traversed in the database to create the fixture hash and/or instance variables. This is expensive for
|
||||
# large sets of fixtured data.
|
||||
#
|
||||
# = Dynamic fixtures with ERb
|
||||
# = Dynamic fixtures with ERB
|
||||
#
|
||||
# Some times you don't care about the content of the fixtures as much as you care about the volume. In these cases, you can
|
||||
# mix ERb in with your YAML or CSV fixtures to create a bunch of fixtures for load testing, like:
|
||||
# mix ERB in with your YAML or CSV fixtures to create a bunch of fixtures for load testing, like:
|
||||
#
|
||||
# <% for i in 1..1000 %>
|
||||
# fix_<%= i %>:
|
||||
@ -186,7 +186,7 @@ class FixturesFileNotFound < StandardError; end
|
||||
#
|
||||
# This will create 1000 very simple YAML fixtures.
|
||||
#
|
||||
# Using ERb, you can also inject dynamic values into your fixtures with inserts like <tt><%= Date.today.strftime("%Y-%m-%d") %></tt>.
|
||||
# Using ERB, you can also inject dynamic values into your fixtures with inserts like <tt><%= Date.today.strftime("%Y-%m-%d") %></tt>.
|
||||
# This is however a feature to be used with some caution. The point of fixtures are that they're
|
||||
# stable units of predictable sample data. If you feel that you need to inject dynamic values, then
|
||||
# perhaps you should reexamine whether your application is properly testable. Hence, dynamic values
|
||||
|
@ -23,6 +23,9 @@ def sql(event)
|
||||
return unless logger.debug?
|
||||
|
||||
payload = event.payload
|
||||
|
||||
return if 'SCHEMA' == payload[:name]
|
||||
|
||||
name = '%s (%.1fms)' % [payload[:name], event.duration]
|
||||
sql = payload[:sql].squeeze(' ')
|
||||
binds = nil
|
||||
|
@ -104,17 +104,33 @@ def becomes(klass)
|
||||
became
|
||||
end
|
||||
|
||||
# Updates a single attribute and saves the record.
|
||||
# This is especially useful for boolean flags on existing records. Also note that
|
||||
#
|
||||
# * Validation is skipped.
|
||||
# * Callbacks are invoked.
|
||||
# * updated_at/updated_on column is updated if that column is available.
|
||||
# * Updates all the attributes that are dirty in this object.
|
||||
#
|
||||
def update_attribute(name, value)
|
||||
name = name.to_s
|
||||
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
|
||||
send("#{name}=", value)
|
||||
save(:validate => false)
|
||||
end
|
||||
|
||||
# Updates a single attribute of an object, without calling save.
|
||||
#
|
||||
# * Validation is skipped.
|
||||
# * Callbacks are skipped.
|
||||
# * updated_at/updated_on column is not updated in any case.
|
||||
# * updated_at/updated_on column is not updated if that column is available.
|
||||
#
|
||||
def update_column(name, value)
|
||||
name = name.to_s
|
||||
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
|
||||
send("#{name}=", value)
|
||||
self.class.update_all({ name => value }, self.class.primary_key => id)
|
||||
raise ActiveRecordError, "can not update on a new record object" unless persisted?
|
||||
raw_write_attribute(name, value)
|
||||
self.class.update_all({ name => value }, self.class.primary_key => id) == 1
|
||||
end
|
||||
|
||||
# Updates the attributes of the model from the passed-in hash and saves the
|
||||
@ -154,7 +170,7 @@ def increment(attribute, by = 1)
|
||||
# Saving is not subjected to validation checks. Returns +true+ if the
|
||||
# record could be saved.
|
||||
def increment!(attribute, by = 1)
|
||||
increment(attribute, by).update_column(attribute, self[attribute])
|
||||
increment(attribute, by).update_attribute(attribute, self[attribute])
|
||||
end
|
||||
|
||||
# Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
|
||||
@ -171,7 +187,7 @@ def decrement(attribute, by = 1)
|
||||
# Saving is not subjected to validation checks. Returns +true+ if the
|
||||
# record could be saved.
|
||||
def decrement!(attribute, by = 1)
|
||||
decrement(attribute, by).update_column(attribute, self[attribute])
|
||||
decrement(attribute, by).update_attribute(attribute, self[attribute])
|
||||
end
|
||||
|
||||
# Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
|
||||
@ -188,7 +204,7 @@ def toggle(attribute)
|
||||
# Saving is not subjected to validation checks. Returns +true+ if the
|
||||
# record could be saved.
|
||||
def toggle!(attribute)
|
||||
toggle(attribute).update_column(attribute, self[attribute])
|
||||
toggle(attribute).update_attribute(attribute, self[attribute])
|
||||
end
|
||||
|
||||
# Reloads the attributes of this object from the database.
|
||||
|
@ -12,7 +12,7 @@ class Relation
|
||||
|
||||
# These are explicitly delegated to improve performance (avoids method_missing)
|
||||
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to => :to_a
|
||||
delegate :table_name, :primary_key, :to => :klass
|
||||
delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key, :to => :klass
|
||||
|
||||
attr_reader :table, :klass, :loaded
|
||||
attr_accessor :extensions
|
||||
|
@ -83,7 +83,7 @@ def find_in_batches(options = {})
|
||||
private
|
||||
|
||||
def batch_order
|
||||
"#{table_name}.#{primary_key} ASC"
|
||||
"#{quoted_table_name}.#{quoted_primary_key} ASC"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -196,24 +196,22 @@ def operation_over_aggregate_column(column, operation, distinct)
|
||||
end
|
||||
|
||||
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
|
||||
column = aggregate_column(column_name)
|
||||
|
||||
# Postgresql doesn't like ORDER BY when there are no GROUP BY
|
||||
relation = except(:order)
|
||||
select_value = operation_over_aggregate_column(column, operation, distinct)
|
||||
|
||||
relation.select_values = [select_value]
|
||||
if operation == "count" && (relation.limit_value || relation.offset_value)
|
||||
# Shortcut when limit is zero.
|
||||
return 0 if relation.limit_value == 0
|
||||
|
||||
query_builder = relation.arel
|
||||
query_builder = build_count_subquery(relation, column_name, distinct)
|
||||
else
|
||||
column = aggregate_column(column_name)
|
||||
|
||||
if operation == "count"
|
||||
limit = relation.limit_value
|
||||
offset = relation.offset_value
|
||||
select_value = operation_over_aggregate_column(column, operation, distinct)
|
||||
|
||||
unless limit && offset
|
||||
query_builder.limit = nil
|
||||
query_builder.offset = nil
|
||||
end
|
||||
relation.select_values = [select_value]
|
||||
|
||||
query_builder = relation.arel
|
||||
end
|
||||
|
||||
type_cast_calculated_value(@klass.connection.select_value(query_builder.to_sql), column_for(column_name), operation)
|
||||
@ -312,5 +310,18 @@ def select_for_count
|
||||
select if select !~ /(,|\*)/
|
||||
end
|
||||
end
|
||||
|
||||
def build_count_subquery(relation, column_name, distinct)
|
||||
column_alias = Arel.sql('count_column')
|
||||
subquery_alias = Arel.sql('subquery_for_count')
|
||||
|
||||
aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
|
||||
relation.select_values = [aliased_column]
|
||||
subquery = relation.arel.as(subquery_alias)
|
||||
|
||||
sm = Arel::SelectManager.new relation.engine
|
||||
select_value = operation_over_aggregate_column(column_alias, 'count', distinct)
|
||||
sm.project(select_value).from(subquery)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -183,7 +183,9 @@ def all(*args)
|
||||
def exists?(id = nil)
|
||||
id = id.id if ActiveRecord::Base === id
|
||||
|
||||
relation = select("1").limit(1)
|
||||
join_dependency = construct_join_dependency_for_association_find
|
||||
relation = construct_relation_for_association_find(join_dependency)
|
||||
relation = relation.except(:select).select("1").limit(1)
|
||||
|
||||
case id
|
||||
when Array, Hash
|
||||
@ -192,14 +194,13 @@ def exists?(id = nil)
|
||||
relation = relation.where(table[primary_key].eq(id)) if id
|
||||
end
|
||||
|
||||
relation.first ? true : false
|
||||
connection.select_value(relation.to_sql) ? true : false
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def find_with_associations
|
||||
including = (@eager_load_values + @includes_values).uniq
|
||||
join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, [])
|
||||
join_dependency = construct_join_dependency_for_association_find
|
||||
relation = construct_relation_for_association_find(join_dependency)
|
||||
rows = connection.select_all(relation.to_sql, 'SQL', relation.bind_values)
|
||||
join_dependency.instantiate(rows)
|
||||
@ -207,6 +208,11 @@ def find_with_associations
|
||||
[]
|
||||
end
|
||||
|
||||
def construct_join_dependency_for_association_find
|
||||
including = (@eager_load_values + @includes_values).uniq
|
||||
ActiveRecord::Associations::JoinDependency.new(@klass, including, [])
|
||||
end
|
||||
|
||||
def construct_relation_for_association_calculations
|
||||
including = (@eager_load_values + @includes_values).uniq
|
||||
join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, arel.froms.first)
|
||||
|
@ -62,6 +62,10 @@ def order(*args)
|
||||
relation
|
||||
end
|
||||
|
||||
def reorder(*args)
|
||||
except(:order).order(args)
|
||||
end
|
||||
|
||||
def joins(*args)
|
||||
return self if args.compact.blank?
|
||||
|
||||
|
@ -83,4 +83,14 @@ def test_find_in_batches_shouldnt_excute_query_unless_needed
|
||||
Post.find_in_batches(:batch_size => post_count + 1) {|batch| assert_kind_of Array, batch }
|
||||
end
|
||||
end
|
||||
|
||||
def test_find_in_batches_should_quote_batch_order
|
||||
c = Post.connection
|
||||
assert_sql(/ORDER BY #{c.quote_table_name('posts')}.#{c.quote_column_name('id')}/) do
|
||||
Post.find_in_batches(:batch_size => 1) do |batch|
|
||||
assert_kind_of Array, batch
|
||||
assert_kind_of Post, batch.first
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -65,7 +65,7 @@ def test_should_group_by_field
|
||||
c = Account.sum(:credit_limit, :group => :firm_id)
|
||||
[1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
|
||||
end
|
||||
|
||||
|
||||
def test_should_group_by_multiple_fields
|
||||
c = Account.count(:all, :group => ['firm_id', :credit_limit])
|
||||
[ [nil, 50], [1, 50], [6, 50], [6, 55], [9, 53], [2, 60] ].each { |firm_and_limit| assert c.keys.include?(firm_and_limit) }
|
||||
@ -109,6 +109,35 @@ def test_should_limit_calculation_with_offset
|
||||
assert_equal [2, 6], c.keys.compact
|
||||
end
|
||||
|
||||
def test_limit_should_apply_before_count
|
||||
accounts = Account.limit(3).where('firm_id IS NOT NULL')
|
||||
|
||||
assert_equal 3, accounts.count(:firm_id)
|
||||
assert_equal 3, accounts.select(:firm_id).count
|
||||
end
|
||||
|
||||
def test_count_should_shortcut_with_limit_zero
|
||||
accounts = Account.limit(0)
|
||||
|
||||
assert_no_queries { assert_equal 0, accounts.count }
|
||||
end
|
||||
|
||||
def test_limit_is_kept
|
||||
return if current_adapter?(:OracleAdapter)
|
||||
|
||||
queries = assert_sql { Account.limit(1).count }
|
||||
assert_equal 1, queries.length
|
||||
assert_match(/LIMIT/, queries.first)
|
||||
end
|
||||
|
||||
def test_offset_is_kept
|
||||
return if current_adapter?(:OracleAdapter)
|
||||
|
||||
queries = assert_sql { Account.offset(1).count }
|
||||
assert_equal 1, queries.length
|
||||
assert_match(/OFFSET/, queries.first)
|
||||
end
|
||||
|
||||
def test_limit_with_offset_is_kept
|
||||
return if current_adapter?(:OracleAdapter)
|
||||
|
||||
@ -118,20 +147,6 @@ def test_limit_with_offset_is_kept
|
||||
assert_match(/OFFSET/, queries.first)
|
||||
end
|
||||
|
||||
def test_offset_without_limit_removes_offset
|
||||
queries = assert_sql { Account.offset(1).count }
|
||||
assert_equal 1, queries.length
|
||||
assert_no_match(/LIMIT/, queries.first)
|
||||
assert_no_match(/OFFSET/, queries.first)
|
||||
end
|
||||
|
||||
def test_limit_without_offset_removes_limit
|
||||
queries = assert_sql { Account.limit(1).count }
|
||||
assert_equal 1, queries.length
|
||||
assert_no_match(/LIMIT/, queries.first)
|
||||
assert_no_match(/OFFSET/, queries.first)
|
||||
end
|
||||
|
||||
def test_no_limit_no_offset
|
||||
queries = assert_sql { Account.count }
|
||||
assert_equal 1, queries.length
|
||||
|
@ -0,0 +1,33 @@
|
||||
require "cases/helper"
|
||||
|
||||
module ActiveRecord
|
||||
module ConnectionAdapters
|
||||
class ConnectionHandlerTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
@handler = ConnectionHandler.new
|
||||
@handler.establish_connection 'america', Base.connection_pool.spec
|
||||
@klass = Struct.new(:name).new('america')
|
||||
end
|
||||
|
||||
def test_retrieve_connection
|
||||
assert @handler.retrieve_connection(@klass)
|
||||
end
|
||||
|
||||
def test_active_connections?
|
||||
assert !@handler.active_connections?
|
||||
assert @handler.retrieve_connection(@klass)
|
||||
assert @handler.active_connections?
|
||||
@handler.clear_active_connections!
|
||||
assert !@handler.active_connections?
|
||||
end
|
||||
|
||||
def test_retrieve_connection_pool_with_ar_base
|
||||
assert_nil @handler.retrieve_connection_pool(ActiveRecord::Base)
|
||||
end
|
||||
|
||||
def test_retrieve_connection_pool
|
||||
assert_not_nil @handler.retrieve_connection_pool(@klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,25 +1,82 @@
|
||||
require "cases/helper"
|
||||
|
||||
class ConnectionManagementTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
@env = {}
|
||||
@app = stub('App')
|
||||
@management = ActiveRecord::ConnectionAdapters::ConnectionManagement.new(@app)
|
||||
module ActiveRecord
|
||||
module ConnectionAdapters
|
||||
class ConnectionManagementTest < ActiveRecord::TestCase
|
||||
class App
|
||||
attr_reader :calls
|
||||
def initialize
|
||||
@calls = []
|
||||
end
|
||||
|
||||
@connections_cleared = false
|
||||
ActiveRecord::Base.stubs(:clear_active_connections!).with { @connections_cleared = true }
|
||||
end
|
||||
def call(env)
|
||||
@calls << env
|
||||
[200, {}, ['hi mom']]
|
||||
end
|
||||
end
|
||||
|
||||
test "clears active connections after each call" do
|
||||
@app.expects(:call).with(@env)
|
||||
@management.call(@env)
|
||||
assert @connections_cleared
|
||||
end
|
||||
def setup
|
||||
@env = {}
|
||||
@app = App.new
|
||||
@management = ConnectionManagement.new(@app)
|
||||
|
||||
test "doesn't clear active connections when running in a test case" do
|
||||
@env['rack.test'] = true
|
||||
@app.expects(:call).with(@env)
|
||||
@management.call(@env)
|
||||
assert !@connections_cleared
|
||||
# make sure we have an active connection
|
||||
assert ActiveRecord::Base.connection
|
||||
assert ActiveRecord::Base.connection_handler.active_connections?
|
||||
end
|
||||
|
||||
def test_app_delegation
|
||||
manager = ConnectionManagement.new(@app)
|
||||
|
||||
manager.call @env
|
||||
assert_equal [@env], @app.calls
|
||||
end
|
||||
|
||||
def test_connections_are_active_after_call
|
||||
@management.call(@env)
|
||||
assert ActiveRecord::Base.connection_handler.active_connections?
|
||||
end
|
||||
|
||||
def test_body_responds_to_each
|
||||
_, _, body = @management.call(@env)
|
||||
bits = []
|
||||
body.each { |bit| bits << bit }
|
||||
assert_equal ['hi mom'], bits
|
||||
end
|
||||
|
||||
def test_connections_are_cleared_after_body_close
|
||||
_, _, body = @management.call(@env)
|
||||
body.close
|
||||
assert !ActiveRecord::Base.connection_handler.active_connections?
|
||||
end
|
||||
|
||||
def test_active_connections_are_not_cleared_on_body_close_during_test
|
||||
@env['rack.test'] = true
|
||||
_, _, body = @management.call(@env)
|
||||
body.close
|
||||
assert ActiveRecord::Base.connection_handler.active_connections?
|
||||
end
|
||||
|
||||
def test_connections_closed_if_exception
|
||||
app = Class.new(App) { def call(env); raise; end }.new
|
||||
explosive = ConnectionManagement.new(app)
|
||||
assert_raises(RuntimeError) { explosive.call(@env) }
|
||||
assert !ActiveRecord::Base.connection_handler.active_connections?
|
||||
end
|
||||
|
||||
def test_connections_not_closed_if_exception_and_test
|
||||
@env['rack.test'] = true
|
||||
app = Class.new(App) { def call(env); raise; end }.new
|
||||
explosive = ConnectionManagement.new(app)
|
||||
assert_raises(RuntimeError) { explosive.call(@env) }
|
||||
assert ActiveRecord::Base.connection_handler.active_connections?
|
||||
end
|
||||
|
||||
test "doesn't clear active connections when running in a test case" do
|
||||
@env['rack.test'] = true
|
||||
@management.call(@env)
|
||||
assert ActiveRecord::Base.connection_handler.active_connections?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -18,6 +18,14 @@ def setup
|
||||
end
|
||||
end
|
||||
|
||||
def test_active_connection?
|
||||
assert !@pool.active_connection?
|
||||
assert @pool.connection
|
||||
assert @pool.active_connection?
|
||||
@pool.release_connection
|
||||
assert !@pool.active_connection?
|
||||
end
|
||||
|
||||
def test_pool_caches_columns
|
||||
columns = @pool.columns['posts']
|
||||
assert_equal columns, @pool.columns['posts']
|
||||
|
@ -487,8 +487,7 @@ def test_previous_changes
|
||||
assert !pirate.previous_changes.key?('created_on')
|
||||
|
||||
pirate = Pirate.find_by_catchphrase("Ahoy!")
|
||||
pirate.catchphrase = "Ninjas suck!"
|
||||
pirate.save(:validations => false)
|
||||
pirate.update_attribute(:catchphrase, "Ninjas suck!")
|
||||
|
||||
assert_equal 2, pirate.previous_changes.size
|
||||
assert_equal ["Ahoy!", "Ninjas suck!"], pirate.previous_changes['catchphrase']
|
||||
|
@ -74,6 +74,11 @@ def test_exists_with_scoped_include
|
||||
end
|
||||
end
|
||||
|
||||
def test_exists_does_not_instantiate_records
|
||||
Developer.expects(:instantiate).never
|
||||
Developer.exists?
|
||||
end
|
||||
|
||||
def test_find_by_array_of_one_id
|
||||
assert_kind_of(Array, Topic.find([ 1 ]))
|
||||
assert_equal(1, Topic.find([ 1 ]).length)
|
||||
@ -203,6 +208,14 @@ def test_first_bang_missing
|
||||
end
|
||||
end
|
||||
|
||||
def test_model_class_responds_to_first_bang
|
||||
assert Topic.first!
|
||||
Topic.delete_all
|
||||
assert_raises ActiveRecord::RecordNotFound do
|
||||
Topic.first!
|
||||
end
|
||||
end
|
||||
|
||||
def test_last_bang_present
|
||||
assert_nothing_raised do
|
||||
assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").last!
|
||||
@ -215,6 +228,14 @@ def test_last_bang_missing
|
||||
end
|
||||
end
|
||||
|
||||
def test_model_class_responds_to_last_bang
|
||||
assert_equal topics(:fourth), Topic.last!
|
||||
assert_raises ActiveRecord::RecordNotFound do
|
||||
Topic.delete_all
|
||||
Topic.last!
|
||||
end
|
||||
end
|
||||
|
||||
def test_unexisting_record_exception_handling
|
||||
assert_raise(ActiveRecord::RecordNotFound) {
|
||||
Topic.find(1).parent
|
||||
|
@ -22,6 +22,33 @@ def set_logger(logger)
|
||||
ActiveRecord::Base.logger = logger
|
||||
end
|
||||
|
||||
def test_schema_statements_are_ignored
|
||||
event = Struct.new(:duration, :payload)
|
||||
|
||||
logger = Class.new(ActiveRecord::LogSubscriber) {
|
||||
attr_accessor :debugs
|
||||
|
||||
def initialize
|
||||
@debugs = []
|
||||
super
|
||||
end
|
||||
|
||||
def debug message
|
||||
@debugs << message
|
||||
end
|
||||
}.new
|
||||
assert_equal 0, logger.debugs.length
|
||||
|
||||
logger.sql(event.new(0, { :sql => 'hi mom!' }))
|
||||
assert_equal 1, logger.debugs.length
|
||||
|
||||
logger.sql(event.new(0, { :sql => 'hi mom!', :name => 'foo' }))
|
||||
assert_equal 2, logger.debugs.length
|
||||
|
||||
logger.sql(event.new(0, { :sql => 'hi mom!', :name => 'SCHEMA' }))
|
||||
assert_equal 2, logger.debugs.length
|
||||
end
|
||||
|
||||
def test_basic_query_logging
|
||||
Developer.all
|
||||
wait
|
||||
|
@ -64,7 +64,7 @@ def test_subclasses_inherit_scopes
|
||||
assert Reply.scopes.include?(:base)
|
||||
assert_equal Reply.find(:all), Reply.base
|
||||
end
|
||||
|
||||
|
||||
def test_classes_dont_inherit_subclasses_scopes
|
||||
assert !ActiveRecord::Base.scopes.include?(:base)
|
||||
end
|
||||
@ -246,6 +246,12 @@ def test_any_should_not_fire_query_if_scope_loaded
|
||||
assert_no_queries { assert topics.any? }
|
||||
end
|
||||
|
||||
def test_model_class_should_respond_to_any
|
||||
assert Topic.any?
|
||||
Topic.delete_all
|
||||
assert !Topic.any?
|
||||
end
|
||||
|
||||
def test_many_should_not_load_results
|
||||
topics = Topic.base
|
||||
assert_queries(2) do
|
||||
@ -280,6 +286,15 @@ def test_many_should_return_true_if_more_than_one
|
||||
assert Topic.base.many?
|
||||
end
|
||||
|
||||
def test_model_class_should_respond_to_many
|
||||
Topic.delete_all
|
||||
assert !Topic.many?
|
||||
Topic.create!
|
||||
assert !Topic.many?
|
||||
Topic.create!
|
||||
assert Topic.many?
|
||||
end
|
||||
|
||||
def test_should_build_on_top_of_scope
|
||||
topic = Topic.approved.build({})
|
||||
assert topic.approved
|
||||
|
@ -327,6 +327,68 @@ def test_destroy_record_with_associations
|
||||
assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" }
|
||||
end
|
||||
|
||||
def test_update_attribute
|
||||
assert !Topic.find(1).approved?
|
||||
Topic.find(1).update_attribute("approved", true)
|
||||
assert Topic.find(1).approved?
|
||||
|
||||
Topic.find(1).update_attribute(:approved, false)
|
||||
assert !Topic.find(1).approved?
|
||||
end
|
||||
|
||||
def test_update_attribute_for_readonly_attribute
|
||||
minivan = Minivan.find('m1')
|
||||
assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, 'black') }
|
||||
end
|
||||
|
||||
# This test is correct, but it is hard to fix it since
|
||||
# update_attribute trigger simply call save! that triggers
|
||||
# all callbacks.
|
||||
# def test_update_attribute_with_one_changed_and_one_updated
|
||||
# t = Topic.order('id').limit(1).first
|
||||
# title, author_name = t.title, t.author_name
|
||||
# t.author_name = 'John'
|
||||
# t.update_attribute(:title, 'super_title')
|
||||
# assert_equal 'John', t.author_name
|
||||
# assert_equal 'super_title', t.title
|
||||
# assert t.changed?, "topic should have changed"
|
||||
# assert t.author_name_changed?, "author_name should have changed"
|
||||
# assert !t.title_changed?, "title should not have changed"
|
||||
# assert_nil t.title_change, 'title change should be nil'
|
||||
# assert_equal ['author_name'], t.changed
|
||||
#
|
||||
# t.reload
|
||||
# assert_equal 'David', t.author_name
|
||||
# assert_equal 'super_title', t.title
|
||||
# end
|
||||
|
||||
def test_update_attribute_with_one_updated
|
||||
t = Topic.first
|
||||
title = t.title
|
||||
t.update_attribute(:title, 'super_title')
|
||||
assert_equal 'super_title', t.title
|
||||
assert !t.changed?, "topic should not have changed"
|
||||
assert !t.title_changed?, "title should not have changed"
|
||||
assert_nil t.title_change, 'title change should be nil'
|
||||
|
||||
t.reload
|
||||
assert_equal 'super_title', t.title
|
||||
end
|
||||
|
||||
def test_update_attribute_for_updated_at_on
|
||||
developer = Developer.find(1)
|
||||
prev_month = Time.now.prev_month
|
||||
|
||||
developer.update_attribute(:updated_at, prev_month)
|
||||
assert_equal prev_month, developer.updated_at
|
||||
|
||||
developer.update_attribute(:salary, 80001)
|
||||
assert_not_equal prev_month, developer.updated_at
|
||||
|
||||
developer.reload
|
||||
assert_not_equal prev_month, developer.updated_at
|
||||
end
|
||||
|
||||
def test_update_column
|
||||
topic = Topic.find(1)
|
||||
topic.update_column("approved", true)
|
||||
@ -340,6 +402,35 @@ def test_update_column
|
||||
assert !topic.approved?
|
||||
end
|
||||
|
||||
def test_update_column_should_not_use_setter_method
|
||||
dev = Developer.find(1)
|
||||
dev.instance_eval { def salary=(value); write_attribute(:salary, value * 2); end }
|
||||
|
||||
dev.update_column(:salary, 80000)
|
||||
assert_equal 80000, dev.salary
|
||||
|
||||
dev.reload
|
||||
assert_equal 80000, dev.salary
|
||||
end
|
||||
|
||||
def test_update_column_should_raise_exception_if_new_record
|
||||
topic = Topic.new
|
||||
assert_raises(ActiveRecord::ActiveRecordError) { topic.update_column("approved", false) }
|
||||
end
|
||||
|
||||
def test_update_column_should_not_leave_the_object_dirty
|
||||
topic = Topic.find(1)
|
||||
topic.update_attribute("content", "Have a nice day")
|
||||
|
||||
topic.reload
|
||||
topic.update_column(:content, "You too")
|
||||
assert_equal [], topic.changed
|
||||
|
||||
topic.reload
|
||||
topic.update_column("content", "Have a nice day")
|
||||
assert_equal [], topic.changed
|
||||
end
|
||||
|
||||
def test_update_column_with_model_having_primary_key_other_than_id
|
||||
minivan = Minivan.find('m1')
|
||||
new_name = 'sebavan'
|
||||
@ -366,7 +457,7 @@ def test_update_column_should_not_modify_updated_at
|
||||
assert_equal prev_month, developer.updated_at
|
||||
|
||||
developer.reload
|
||||
assert_equal prev_month, developer.updated_at
|
||||
assert_equal prev_month.to_i, developer.updated_at.to_i
|
||||
end
|
||||
|
||||
def test_update_column_with_one_changed_and_one_updated
|
||||
@ -378,7 +469,6 @@ def test_update_column_with_one_changed_and_one_updated
|
||||
assert_equal 'super_title', t.title
|
||||
assert t.changed?, "topic should have changed"
|
||||
assert t.author_name_changed?, "author_name should have changed"
|
||||
assert t.title_changed?, "title should have changed"
|
||||
|
||||
t.reload
|
||||
assert_equal author_name, t.author_name
|
||||
|
@ -136,4 +136,13 @@ def test_primary_key_returns_nil_if_it_does_not_exist
|
||||
assert_nil ActiveRecord::Base.connection.primary_key('developers_projects')
|
||||
end
|
||||
end
|
||||
|
||||
def test_quoted_primary_key_after_set_primary_key
|
||||
k = Class.new( ActiveRecord::Base )
|
||||
assert_equal k.connection.quote_column_name("id"), k.quoted_primary_key
|
||||
k.primary_key = "foo"
|
||||
assert_equal k.connection.quote_column_name("foo"), k.quoted_primary_key
|
||||
k.set_primary_key "bar"
|
||||
assert_equal k.connection.quote_column_name("bar"), k.quoted_primary_key
|
||||
end
|
||||
end
|
||||
|
@ -429,9 +429,9 @@ def test_scope_overwrites_default
|
||||
assert_equal expected, received
|
||||
end
|
||||
|
||||
def test_except_and_order_overrides_default_scope_order
|
||||
def test_reorder_overrides_default_scope_order
|
||||
expected = Developer.order('name DESC').collect { |dev| dev.name }
|
||||
received = DeveloperOrderedBySalary.except(:order).order('name DESC').collect { |dev| dev.name }
|
||||
received = DeveloperOrderedBySalary.reorder('name DESC').collect { |dev| dev.name }
|
||||
assert_equal expected, received
|
||||
end
|
||||
|
||||
|
@ -151,6 +151,12 @@ def test_finding_with_order_concatenated
|
||||
assert_equal topics(:fourth).title, topics.first.title
|
||||
end
|
||||
|
||||
def test_finding_with_reorder
|
||||
topics = Topic.order('author_name').order('title').reorder('id').all
|
||||
topics_titles = topics.map{ |t| t.title }
|
||||
assert_equal ['The First Topic', 'The Second Topic of the day', 'The Third Topic of the day', 'The Fourth Topic of the day'], topics_titles
|
||||
end
|
||||
|
||||
def test_finding_with_order_and_take
|
||||
entrants = Entrant.order("id ASC").limit(2).to_a
|
||||
|
||||
@ -666,6 +672,34 @@ def test_size
|
||||
assert_no_queries { assert_equal 9, best_posts.size }
|
||||
end
|
||||
|
||||
def test_size_with_limit
|
||||
posts = Post.limit(10)
|
||||
|
||||
assert_queries(1) { assert_equal 10, posts.size }
|
||||
assert ! posts.loaded?
|
||||
|
||||
best_posts = posts.where(:comments_count => 0)
|
||||
best_posts.to_a # force load
|
||||
assert_no_queries { assert_equal 9, best_posts.size }
|
||||
end
|
||||
|
||||
def test_size_with_zero_limit
|
||||
posts = Post.limit(0)
|
||||
|
||||
assert_no_queries { assert_equal 0, posts.size }
|
||||
assert ! posts.loaded?
|
||||
|
||||
posts.to_a # force load
|
||||
assert_no_queries { assert_equal 0, posts.size }
|
||||
end
|
||||
|
||||
def test_empty_with_zero_limit
|
||||
posts = Post.limit(0)
|
||||
|
||||
assert_no_queries { assert_equal true, posts.empty? }
|
||||
assert ! posts.loaded?
|
||||
end
|
||||
|
||||
def test_count_complex_chained_relations
|
||||
posts = Post.select('comments_count').where('id is not null').group("author_id").where("comments_count > 0")
|
||||
|
||||
|
@ -113,8 +113,7 @@ def test_touching_a_record_with_a_belongs_to_that_uses_a_counter_cache_should_up
|
||||
|
||||
pet = Pet.first
|
||||
owner = pet.owner
|
||||
owner.happy_at = 3.days.ago
|
||||
owner.save
|
||||
owner.update_attribute(:happy_at, 3.days.ago)
|
||||
previously_owner_updated_at = owner.updated_at
|
||||
|
||||
pet.name = "I'm a parrot"
|
||||
|
@ -17,7 +17,6 @@
|
||||
s.files = Dir['CHANGELOG', 'README.rdoc', 'examples/**/*', 'lib/**/*']
|
||||
s.require_path = 'lib'
|
||||
|
||||
s.has_rdoc = true
|
||||
s.extra_rdoc_files = %w( README.rdoc )
|
||||
s.rdoc_options.concat ['--main', 'README.rdoc']
|
||||
|
||||
|
@ -16,6 +16,4 @@
|
||||
|
||||
s.files = Dir['CHANGELOG', 'README.rdoc', 'lib/**/*']
|
||||
s.require_path = 'lib'
|
||||
|
||||
s.has_rdoc = true
|
||||
end
|
||||
|
@ -9,7 +9,7 @@ module Util
|
||||
# A utility method for escaping HTML tag characters.
|
||||
# This method is also aliased as <tt>h</tt>.
|
||||
#
|
||||
# In your ERb templates, use this method to escape any unsafe content. For example:
|
||||
# In your ERB templates, use this method to escape any unsafe content. For example:
|
||||
# <%=h @person.name %>
|
||||
#
|
||||
# ==== Example:
|
||||
|
@ -5,16 +5,9 @@
|
||||
require 'active_support/testing/declarative'
|
||||
require 'active_support/testing/pending'
|
||||
require 'active_support/testing/isolation'
|
||||
require 'active_support/testing/mochaing'
|
||||
require 'active_support/core_ext/kernel/reporting'
|
||||
|
||||
begin
|
||||
silence_warnings { require 'mocha' }
|
||||
rescue LoadError
|
||||
# Fake Mocha::ExpectationError so we can rescue it in #run. Bleh.
|
||||
Object.const_set :Mocha, Module.new
|
||||
Mocha.const_set :ExpectationError, Class.new(StandardError)
|
||||
end
|
||||
|
||||
module ActiveSupport
|
||||
class TestCase < ::Test::Unit::TestCase
|
||||
if defined? MiniTest
|
||||
|
7
activesupport/lib/active_support/testing/mochaing.rb
Normal file
7
activesupport/lib/active_support/testing/mochaing.rb
Normal file
@ -0,0 +1,7 @@
|
||||
begin
|
||||
silence_warnings { require 'mocha' }
|
||||
rescue LoadError
|
||||
# Fake Mocha::ExpectationError so we can rescue it in #run. Bleh.
|
||||
Object.const_set :Mocha, Module.new
|
||||
Mocha.const_set :ExpectationError, Class.new(StandardError)
|
||||
end
|
@ -11,32 +11,36 @@ module Pending
|
||||
@@at_exit = false
|
||||
|
||||
def pending(description = "", &block)
|
||||
if description.is_a?(Symbol)
|
||||
is_pending = $tags[description]
|
||||
return block.call unless is_pending
|
||||
end
|
||||
|
||||
if block_given?
|
||||
failed = false
|
||||
|
||||
begin
|
||||
block.call
|
||||
rescue Exception
|
||||
failed = true
|
||||
if defined?(::MiniTest)
|
||||
skip(description.blank? ? nil : description)
|
||||
else
|
||||
if description.is_a?(Symbol)
|
||||
is_pending = $tags[description]
|
||||
return block.call unless is_pending
|
||||
end
|
||||
|
||||
flunk("<#{description}> did not fail.") unless failed
|
||||
end
|
||||
if block_given?
|
||||
failed = false
|
||||
|
||||
caller[0] =~ (/(.*):(.*):in `(.*)'/)
|
||||
@@pending_cases << "#{$3} at #{$1}, line #{$2}"
|
||||
print "P"
|
||||
begin
|
||||
block.call
|
||||
rescue Exception
|
||||
failed = true
|
||||
end
|
||||
|
||||
@@at_exit ||= begin
|
||||
at_exit do
|
||||
puts "\nPending Cases:"
|
||||
@@pending_cases.each do |test_case|
|
||||
puts test_case
|
||||
flunk("<#{description}> did not fail.") unless failed
|
||||
end
|
||||
|
||||
caller[0] =~ (/(.*):(.*):in `(.*)'/)
|
||||
@@pending_cases << "#{$3} at #{$1}, line #{$2}"
|
||||
print "P"
|
||||
|
||||
@@at_exit ||= begin
|
||||
at_exit do
|
||||
puts "\nPending Cases:"
|
||||
@@pending_cases.each do |test_case|
|
||||
puts test_case
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
s.bindir = 'bin'
|
||||
s.executables = ['rails']
|
||||
s.default_executable = 'rails'
|
||||
|
||||
s.add_dependency('activesupport', version)
|
||||
s.add_dependency('actionpack', version)
|
||||
|
@ -1,5 +1,9 @@
|
||||
*Rails 3.1.0 (unreleased)*
|
||||
|
||||
* Add using Turn with natural language test case names for test_help.rb when running with minitest (Ruby 1.9.2+) [DHH]
|
||||
|
||||
* Direct logging of Active Record to STDOUT so it's shown inline with the results in the console [DHH]
|
||||
|
||||
* Added `config.force_ssl` configuration which loads Rack::SSL middleware and force all requests to be under HTTPS protocol [DHH, Prem Sichanugrist, and Josh Peek]
|
||||
|
||||
* Added `rails plugin new` command which generates rails plugin with gemspec, tests and dummy application for testing [Piotr Sarnacki]
|
||||
|
@ -1295,7 +1295,7 @@ end
|
||||
|
||||
h5. update_page_tag
|
||||
|
||||
Works like update_page but wraps the generated JavaScript in a +script+ tag. Use this to include generated JavaScript in an ERb template.
|
||||
Works like update_page but wraps the generated JavaScript in a +script+ tag. Use this to include generated JavaScript in an ERB template.
|
||||
|
||||
h4. PrototypeHelper::JavaScriptGenerator::GeneratorMethods
|
||||
|
||||
|
@ -962,6 +962,26 @@ Client.exists?
|
||||
|
||||
The above returns +false+ if the +clients+ table is empty and +true+ otherwise.
|
||||
|
||||
You can also use +any?+ and +many?+ to check for existence on a model or relation.
|
||||
|
||||
<ruby>
|
||||
# via a model
|
||||
Post.any?
|
||||
Post.many?
|
||||
|
||||
# via a named scope
|
||||
Post.recent.any?
|
||||
Post.recent.many?
|
||||
|
||||
# via a relation
|
||||
Post.where(:published => true).any?
|
||||
Post.where(:published => true).many?
|
||||
|
||||
# via an association
|
||||
Post.first.categories.any?
|
||||
Post.first.categories.many?
|
||||
</ruby>
|
||||
|
||||
h3. Calculations
|
||||
|
||||
This section uses count as an example method in this preamble, but the options described apply to all sub-sections.
|
||||
|
@ -29,7 +29,7 @@ Documentation has to be concise but comprehensive. Explore and document edge cas
|
||||
|
||||
The proper names of Rails components have a space in between the words, like "Active Support". +ActiveRecord+ is a Ruby module, whereas Active Record is an ORM. All Rails documentation should consistently refer to Rails components by their proper name, and if in your next blog post or presentation you remember this tidbit and take it into account that'd be phenomenal.
|
||||
|
||||
Spell names correctly: Arel, Test::Unit, RSpec, HTML, MySQL, JavaScript, ERb. When in doubt, please have a look at some authoritative source like their official documentation.
|
||||
Spell names correctly: Arel, Test::Unit, RSpec, HTML, MySQL, JavaScript, ERB. When in doubt, please have a look at some authoritative source like their official documentation.
|
||||
|
||||
Use the article "an" for "SQL", as in "an SQL statement". Also "an SQLite database".
|
||||
|
||||
|
@ -484,7 +484,7 @@ end
|
||||
We take whatever args are supplied, save them to an instance variable, and literally copying from the Rails source, implement a +manifest+ method, which calls +record+ with a block, and we:
|
||||
|
||||
* Check there's a *public* directory. You bet there is.
|
||||
* Run the ERb template called "tutorial.erb".
|
||||
* Run the ERB template called "tutorial.erb".
|
||||
* Save it into "Rails.root/public/tutorial.txt".
|
||||
* Pass in the arguments we saved through the +:assigns+ parameter.
|
||||
|
||||
|
@ -478,8 +478,7 @@ The next line in +config/application.rb+ is:
|
||||
require 'rails/all'
|
||||
</ruby>
|
||||
|
||||
h4 +railties/lib/rails/all.rb+
|
||||
|
||||
h4. +railties/lib/rails/all.rb+
|
||||
|
||||
This file is responsible for requiring all the individual parts of Rails like so:
|
||||
|
||||
@ -591,7 +590,7 @@ h4. +activesupport/lib/active_support/deprecation/behaviors.rb+
|
||||
|
||||
This file defines the behavior of the +ActiveSupport::Deprecation+ module, setting up the +DEFAULT_BEHAVIORS+ hash constant which contains the three defaults to outputting deprecation warnings: +:stderr+, +:log+ and +:notify+. This file begins by requiring +activesupport/notifications+ and +activesupport/core_ext/array/wrap+.
|
||||
|
||||
h4 +activesupport/lib/active_support/notifications.rb+
|
||||
h4. +activesupport/lib/active_support/notifications.rb+
|
||||
|
||||
TODO: document +ActiveSupport::Notifications+.
|
||||
|
||||
|
@ -557,6 +557,18 @@ match '*a/foo/*b' => 'test#index'
|
||||
|
||||
would match +zoo/woo/foo/bar/baz+ with +params[:a]+ equals +"zoo/woo"+, and +params[:b]+ equals +"bar/baz"+.
|
||||
|
||||
NOTE: Starting from Rails 3.1, wildcard route will always matching the optional format segment by default. For example if you have this route:
|
||||
|
||||
<ruby>
|
||||
map '*pages' => 'pages#show'
|
||||
</ruby>
|
||||
|
||||
NOTE: By requesting +"/foo/bar.json"+, your +params[:pages]+ will be equals to +"foo/bar"+ with the request format of JSON. If you want the old 3.0.x behavior back, you could supply +:format => false+ like this:
|
||||
|
||||
<ruby>
|
||||
map '*pages' => 'pages#show', :format => false
|
||||
</ruby>
|
||||
|
||||
h4. Redirection
|
||||
|
||||
You can redirect any path to another path using the +redirect+ helper in your router:
|
||||
|
@ -10,10 +10,10 @@ Guides are written in "Textile":http://www.textism.com/tools/textile/. There's c
|
||||
|
||||
h3. Prologue
|
||||
|
||||
Each guide should start with motivational text at the top. That's the little introduction in the blue area. The prologue should tell the readers what's the guide about, and what will they learn. See for example the "Routing Guide":routing.html.
|
||||
Each guide should start with motivational text at the top (that's the little introduction in the blue area.) The prologue should tell the reader what the guide is about, and what they will learn. See for example the "Routing Guide":routing.html.
|
||||
|
||||
h3. Titles
|
||||
|
||||
|
||||
The title of every guide uses +h2+, guide sections use +h3+, subsections +h4+, etc.
|
||||
|
||||
Capitalize all words except for internal articles, prepositions, conjunctions, and forms of the verb to be:
|
||||
@ -23,7 +23,7 @@ h5. Middleware Stack is an Array
|
||||
h5. When are Objects Saved?
|
||||
</plain>
|
||||
|
||||
Use same typography as in regular text:
|
||||
Use the same typography as in regular text:
|
||||
|
||||
<plain>
|
||||
h6. The +:content_type+ Option
|
||||
@ -42,13 +42,13 @@ Those guidelines apply also to guides.
|
||||
|
||||
h3. HTML Generation
|
||||
|
||||
To generate all the guides just cd into the +railties+ directory and execute
|
||||
To generate all the guides, just +cd+ into the +railties+ directory and execute:
|
||||
|
||||
<plain>
|
||||
bundle exec rake generate_guides
|
||||
</plain>
|
||||
|
||||
You'll need the gems erubis, i18n, and RedCloth.
|
||||
(You may need to run +bundle install+ first to install the required gems.)
|
||||
|
||||
To process +my_guide.textile+ and nothing else use the +ONLY+ environment variable:
|
||||
|
||||
@ -56,13 +56,13 @@ To process +my_guide.textile+ and nothing else use the +ONLY+ environment variab
|
||||
bundle exec rake generate_guides ONLY=my_guide
|
||||
</plain>
|
||||
|
||||
Although by default guides that have not been modified are not processed, so +ONLY+ is rarely needed in practice.
|
||||
By default, guides that have not been modified are not processed, so +ONLY+ is rarely needed in practice.
|
||||
|
||||
To force process of all the guides, pass +ALL=1+.
|
||||
|
||||
It is also recommended that you work with +WARNINGS=1+, this detects duplicate IDs and warns about broken internal links.
|
||||
It is also recommended that you work with +WARNINGS=1+. This detects duplicate IDs and warns about broken internal links.
|
||||
|
||||
If you want to generate guides in languages other than English, you can keep them in a separate directory under +source+ (eg. <tt>source/es</tt>) and use the +LANGUAGE+ environment variable.
|
||||
If you want to generate guides in languages other than English, you can keep them in a separate directory under +source+ (eg. <tt>source/es</tt>) and use the +LANGUAGE+ environment variable:
|
||||
|
||||
<plain>
|
||||
rake generate_guides LANGUAGE=es
|
||||
@ -70,7 +70,7 @@ rake generate_guides LANGUAGE=es
|
||||
|
||||
h3. HTML Validation
|
||||
|
||||
Please do validate the generated HTML with
|
||||
Please validate the generated HTML with:
|
||||
|
||||
<plain>
|
||||
rake validate_guides
|
||||
@ -80,4 +80,5 @@ Particularly, titles get an ID generated from their content and this often leads
|
||||
|
||||
h3. Changelog
|
||||
|
||||
* March 31, 2011: grammar tweaks by "Josiah Ivey":http://twitter.com/josiahivey
|
||||
* October 5, 2010: ported from the docrails wiki and revised by "Xavier Noria":credits.html#fxn
|
||||
|
@ -79,9 +79,9 @@ steve:
|
||||
|
||||
Each fixture is given a name followed by an indented list of colon-separated key/value pairs. Records are separated by a blank space. You can place comments in a fixture file by using the # character in the first column.
|
||||
|
||||
h5. ERb'in It Up
|
||||
h5. ERB'in It Up
|
||||
|
||||
ERb allows you to embed ruby code within templates. Both the YAML and CSV fixture formats are pre-processed with ERb when you load fixtures. This allows you to use Ruby to help you generate some sample data.
|
||||
ERB allows you to embed ruby code within templates. Both the YAML and CSV fixture formats are pre-processed with ERB when you load fixtures. This allows you to use Ruby to help you generate some sample data.
|
||||
|
||||
<erb>
|
||||
<% earth_size = 20 %>
|
||||
@ -391,7 +391,7 @@ There are a bunch of different types of assertions you can use. Here's the compl
|
||||
|+assert_nil( obj, [msg] )+ |Ensures that +obj.nil?+ is true.|
|
||||
|+assert_not_nil( obj, [msg] )+ |Ensures that +obj.nil?+ is false.|
|
||||
|+assert_match( regexp, string, [msg] )+ |Ensures that a string matches the regular expression.|
|
||||
|+assert_no_match( regexp, string, [msg] )+ |Ensures that a string doesn't matches the regular expression.|
|
||||
|+assert_no_match( regexp, string, [msg] )+ |Ensures that a string doesn't match the regular expression.|
|
||||
|+assert_in_delta( expecting, actual, delta, [msg] )+ |Ensures that the numbers +expecting+ and +actual+ are within +delta+ of each other.|
|
||||
|+assert_throws( symbol, [msg] ) { block }+ |Ensures that the given block throws the symbol.|
|
||||
|+assert_raise( exception1, exception2, ... ) { block }+ |Ensures that the given block raises one of the given exceptions.|
|
||||
|
@ -34,6 +34,10 @@ def start
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
if defined?(ActiveRecord)
|
||||
ActiveRecord::Base.logger = Logger.new(STDERR)
|
||||
end
|
||||
|
||||
if options[:sandbox]
|
||||
puts "Loading #{Rails.env} environment in sandbox (Rails #{Rails.version})"
|
||||
|
@ -360,11 +360,11 @@ def endpoint(endpoint = nil)
|
||||
def isolate_namespace(mod)
|
||||
engine_name(generate_railtie_name(mod))
|
||||
|
||||
name = engine_name
|
||||
self.routes.default_scope = {:module => name}
|
||||
self.routes.default_scope = { :module => ActiveSupport::Inflector.underscore(mod.name) }
|
||||
self.isolated = true
|
||||
|
||||
unless mod.respond_to?(:_railtie)
|
||||
name = engine_name
|
||||
_railtie = self
|
||||
mod.singleton_class.instance_eval do
|
||||
define_method(:_railtie) do
|
||||
|
@ -1,5 +1,6 @@
|
||||
require 'digest/md5'
|
||||
require 'active_support/secure_random'
|
||||
require 'active_support/core_ext/string/strip'
|
||||
require 'rails/version' unless defined?(Rails::VERSION)
|
||||
require 'rbconfig'
|
||||
require 'open-uri'
|
||||
@ -112,30 +113,38 @@ def set_default_accessors!
|
||||
end
|
||||
|
||||
def database_gemfile_entry
|
||||
options[:skip_active_record] ? "" : "gem '#{gem_for_database}'"
|
||||
entry = options[:skip_active_record] ? "" : "gem '#{gem_for_database}'"
|
||||
if options[:database] == 'mysql'
|
||||
if options.dev? || options.edge?
|
||||
entry += ", :git => 'git://github.com/brianmario/mysql2.git'"
|
||||
else
|
||||
entry += "\n# gem 'mysql2', :git => 'git://github.com/brianmario/mysql2.git'"
|
||||
end
|
||||
end
|
||||
entry
|
||||
end
|
||||
|
||||
def rails_gemfile_entry
|
||||
if options.dev?
|
||||
<<-GEMFILE
|
||||
gem 'rails', :path => '#{Rails::Generators::RAILS_DEV_PATH}'
|
||||
gem 'arel', :git => 'git://github.com/rails/arel.git'
|
||||
gem "rack", :git => "git://github.com/rack/rack.git"
|
||||
<<-GEMFILE.strip_heredoc
|
||||
gem 'rails', :path => '#{Rails::Generators::RAILS_DEV_PATH}'
|
||||
gem 'arel', :git => 'git://github.com/rails/arel.git'
|
||||
gem 'rack', :git => 'git://github.com/rack/rack.git'
|
||||
GEMFILE
|
||||
elsif options.edge?
|
||||
<<-GEMFILE
|
||||
gem 'rails', :git => 'git://github.com/rails/rails.git'
|
||||
gem 'arel', :git => 'git://github.com/rails/arel.git'
|
||||
gem "rack", :git => "git://github.com/rack/rack.git"
|
||||
<<-GEMFILE.strip_heredoc
|
||||
gem 'rails', :git => 'git://github.com/rails/rails.git'
|
||||
gem 'arel', :git => 'git://github.com/rails/arel.git'
|
||||
gem 'rack', :git => 'git://github.com/rack/rack.git'
|
||||
GEMFILE
|
||||
else
|
||||
<<-GEMFILE
|
||||
gem 'rails', '#{Rails::VERSION::STRING}'
|
||||
<<-GEMFILE.strip_heredoc
|
||||
gem 'rails', '#{Rails::VERSION::STRING}'
|
||||
|
||||
# Bundle edge Rails instead:
|
||||
# gem 'rails', :git => 'git://github.com/rails/rails.git'
|
||||
# gem 'arel', :git => 'git://github.com/rails/arel.git'
|
||||
# gem "rack", :git => "git://github.com/rack/rack.git"
|
||||
# Bundle edge Rails instead:
|
||||
# gem 'rails', :git => 'git://github.com/rails/rails.git'
|
||||
# gem 'arel', :git => 'git://github.com/rails/arel.git'
|
||||
# gem 'rack', :git => 'git://github.com/rack/rack.git'
|
||||
GEMFILE
|
||||
end
|
||||
end
|
||||
|
@ -11,7 +11,7 @@
|
||||
#
|
||||
# Annotations are looked for in comments and modulus whitespace they have to
|
||||
# start with the tag optionally followed by a colon. Everything up to the end
|
||||
# of the line (or closing ERb comment tag) is considered to be their text.
|
||||
# of the line (or closing ERB comment tag) is considered to be their text.
|
||||
class SourceAnnotationExtractor
|
||||
class Annotation < Struct.new(:line, :tag, :text)
|
||||
|
||||
@ -99,4 +99,4 @@ def display(results, options={})
|
||||
puts
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -13,6 +13,14 @@
|
||||
Test::Unit::Util::BacktraceFilter.module_eval { include Rails::BacktraceFilterForTestUnit }
|
||||
end
|
||||
|
||||
if defined?(MiniTest)
|
||||
require 'turn'
|
||||
|
||||
if MiniTest::Unit.respond_to?(:use_natural_language_case_names=)
|
||||
MiniTest::Unit.use_natural_language_case_names = true
|
||||
end
|
||||
end
|
||||
|
||||
if defined?(ActiveRecord)
|
||||
require 'active_record/test_case'
|
||||
|
||||
|
@ -17,11 +17,11 @@
|
||||
s.require_path = 'lib'
|
||||
|
||||
s.rdoc_options << '--exclude' << '.'
|
||||
s.has_rdoc = false
|
||||
|
||||
s.add_dependency('rake', '>= 0.8.7')
|
||||
s.add_dependency('thor', '~> 0.14.4')
|
||||
s.add_dependency('rack-ssl', '~> 1.3.2')
|
||||
s.add_dependency('turn', '~> 0.8.2')
|
||||
s.add_dependency('activesupport', version)
|
||||
s.add_dependency('actionpack', version)
|
||||
end
|
||||
|
@ -559,6 +559,45 @@ def new
|
||||
assert_match /name="post\[title\]"/, last_response.body
|
||||
end
|
||||
|
||||
test "isolated engine should set correct route module prefix for nested namespace" do
|
||||
@plugin.write "lib/bukkits.rb", <<-RUBY
|
||||
module Bukkits
|
||||
module Awesome
|
||||
class Engine < ::Rails::Engine
|
||||
isolate_namespace Bukkits::Awesome
|
||||
end
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
app_file "config/routes.rb", <<-RUBY
|
||||
AppTemplate::Application.routes.draw do
|
||||
mount Bukkits::Awesome::Engine => "/bukkits", :as => "bukkits"
|
||||
end
|
||||
RUBY
|
||||
|
||||
@plugin.write "config/routes.rb", <<-RUBY
|
||||
Bukkits::Awesome::Engine.routes.draw do
|
||||
match "/foo" => "foo#index"
|
||||
end
|
||||
RUBY
|
||||
|
||||
@plugin.write "app/controllers/bukkits/awesome/foo_controller.rb", <<-RUBY
|
||||
class Bukkits::Awesome::FooController < ActionController::Base
|
||||
def index
|
||||
render :text => "ok"
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
add_to_config("config.action_dispatch.show_exceptions = false")
|
||||
|
||||
boot_rails
|
||||
|
||||
get("/bukkits/foo")
|
||||
assert_equal "ok", last_response.body
|
||||
end
|
||||
|
||||
test "loading seed data" do
|
||||
@plugin.write "db/seeds.rb", <<-RUBY
|
||||
Bukkits::Engine.config.bukkits_seeds_loaded = true
|
||||
|
Loading…
Reference in New Issue
Block a user