Freeze to rails 1.1.5. The only change I needed to make for compatibility was to ApplicationController#init_not_done_counts

git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@306 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
lukemelia 2006-08-10 03:22:47 +00:00
parent 45739e12de
commit a36b736c6a
74 changed files with 1064 additions and 535 deletions

View file

@ -90,8 +90,8 @@ class ApplicationController < ActionController::Base
def init_not_done_counts(parents = ['project','context'])
parents.each {|parent|
eval("@#{parent}_not_done_counts = Todo.count(:todo,
:conditions => ['todos.user_id = ? and todos.type = ? and todos.done = ?', @user.id, \"Immediate\", false],
eval("@#{parent}_not_done_counts = Todo.count(:all,
:conditions => ['user_id = ? and type = ? and done = ?', @user.id, \"Immediate\", false],
:group => :#{parent}_id)")
}
end

View file

@ -1,3 +0,0 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../config/boot'
require 'commands/process/spinner'

View file

@ -1,3 +1,22 @@
*1.2.4* (August 8th, 2006)
* Backport of documentation enhancements. [Kevin Clark, Marcel Molina Jr]
* Correct spurious documentation example code which results in a SyntaxError. [Marcel Molina Jr.]
* Mailer template root applies to a class and its subclasses rather than acting globally. #5555 [somekool@gmail.com]
*1.2.3* (June 29th, 2006)
* Depend on Action Pack 1.12.3
*1.2.2* (June 27th, 2006)
* Depend on Action Pack 1.12.2
*1.2.1* (April 6th, 2005)
* Be part of Rails 1.1.1

View file

@ -5,20 +5,92 @@ require 'action_mailer/utils'
require 'tmail/net'
module ActionMailer #:nodoc:
# Usage:
# ActionMailer allows you to send email from your application using a mailer model and views.
#
# class ApplicationMailer < ActionMailer::Base
# # Set up properties
# # Properties can also be specified via accessor methods
# # (i.e. self.subject = "foo") and instance variables (@subject = "foo").
# = Mailer Models
# To use ActionMailer, you need to create a mailer model.
#
# $ script/generate mailer Notifier
#
# The generated model inherits from ActionMailer::Base. Emails are defined by creating methods within the model which are then
# used to set variables to be used in the mail template, to change options on the mail, or
# to add attachments.
#
# Examples:
#
# class Notifier < ActionMailer::Base
# def signup_notification(recipient)
# recipients recipient.email_address_with_name
# from "system@example.com"
# subject "New account information"
# body "account" => recipient
# end
# end
#
# Mailer methods have the following configuration methods available.
#
# * <tt>recipients</tt> - Takes one or more email addresses. These addresses are where your email will be delivered to. Sets the <tt>To:</tt> header.
# * <tt>subject</tt> - The subject of your email. Sets the <tt>Subject:</tt> header.
# * <tt>from</tt> - Who the email you are sending is from. Sets the <tt>From:</tt> header.
# * <tt>cc</tt> - Takes one or more email addresses. These addresses will receive a carbon copy of your email. Sets the <tt>Cc:</tt> header.
# * <tt>bcc</tt> - Takes one or more email address. These addresses will receive a blind carbon copy of your email. Sets the <tt>Bcc</tt> header.
# * <tt>sent_on</tt> - The date on which the message was sent. If not set, the header wil be set by the delivery agent.
# * <tt>content_type</tt> - Specify the content type of the message. Defaults to <tt>text/plain</tt>.
# * <tt>headers</tt> - Specify additional headers to be set for the message, e.g. <tt>headers 'X-Mail-Count' => 107370</tt>.
#
# The <tt>body</tt> method has special behavior. It takes a hash which generates an instance variable
# named after each key in the hash containing the value that that key points to.
#
# So, for example, <tt>body "account" => recipient</tt> would result
# in an instance variable <tt>@account</tt> with the value of <tt>recipient</tt> being accessible in the
# view.
#
# = Mailer Views
# Like ActionController, each mailer class has a corresponding view directory
# in which each method of the class looks for a template with its name.
# To define a template to be used with a mailing, create an <tt>.rhtml</tt> file with the same name as the method
# in your mailer model. For example, in the mailer defined above, the template at
# <tt>app/views/notifier/signup_notification.rhtml</tt> would be used to generate the email.
#
# Variables defined in the model are accessible as instance variables in the view.
#
# Emails by default are sent in plain text, so a sample view for our model example might look like this:
#
# Hi <%= @account.name %>,
# Thanks for joining our service! Please check back often.
#
# = Sending Mail
# Once a mailer action and template are defined, you can deliver your message or create it and save it
# for delivery later:
#
# Notifier.deliver_signup_notification(david) # sends the email
# mail = Notifier.create_signup_notification(david) # => a tmail object
# Notifier.deliver(mail)
#
# You never instantiate your mailer class. Rather, your delivery instance
# methods are automatically wrapped in class methods that start with the word
# <tt>deliver_</tt> followed by the name of the mailer method that you would
# like to deliver. The <tt>signup_notification</tt> method defined above is
# delivered by invoking <tt>Notifier.deliver_signup_notification</tt>.
#
# = HTML Email
# To send mail as HTML, make sure your view (the <tt>.rhtml</tt> file) generates HTML and
# set the content type to html.
#
# class MyMailer < ActionMailer::Base
# def signup_notification(recipient)
# recipients recipient.email_address_with_name
# subject "New account information"
# body { "account" => recipient }
# body "account" => recipient
# from "system@example.com"
# content_type "text/html" # Here's where the magic happens
# end
# end
#
# # explicitly specify multipart messages
# = Multipart Email
# You can explicitly specify multipart messages:
#
# class ApplicationMailer < ActionMailer::Base
# def signup_notification(recipient)
# recipients recipient.email_address_with_name
# subject "New account information"
@ -32,7 +104,28 @@ module ActionMailer #:nodoc:
# p.transfer_encoding = "base64"
# end
# end
# end
#
# Multipart messages can also be used implicitly because ActionMailer will automatically
# detect and use multipart templates, where each template is named after the name of the action, followed
# by the content type. Each such detected template will be added as separate part to the message.
#
# For example, if the following templates existed:
# * signup_notification.text.plain.rhtml
# * signup_notification.text.html.rhtml
# * signup_notification.text.xml.rxml
# * signup_notification.text.x-yaml.rhtml
#
# Each would be rendered and added as a separate part to the message,
# with the corresponding content type. The same body hash is passed to
# each template.
#
# = Attachments
# Attachments can be added by using the +attachment+ method.
#
# Example:
#
# class ApplicationMailer < ActionMailer::Base
# # attachments
# def signup_notification(recipient)
# recipients recipient.email_address_with_name
@ -46,36 +139,7 @@ module ActionMailer #:nodoc:
# a.body = generate_your_pdf_here()
# end
# end
#
# # implicitly multipart messages
# def signup_notification(recipient)
# recipients recipient.email_address_with_name
# subject "New account information"
# from "system@example.com"
# body(:account => "recipient")
#
# # ActionMailer will automatically detect and use multipart templates,
# # where each template is named after the name of the action, followed
# # by the content type. Each such detected template will be added as
# # a separate part to the message.
# #
# # for example, if the following templates existed:
# # * signup_notification.text.plain.rhtml
# # * signup_notification.text.html.rhtml
# # * signup_notification.text.xml.rxml
# # * signup_notification.text.x-yaml.rhtml
# #
# # Each would be rendered and added as a separate part to the message,
# # with the corresponding content type. The same body hash is passed to
# # each template.
# end
# end
#
# # After this, post_notification will look for "templates/application_mailer/post_notification.rhtml"
# ApplicationMailer.template_root = "templates"
#
# ApplicationMailer.create_comment_notification(david, hello_world) # => a tmail object
# ApplicationMailer.deliver_comment_notification(david, hello_world) # sends the email
# end
#
# = Configuration options
#
@ -127,7 +191,7 @@ module ActionMailer #:nodoc:
private_class_method :new #:nodoc:
cattr_accessor :template_root
class_inheritable_accessor :template_root
cattr_accessor :logger
@@server_settings = {

View file

@ -2,7 +2,7 @@ module ActionMailer
module VERSION #:nodoc:
MAJOR = 1
MINOR = 2
TINY = 1
TINY = 4
STRING = [MAJOR, MINOR, TINY].join('.')
end

View file

@ -54,14 +54,14 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "actionmailer"
s.homepage = "http://www.rubyonrails.org"
s.add_dependency('actionpack', '= 1.12.1' + PKG_BUILD)
s.add_dependency('actionpack', '= 1.12.4' + PKG_BUILD)
s.has_rdoc = true
s.requirements << 'none'
s.require_path = 'lib'
s.autorequire = 'action_mailer'
s.files = [ "rakefile", "install.rb", "README", "CHANGELOG", "MIT-LICENSE" ]
s.files = [ "Rakefile", "install.rb", "README", "CHANGELOG", "MIT-LICENSE" ]
s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
end
@ -84,116 +84,12 @@ task :pdoc => [:rdoc] do
end
desc "Publish the release files to RubyForge."
task :release => [:package] do
files = ["gem", "tgz", "zip"].map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }
task :release => [ :package ] do
`rubyforge login`
if RUBY_FORGE_PROJECT then
require 'net/http'
require 'open-uri'
project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/"
project_data = open(project_uri) { |data| data.read }
group_id = project_data[/[?&]group_id=(\d+)/, 1]
raise "Couldn't get group id" unless group_id
# This echos password to shell which is a bit sucky
if ENV["RUBY_FORGE_PASSWORD"]
password = ENV["RUBY_FORGE_PASSWORD"]
else
print "#{RUBY_FORGE_USER}@rubyforge.org's password: "
password = STDIN.gets.chomp
end
login_response = Net::HTTP.start("rubyforge.org", 80) do |http|
data = [
"login=1",
"form_loginname=#{RUBY_FORGE_USER}",
"form_pw=#{password}"
].join("&")
http.post("/account/login.php", data)
end
cookie = login_response["set-cookie"]
raise "Login failed" unless cookie
headers = { "Cookie" => cookie }
release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"
release_data = open(release_uri, headers) { |data| data.read }
package_id = release_data[/[?&]package_id=(\d+)/, 1]
raise "Couldn't get package id" unless package_id
first_file = true
release_id = ""
files.each do |filename|
basename = File.basename(filename)
file_ext = File.extname(filename)
file_data = File.open(filename, "rb") { |file| file.read }
puts "Releasing #{basename}..."
release_response = Net::HTTP.start("rubyforge.org", 80) do |http|
release_date = Time.now.strftime("%Y-%m-%d %H:%M")
type_map = {
".zip" => "3000",
".tgz" => "3110",
".gz" => "3110",
".gem" => "1400"
}; type_map.default = "9999"
type = type_map[file_ext]
boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"
query_hash = if first_file then
{
"group_id" => group_id,
"package_id" => package_id,
"release_name" => RELEASE_NAME,
"release_date" => release_date,
"type_id" => type,
"processor_id" => "8000", # Any
"release_notes" => "",
"release_changes" => "",
"preformatted" => "1",
"submit" => "1"
}
else
{
"group_id" => group_id,
"release_id" => release_id,
"package_id" => package_id,
"step2" => "1",
"type_id" => type,
"processor_id" => "8000", # Any
"submit" => "Add This File"
}
end
query = "?" + query_hash.map do |(name, value)|
[name, URI.encode(value)].join("=")
end.join("&")
data = [
"--" + boundary,
"Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
"Content-Type: application/octet-stream",
"Content-Transfer-Encoding: binary",
"", file_data, ""
].join("\x0D\x0A")
release_headers = headers.merge(
"Content-Type" => "multipart/form-data; boundary=#{boundary}"
)
target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
http.post(target + query, data, release_headers)
end
if first_file then
release_id = release_response.body[/release_id=(\d+)/, 1]
raise("Couldn't get release id") unless release_id
end
first_file = false
end
for ext in %w( gem tgz zip )
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
puts release_command
system(release_command)
end
end
end

View file

@ -24,6 +24,8 @@ class Net::SMTP
end
class FunkyPathMailer < ActionMailer::Base
self.template_root = "#{File.dirname(__FILE__)}/fixtures/path.with.dots"
def multipart_with_template_path_with_dots(recipient)
recipients recipient
subject "Have a lovely picture"
@ -816,3 +818,15 @@ EOF
end
end
class InheritableTemplateRootTest < Test::Unit::TestCase
def test_attr
expected = "#{File.dirname(__FILE__)}/fixtures/path.with.dots"
assert_equal expected, FunkyPathMailer.template_root
sub = Class.new(FunkyPathMailer)
sub.template_root = 'test/path'
assert_equal 'test/path', sub.template_root
assert_equal expected, FunkyPathMailer.template_root
end
end

View file

@ -1,4 +1,55 @@
*1.12.1* (April 6th, 2005)
*1.12.4* (August 8th, 2006)
* Documentation fix: integration test scripts don't require integration_test. #4914 [Frederick Ros <sl33p3r@free.fr>]
* ActionController::Base Summary documentation rewrite. #4900 [kevin.clark@gmail.com]
* Fix text_helper.rb documentation rendering. #4725 [Frederick Ros]
* Fixes bad rendering of JavaScriptMacrosHelper rdoc. #4910 [Frederick Ros]
* Enhance documentation for setting headers in integration tests. Skip auto HTTP prepending when its already there. #4079 [Rick Olson]
* Documentation for AbstractRequest. #4895 [kevin.clark@gmail.com]
* Remove all remaining references to @params in the documentation. [Marcel Molina Jr.]
* Add documentation for redirect_to :back's RedirectBackError exception. [Marcel Molina Jr.]
* Update layout and content_for documentation to use yield rather than magic @content_for instance variables. [Marcel Molina Jr.]
* Cache CgiRequest#request_parameters so that multiple calls don't re-parse multipart data. [Rick]
* Fixed that remote_form_for can leave out the object parameter and default to the instance variable of the object_name, just like form_for [DHH]
* Added ActionController.filter_parameter_logging that makes it easy to remove passwords, credit card numbers, and other sensitive information from being logged when a request is handled. #1897 [jeremye@bsa.ca.gov]
* Fixed that real files and symlinks should be treated the same when compiling templates. #5438 [zachary@panandscan.com]
* Add :status option to send_data and send_file. Defaults to '200 OK'. #5243 [Manfred Stienstra <m.stienstra@fngtps.com>]
* Update documentation for erb trim syntax. #5651 [matt@mattmargolis.net]
* Short documentation to mention use of Mime::Type.register. #5710 [choonkeat@gmail.com]
*1.12.3* (June 28th, 2006)
* Fix broken traverse_to_controller. We now:
Look for a _controller.rb file under RAILS_ROOT to load.
If we find it, we require_dependency it and return the controller it defined. (If none was defined we stop looking.)
If we don't find it, we look for a .rb file under RAILS_ROOT to load. If we find it, and it loads a constant we keep looking.
Otherwise we check to see if a directory of the same name exists, and if it does we create a module for it.
*1.12.2* (June 27th, 2006)
* Refinement to avoid exceptions in traverse_to_controller.
* (Hackish) Fix loading of arbitrary files in Ruby's load path by traverse_to_controller. [Nicholas Seckar]
*1.12.1* (April 6th, 2006)
* Fixed that template extensions would be cached development mode #4624 [Stefan Kaes]
@ -30,7 +81,7 @@
This can be used by deployment managers to set the asset id by application revision
*1.12.0* (March 27th, 2005)
*1.12.0* (March 27th, 2006)
* Add documentation for respond_to. [Jamis Buck]

View file

@ -469,3 +469,7 @@ And as Jim from Rake says:
For other information, feel free to ask on the ruby-talk mailing list (which
is mirrored to comp.lang.ruby) or contact mailto:david@loudthinking.com.
...

53
tracks/vendor/rails/actionpack/filler vendored Normal file
View file

@ -0,0 +1,53 @@
this is just a filler file to try and work around the zlib error when unpacking the gem. Please ignore it, thanks.
abcDEfgHijkLMNopqrStUVWxyz
AbcdefgHIjklMnOpqrsTUvwxYZ
AbCDEfghIjKLmnoPQrstuVwxyz
abcDefGhijKlmnopQrstuvWXYz
AbCdefGhiJKlmnoPqrstuVwxYz
aBcdefGHijKlmnOpQrStUvwxYz
AbcdEfGhIJklmnOPQrSTuvwxyZ
AbcDeFGHijkLmnopqrstuVwxYZ
ABcdefgHIjkLmnOpqrStuVwxyZ
aBcdEFGhiJklmnopQrstuVwxyz
abcDefgHijKlmnoPQrSTuvwxYz
AbcdefGhiJklmnOpqrstuVwxYZ
abcdefgHIjKlMNoPqRsTuvwxYz
ABcDeFghIjklMnopQrstUVwxyZ
AbcdefGhijkLmNopQRstuVWxYZ
aBcdefGhijklMNOpqRsTUvwxyz
abcdEFGhiJKlmnOPQrStUVwxyz
abcDefghIJklmnOPqRStuVWxyz
abcdefGhIjklmnoPQrStUVwXyZ
abcDefghIjkLmnopQrstuVwxyz
AbcdefGhIjklMNOPqrstuvWXyz
AbCdEfGHijkLmnopqrstuvwxyz
abCdEFghijKlmnopqRstuvwXYz
abCdEfghIJklmnOPqrsTUvwxyz
AbcdeFghijklmnoPqrStUvWxyZ
aBcDEFghIJKlmnopqrstuvWXyz
abcdEfghiJKlmNopqrstuvwXyz
AbcdEFGHIJKlmnopqRsTuvwxYz
abcdeFgHiJklmnoPQRsTuvwXYz
abcdEfGhijkLmnOPqrstUvwXYZ
abCDeFGhijklmNopQrstUvwxYz
abCdeFGhIjklmnOpQrstUvwxyZ
aBcDEFgHijKlmNOPQrsTUvwxYz
aBcDefghijklmNoPqrstUvWXyz
AbcDefgHiJklmnOPqRStuvwxYz
aBcdefGHijklMnopqRstUvwxyz
AbCdefghijKLmnopqRstuvWXyz
aBCdefGhiJkLMnopQrsTUvwxyz
ABcdefGHijKlmnOPqrSTUvWXyz
aBCdEfGHIJklMnopqRsTUvWxyz
ABcDEFGHIJklMnopqrSTuVwxyz
abcdEfghijklMnopqrstuvwxyz
AbCDEFghIjkLmNOpQRstUVwxyZ
abCdEFghIJklMNOPqrstUvwXYZ
abCdefghijklmnoPQrstuVwxyz
AbcdEfghijkLMnopqRSTUvWxYz
ABcDEfGhIjKLmNopqrStuVwxyZ
abCdefgHijklmnOpQRStuvwxYz
abCdeFghijKLmNopQrstuvwxyZ
abcdEFGHijKlmnopqrstuvwxYZ

View file

@ -49,13 +49,15 @@ module ActionController #:nodoc:
end
end
# Action Controllers are made up of one or more actions that performs its purpose and then either renders a template or
# redirects to another action. An action is defined as a public method on the controller, which will automatically be
# made accessible to the web-server through a mod_rewrite mapping. A sample controller could look like this:
# Action Controllers are the core of a web request in Rails. They are made up of one or more actions that are executed
# on request and then either render a template or redirect to another action. An action is defined as a public method
# on the controller, which will automatically be made accessible to the web-server through Rails Routes.
#
# A sample controller could look like this:
#
# class GuestBookController < ActionController::Base
# def index
# @entries = Entry.find_all
# @entries = Entry.find(:all)
# end
#
# def sign
@ -64,26 +66,17 @@ module ActionController #:nodoc:
# end
# end
#
# GuestBookController.template_root = "templates/"
# GuestBookController.process_cgi
# Actions, by default, render a template in the <tt>app/views</tt> directory corresponding to the name of the controller and action
# after executing code in the action. For example, the +index+ action of the +GuestBookController+ would render the
# template <tt>app/views/guestbook/index.rhtml</tt> by default after populating the <tt>@entries</tt> instance variable.
#
# All actions assume that you want to render a template matching the name of the action at the end of the performance
# unless you tell it otherwise. The index action complies with this assumption, so after populating the @entries instance
# variable, the GuestBookController will render "templates/guestbook/index.rhtml".
#
# Unlike index, the sign action isn't interested in rendering a template. So after performing its main purpose (creating a
# new entry in the guest book), it sheds the rendering assumption and initiates a redirect instead. This redirect works by
# returning an external "302 Moved" HTTP response that takes the user to the index action.
# Unlike index, the sign action will not render a template. After performing its main purpose (creating a
# new entry in the guest book), it initiates a redirect instead. This redirect works by returning an external
# "302 Moved" HTTP response that takes the user to the index action.
#
# The index and sign represent the two basic action archetypes used in Action Controllers. Get-and-show and do-and-redirect.
# Most actions are variations of these themes.
#
# Also note that it's the final call to <tt>process_cgi</tt> that actually initiates the action performance. It will extract
# request and response objects from the CGI
#
# When Action Pack is used inside of Rails, the template_root is automatically configured and you don't need to call process_cgi
# yourself.
#
# == Requests
#
# Requests are processed by the Action Controller framework by extracting the value of the "action" key in the request parameters.
@ -94,16 +87,16 @@ module ActionController #:nodoc:
# The full request object is available with the request accessor and is primarily used to query for http headers. These queries
# are made by accessing the environment hash, like this:
#
# def hello_ip
# location = request.env["REMOTE_IP"]
# render :text => "Hello stranger from #{location}"
# def server_ip
# location = request.env["SERVER_ADDR"]
# render :text => "This server hosted at #{location}"
# end
#
# == Parameters
#
# All request parameters, whether they come from a GET or POST request, or from the URL, are available through the params hash.
# So an action that was performed through /weblog/list?category=All&limit=5 will include { "category" => "All", "limit" => 5 }
# in params.
# All request parameters, whether they come from a GET or POST request, or from the URL, are available through the params method
# which returns a hash. For example, an action that was performed through <tt>/weblog/list?category=All&limit=5</tt> will include
# <tt>{ "category" => "All", "limit" => 5 }</tt> in params.
#
# It's also possible to construct multi-dimensional parameter hashes by specifying keys using brackets, such as:
#
@ -116,12 +109,12 @@ module ActionController #:nodoc:
#
# == Sessions
#
# Sessions allows you to store objects in memory between requests. This is useful for objects that are not yet ready to be persisted,
# Sessions allows you to store objects in between requests. This is useful for objects that are not yet ready to be persisted,
# such as a Signup object constructed in a multi-paged process, or objects that don't change much and are needed all the time, such
# as a User object for a system that requires login. The session should not be used, however, as a cache for objects where it's likely
# they could be changed unknowingly. It's usually too much work to keep it all synchronized -- something databases already excel at.
#
# You can place objects in the session by using the <tt>session</tt> hash accessor:
# You can place objects in the session by using the <tt>session</tt> method, which accesses a hash:
#
# session[:person] = Person.authenticate(user_name, password)
#
@ -129,17 +122,24 @@ module ActionController #:nodoc:
#
# Hello #{session[:person]}
#
# Any object can be placed in the session (as long as it can be Marshalled). But remember that 1000 active sessions each storing a
# 50kb object could lead to a 50MB memory overhead. In other words, think carefully about size and caching before resorting to the use
# of the session.
#
# For removing objects from the session, you can either assign a single key to nil, like <tt>session[:person] = nil</tt>, or you can
# remove the entire session with reset_session.
#
# By default, sessions are stored on the file system in <tt>RAILS_ROOT/tmp/sessions</tt>. Any object can be placed in the session
# (as long as it can be Marshalled). But remember that 1000 active sessions each storing a 50kb object could lead to a 50MB store on the filesystem.
# In other words, think carefully about size and caching before resorting to the use of the session on the filesystem.
#
# An alternative to storing sessions on disk is to use ActiveRecordStore to store sessions in your database, which can solve problems
# caused by storing sessions in the file system and may speed up your application. To use ActiveRecordStore, uncomment the line:
#
# config.action_controller.session_store = :active_record_store
#
# in your <tt>environment.rb</tt> and run <tt>rake db:sessions:create</tt>.
#
# == Responses
#
# Each action results in a response, which holds the headers and document to be sent to the user's browser. The actual response
# object is generated automatically through the use of renders and redirects, so it's normally nothing you'll need to be concerned about.
# object is generated automatically through the use of renders and redirects and requires no user intervention.
#
# == Renders
#
@ -161,9 +161,9 @@ module ActionController #:nodoc:
# def search
# @results = Search.find(params[:query])
# case @results
# when 0 then render :action=> "no_results"
# when 1 then render :action=> "show"
# when 2..10 then render :action=> "show_many"
# when 0 then render :action => "no_results"
# when 1 then render :action => "show"
# when 2..10 then render :action => "show_many"
# end
# end
#
@ -171,32 +171,21 @@ module ActionController #:nodoc:
#
# == Redirects
#
# Redirecting is what actions that update the model do when they're done. The <tt>save_post</tt> method shouldn't be responsible for also
# showing the post once it's saved -- that's the job for <tt>show_post</tt>. So once <tt>save_post</tt> has completed its business, it'll
# redirect to <tt>show_post</tt>. All redirects are external, which means that when the user refreshes his browser, it's not going to save
# the post again, but rather just show it one more time.
#
# This sounds fairly simple, but the redirection is complicated by the quest for a phenomenon known as "pretty urls". Instead of accepting
# the dreadful being that is "weblog_controller?action=show&post_id=5", Action Controller goes out of its way to represent the former as
# "/weblog/show/5". And this is even the simple case. As an example of a more advanced pretty url consider
# "/library/books/ISBN/0743536703/show", which can be mapped to books_controller?action=show&type=ISBN&id=0743536703.
#
# Redirects work by rewriting the URL of the current action. So if the show action was called by "/library/books/ISBN/0743536703/show",
# we can redirect to an edit action simply by doing <tt>redirect_to(:action => "edit")</tt>, which could throw the user to
# "/library/books/ISBN/0743536703/edit". Naturally, you'll need to setup the routes configuration file to point to the proper controller
# and action in the first place, but once you have, it can be rewritten with ease.
#
# Let's consider a bunch of examples on how to go from "/clients/37signals/basecamp/project/dash" to somewhere else:
# Redirects are used to move from one action to another. For example, after a <tt>create</tt> action, which stores a blog entry to a database,
# we might like to show the user the new entry. Because we're following good DRY principles (Don't Repeat Yourself), we're going to reuse (and redirect to)
# a <tt>show</tt> action that we'll assume has already been created. The code might look like this:
#
# redirect_to(:action => "edit") =>
# /clients/37signals/basecamp/project/dash
#
# redirect_to(:client_name => "nextangle", :project_name => "rails") =>
# /clients/nextangle/rails/project/dash
# def create
# @entry = Entry.new(params[:entry])
# if @entry.save
# # The entry was saved correctly, redirect to show
# redirect_to :action => 'show', :id => @entry.id
# else
# # things didn't go so well, do something else
# end
# end
#
# Those redirects happen under the configuration of:
#
# map.connect 'clients/:client_name/:project_name/:controller/:action'
# In this case, after saving our new entry to the database, the user is redirected to the <tt>show</tt> method which is then executed.
#
# == Calling multiple redirects or renders
#
@ -214,15 +203,6 @@ module ActionController #:nodoc:
# render :action => "overthere" # won't be called unless monkeys is nil
# end
#
# == Environments
#
# Action Controller works out of the box with CGI, FastCGI, and mod_ruby. CGI and mod_ruby controllers are triggered just the same using:
#
# WeblogController.process_cgi
#
# FastCGI controllers are triggered using:
#
# FCGI.each_cgi{ |cgi| WeblogController.process_cgi(cgi) }
class Base
DEFAULT_RENDER_STATUS_CODE = "200 OK"
@ -263,10 +243,10 @@ module ActionController #:nodoc:
# Modern REST web services often need to submit complex data to the web application.
# The param_parsers hash lets you register handlers wich will process the http body and add parameters to the
# @params hash. These handlers are invoked for post and put requests.
# <tt>params</tt> hash. These handlers are invoked for post and put requests.
#
# By default application/xml is enabled. A XmlSimple class with the same param name as the root will be instanciated
# in the @params. This allows XML requests to mask themselves as regular form submissions, so you can have one
# in the <tt>params</tt>. This allows XML requests to mask themselves as regular form submissions, so you can have one
# action serve both regular forms and web service requests.
#
# Example of doing your own parser for a custom content type:
@ -366,6 +346,53 @@ module ActionController #:nodoc:
def hide_action(*names)
write_inheritable_attribute(:hidden_actions, hidden_actions | names.collect { |n| n.to_s })
end
# Replace sensitive paramater data from the request log.
# Filters paramaters that have any of the arguments as a substring.
# Looks in all subhashes of the param hash for keys to filter.
# If a block is given, each key and value of the paramater hash and all
# subhashes is passed to it, the value or key
# can be replaced using String#replace or similar method.
#
# Examples:
# filter_parameter_logging
# => Does nothing, just slows the logging process down
#
# filter_parameter_logging :password
# => replaces the value to all keys matching /password/i with "[FILTERED]"
#
# filter_parameter_logging :foo, "bar"
# => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
#
# filter_parameter_logging { |k,v| v.reverse! if k =~ /secret/i }
# => reverses the value to all keys matching /secret/i
#
# filter_parameter_logging(:foo, "bar") { |k,v| v.reverse! if k =~ /secret/i }
# => reverses the value to all keys matching /secret/i, and
# replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
def filter_parameter_logging(*filter_words, &block)
parameter_filter = Regexp.new(filter_words.collect{ |s| s.to_s }.join('|'), true) if filter_words.length > 0
define_method(:filter_parameters) do |unfiltered_parameters|
filtered_parameters = {}
unfiltered_parameters.each do |key, value|
if key =~ parameter_filter
filtered_parameters[key] = '[FILTERED]'
elsif value.is_a?(Hash)
filtered_parameters[key] = filter_parameters(value)
elsif block_given?
key, value = key.dup, value.dup
yield key, value
filtered_parameters[key] = value
else
filtered_parameters[key] = value
end
end
filtered_parameters
end
end
end
public
@ -803,6 +830,10 @@ module ActionController #:nodoc:
# redirect_to :back
#
# The redirection happens as a "302 Moved" header.
#
# When using <tt>redirect_to :back</tt>, if there is no referrer,
# RedirectBackError will be raised. You may specify some fallback
# behavior for this case by rescueing RedirectBackError.
def redirect_to(options = {}, *parameters_for_method_reference) #:doc:
case options
when %r{^\w+://.*}
@ -901,7 +932,7 @@ module ActionController #:nodoc:
if logger
logger.info "\n\nProcessing #{controller_class_name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
logger.info " Session ID: #{@session.session_id}" if @session and @session.respond_to?(:session_id)
logger.info " Parameters: #{@params.inspect}"
logger.info " Parameters: #{respond_to?(:filter_parameters) ? filter_parameters(@params).inspect : @params.inspect}"
end
end

View file

@ -38,9 +38,9 @@ module ActionController #:nodoc:
#
# class WeblogController < ActionController::Base
# def update
# List.update(@params["list"]["id"], @params["list"])
# expire_page :action => "show", :id => @params["list"]["id"]
# redirect_to :action => "show", :id => @params["list"]["id"]
# List.update(params[:list][:id], params[:list])
# expire_page :action => "show", :id => params[:list][:id]
# redirect_to :action => "show", :id => params[:list][:id]
# end
# end
#

View file

@ -64,11 +64,12 @@ module ActionController #:nodoc:
end
def request_parameters
if ActionController::Base.param_parsers.has_key?(content_type)
CGIMethods.parse_formatted_request_parameters(content_type, @env['RAW_POST_DATA'])
else
CGIMethods.parse_request_parameters(@cgi.params)
end
@request_parameters ||=
if ActionController::Base.param_parsers.has_key?(content_type)
CGIMethods.parse_formatted_request_parameters(content_type, @env['RAW_POST_DATA'])
else
CGIMethods.parse_request_parameters(@cgi.params)
end
end
def cookies

View file

@ -140,14 +140,18 @@ module ActionController
# Performs a GET request with the given parameters. The parameters may
# be +nil+, a Hash, or a string that is appropriately encoded
# (application/x-www-form-urlencoded or multipart/form-data).
# (application/x-www-form-urlencoded or multipart/form-data). The headers
# should be a hash. The keys will automatically be upcased, with the
# prefix 'HTTP_' added if needed.
def get(path, parameters=nil, headers=nil)
process :get, path, parameters, headers
end
# Performs a POST request with the given parameters. The parameters may
# be +nil+, a Hash, or a string that is appropriately encoded
# (application/x-www-form-urlencoded or multipart/form-data).
# (application/x-www-form-urlencoded or multipart/form-data). The headers
# should be a hash. The keys will automatically be upcased, with the
# prefix 'HTTP_' added if needed.
def post(path, parameters=nil, headers=nil)
process :post, path, parameters, headers
end
@ -155,7 +159,9 @@ module ActionController
# Performs an XMLHttpRequest request with the given parameters, mimicing
# the request environment created by the Prototype library. The parameters
# may be +nil+, a Hash, or a string that is appropriately encoded
# (application/x-www-form-urlencoded or multipart/form-data).
# (application/x-www-form-urlencoded or multipart/form-data). The headers
# should be a hash. The keys will automatically be upcased, with the
# prefix 'HTTP_' added if needed.
def xml_http_request(path, parameters=nil, headers=nil)
headers = (headers || {}).merge("X-Requested-With" => "XMLHttpRequest")
post(path, parameters, headers)
@ -218,7 +224,7 @@ module ActionController
(headers || {}).each do |key, value|
key = key.to_s.upcase.gsub(/-/, "_")
key = "HTTP_#{key}" unless env.has_key?(key)
key = "HTTP_#{key}" unless env.has_key?(key) || env =~ /^X|HTTP/
env[key] = value
end
@ -341,7 +347,6 @@ module ActionController
# using the get/post methods:
#
# require "#{File.dirname(__FILE__)}/test_helper"
# require "integration_test"
#
# class ExampleTest < ActionController::IntegrationTest
# fixtures :people
@ -366,7 +371,6 @@ module ActionController
# reference any named routes you happen to have defined!
#
# require "#{File.dirname(__FILE__)}/test_helper"
# require "integration_test"
#
# class AdvancedTest < ActionController::IntegrationTest
# fixtures :people, :rooms

View file

@ -27,7 +27,7 @@ module ActionController #:nodoc:
# that the header and footer are only mentioned in one place, like this:
#
# <!-- The header part of this layout -->
# <%= @content_for_layout %>
# <%= yield %>
# <!-- The footer part of this layout -->
#
# And then you have content pages that look like this:
@ -47,7 +47,7 @@ module ActionController #:nodoc:
# references that won't materialize before rendering time:
#
# <h1><%= @page_title %></h1>
# <%= @content_for_layout %>
# <%= yield %>
#
# ...and content pages that fulfill these references _at_ rendering time:
#
@ -159,10 +159,12 @@ module ActionController #:nodoc:
#
# As you can see, you pass the template as the first parameter, the status code as the second ("200" is OK), and the layout
# as the third.
#
# NOTE: The old notation for rendering the view from a layout was to expose the magic <tt>@content_for_layout</tt> instance
# variable. The preferred notation now is to use <tt>yield</tt>, as documented above.
module ClassMethods
# If a layout is specified, all actions rendered through render and render_action will have their result assigned
# to <tt>@content_for_layout</tt>, which can then be used by the layout to insert their contents with
# <tt><%= @content_for_layout %></tt>. This layout can itself depend on instance variables assigned during action
# If a layout is specified, all rendered actions will have their result rendered
# when the layout<tt>yield</tt>'s. This layout can itself depend on instance variables assigned during action
# performance and have access to them as any normal template would.
def layout(template_name, conditions = {})
add_layout_conditions(conditions)

View file

@ -92,6 +92,12 @@ module ActionController #:nodoc:
# Note that you can define your own XML parameter parser which would allow you to describe multiple entities
# in a single request (i.e., by wrapping them all in a single root note), but if you just go with the flow
# and accept Rails' defaults, life will be much easier.
#
# If you need to use a MIME type which isn't supported by default, you can register your own handlers in
# environment.rb as follows.
#
# Mime::Type.register "image/jpg", :jpg
#
def respond_to(*types, &block)
raise ArgumentError, "respond_to takes either types or a block, never bot" unless types.any? ^ block
block ||= lambda { |responder| types.each { |type| responder.send(type) } }
@ -160,4 +166,4 @@ module ActionController #:nodoc:
end
end
end
end
end

View file

@ -31,7 +31,7 @@ module ActionController
# instance variable, which is an ordered collection of model objects for the
# current page (at most 20, sorted by last name and first name), and a
# <tt>@person_pages</tt> Paginator instance. The current page is determined
# by the <tt>@params['page']</tt> variable.
# by the <tt>params[:page]</tt> variable.
#
# ==== Pagination for a single action
#
@ -47,7 +47,7 @@ module ActionController
# ==== Custom/"classic" pagination
#
# def list
# @person_pages = Paginator.new self, Person.count, 10, @params['page']
# @person_pages = Paginator.new self, Person.count, 10, params[:page]
# @people = Person.find :all, :order => 'last_name, first_name',
# :limit => @person_pages.items_per_page,
# :offset => @person_pages.current.offset

View file

@ -1,5 +1,6 @@
module ActionController
# These methods are available in both the production and test Request objects.
# Subclassing AbstractRequest makes these methods available to the request objects used in production and testing,
# CgiRequest and TestRequest
class AbstractRequest
cattr_accessor :relative_url_root
@ -65,6 +66,7 @@ module ActionController
end
end
# Returns the accepted MIME type for the request
def accepts
@accepts ||=
if @env['HTTP_ACCEPT'].to_s.strip.empty?
@ -202,15 +204,21 @@ module ActionController
host + port_string
end
def path_parameters=(parameters)
def path_parameters=(parameters) #:nodoc:
@path_parameters = parameters
@symbolized_path_parameters = @parameters = nil
end
def symbolized_path_parameters
# The same as <tt>path_parameters</tt> with explicitly symbolized keys
def symbolized_path_parameters
@symbolized_path_parameters ||= path_parameters.symbolize_keys
end
# Returns a hash with the parameters used to form the path of the request
#
# Example:
#
# {:action => 'my_action', :controller => 'my_controller'}
def path_parameters
@path_parameters ||= {}
end

View file

@ -218,43 +218,81 @@ module ActionController
expr = "::#{controller.split('/').collect {|c| c.camelize}.join('::')}Controller"
g.result :controller, expr, true
end
def file_kinds(kind)
((@file_kinds ||= []) << kind).uniq! || @file_kinds
end
def traverse_to_controller(segments, start_at = 0)
mod = ::Object
length = segments.length
index = start_at
mod_name = controller_name = segment = nil
while index < length
return nil unless /^[A-Za-z][A-Za-z\d_]*$/ =~ (segment = segments[index])
return nil unless /\A[A-Za-z][A-Za-z\d_]*\Z/ =~ (segment = segments[index])
index += 1
file_kinds :app
mod_name = segment.camelize
controller_name = "#{mod_name}Controller"
path_suffix = File.join(segments[start_at..(index - 1)])
next_mod = nil
begin
# We use eval instead of const_get to avoid obtaining values from parent modules.
controller = eval("mod::#{controller_name}", nil, __FILE__, __LINE__)
expected_name = "#{mod.name}::#{controller_name}"
# Detect the case when const_get returns an object from a parent namespace.
if controller.is_a?(Class) && controller.ancestors.include?(ActionController::Base) && (mod == Object || controller.name == expected_name)
return controller, (index - start_at)
# If the controller is already present, or if we load it, return it.
if mod.const_defined?(controller_name) || attempt_load(mod, controller_name, path_suffix + "_controller") == :defined
controller = mod.const_get(controller_name)
return nil unless controller.is_a?(Class) && controller.ancestors.include?(ActionController::Base) # it's not really a controller?
return [controller, (index - start_at)]
end
# No controller? Look for the module
if mod.const_defined? mod_name
next_mod = mod.send(:const_get, mod_name)
next_mod = nil unless next_mod.is_a?(Module)
else
# Try to load a file that defines the module we want.
case attempt_load(mod, mod_name, path_suffix)
when :defined then next_mod = mod.const_get mod_name
when :dir then # We didn't find a file, but there's a dir.
next_mod = Module.new # So create a module for the directory
mod.send :const_set, mod_name, next_mod
else
return nil
end
rescue NameError => e
raise unless /^uninitialized constant .*#{controller_name}$/ =~ e.message
end
mod = next_mod
begin
next_mod = eval("mod::#{mod_name}", nil, __FILE__, __LINE__)
# Check that we didn't get a module from a parent namespace
mod = (mod == Object || next_mod.name == "#{mod.name}::#{mod_name}") ? next_mod : nil
rescue NameError => e
raise unless /^uninitialized constant .*#{mod_name}$/ =~ e.message
end
return nil unless mod
return nil unless mod && mod.is_a?(Module)
end
nil
end
protected
def safe_load_paths #:nodoc:
if defined?(RAILS_ROOT)
$LOAD_PATH.select do |base|
base = File.expand_path(base)
extended_root = File.expand_path(RAILS_ROOT)
base.match(/\A#{Regexp.escape(extended_root)}\/*#{file_kinds(:lib) * '|'}/) || base =~ %r{rails-[\d.]+/builtin}
end
else
$LOAD_PATH
end
end
def attempt_load(mod, const_name, path)
has_dir = false
safe_load_paths.each do |load_path|
full_path = File.join(load_path, path)
file_path = full_path + '.rb'
if File.file?(file_path) # Found a .rb file? Load it up
require_dependency(file_path)
return :defined if mod.const_defined? const_name
else
has_dir ||= File.directory?(full_path)
end
end
return (has_dir ? :dir : nil)
end
end
end

View file

@ -14,7 +14,7 @@ module ActionController #:nodoc:
# it feasible to send even large files.
#
# Be careful to sanitize the path parameter if it coming from a web
# page. send_file(@params['path']) allows a malicious user to
# page. send_file(params[:path]) allows a malicious user to
# download any file on your server.
#
# Options:
@ -28,6 +28,7 @@ module ActionController #:nodoc:
# or to read the entire file before sending (false). Defaults to true.
# * <tt>:buffer_size</tt> - specifies size (in bytes) of the buffer used to stream the file.
# Defaults to 4096.
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to '200 OK'.
#
# The default Content-Type and Content-Disposition headers are
# set to download arbitrary binary files in as many browsers as
@ -37,9 +38,12 @@ module ActionController #:nodoc:
# Simple download:
# send_file '/path/to.zip'
#
# Show a JPEG in browser:
# Show a JPEG in the browser:
# send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline'
#
# Show a 404 page in the browser:
# send_file '/path/to/404.html, :type => 'text/html; charset=utf-8', :status => 404
#
# Read about the other Content-* HTTP headers if you'd like to
# provide the user with more information (such as Content-Description).
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11
@ -61,7 +65,7 @@ module ActionController #:nodoc:
@performed_render = false
if options[:stream]
render :text => Proc.new { |response, output|
render :status => options[:status], :text => Proc.new { |response, output|
logger.info "Streaming file #{path}" unless logger.nil?
len = options[:buffer_size] || 4096
File.open(path, 'rb') do |file|
@ -81,7 +85,7 @@ module ActionController #:nodoc:
}
else
logger.info "Sending file #{path}" unless logger.nil?
File.open(path, 'rb') { |file| render :text => file.read }
File.open(path, 'rb') { |file| render :status => options[:status], :text => file.read }
end
end
@ -93,6 +97,7 @@ module ActionController #:nodoc:
# * <tt>:type</tt> - specifies an HTTP content type.
# Defaults to 'application/octet-stream'.
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to '200 OK'.
# Valid values are 'inline' and 'attachment' (default).
#
# Generic data download:
@ -109,7 +114,7 @@ module ActionController #:nodoc:
logger.info "Sending data #{options[:filename]}" unless logger.nil?
send_file_headers! options.merge(:length => data.size)
@performed_render = false
render :text => data
render :status => options[:status], :text => data
end
private
@ -139,4 +144,4 @@ module ActionController #:nodoc:
@headers['Cache-Control'] = 'private' if @headers['Cache-Control'] == 'no-cache'
end
end
end
end

View file

@ -63,7 +63,7 @@
<p style="color: green"><%= flash[:notice] %></p>
<%= @content_for_layout %>
<%= yield %>
</body>
</html>

View file

@ -37,7 +37,7 @@ module ActionController #:nodoc:
# is a hash consisting of the following key/value pairs:
#
# * <tt>:params</tt>: a single key or an array of keys that must
# be in the @params hash in order for the action(s) to be safely
# be in the <tt>params</tt> hash in order for the action(s) to be safely
# called.
# * <tt>:session</tt>: a single key or an array of keys that must
# be in the @session in order for the action(s) to be safely called.

View file

@ -2,7 +2,7 @@ module ActionPack #:nodoc:
module VERSION #:nodoc:
MAJOR = 1
MINOR = 12
TINY = 1
TINY = 4
STRING = [MAJOR, MINOR, TINY].join('.')
end

View file

@ -11,7 +11,7 @@ module ActionView #:nodoc:
#
# = ERb
#
# You trigger ERb by using embeddings such as <% %> and <%= %>. The difference is whether you want output or not. 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>
@ -19,12 +19,14 @@ module ActionView #:nodoc:
# Name: <%= person.name %><br/>
# <% end %>
#
# The loop is setup in regular embedding tags (<% %>) and the name is written using the output embedding tag (<%= %>). Note that this
# 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:
#
# Hi, Mr. <% puts "Frodo" %>
#
# (If you absolutely must write from within a function, you can use the TextHelper#concat)
# If you absolutely must write from within a function, you can use the TextHelper#concat
#
# <%- and -%> suppress leading and trailing whitespace, including the trailing newline, and can be used interchangeably with <% and %>.
#
# == Using sub templates
#
@ -425,7 +427,8 @@ module ActionView #:nodoc:
if @@compile_time[render_symbol] && supports_local_assigns?(render_symbol, local_assigns)
if file_name && !@@cache_template_loading
@@compile_time[render_symbol] < File.mtime(file_name)
@@compile_time[render_symbol] < File.mtime(file_name) || (File.symlink?(file_name) ?
@@compile_time[render_symbol] < File.lstat(file_name).mtime : false)
end
else
true

View file

@ -1,6 +1,6 @@
module ActionView
module Helpers
# Capture lets you extract parts of code into instance variables which
# Capture lets you extract parts of code which
# can be used in other points of the template or even layout file.
#
# == Capturing a block into an instance variable
@ -8,12 +8,11 @@ module ActionView
# <% @script = capture do %>
# [some html...]
# <% end %>
#
#
# == Add javascript to header using content_for
#
# content_for("name") is a wrapper for capture which will store the
# fragment in a instance variable similar to @content_for_layout.
# content_for("name") is a wrapper for capture which will
# make the fragment available by name to a yielding layout or template.
#
# layout.rhtml:
#
@ -21,11 +20,11 @@ module ActionView
# <head>
# <title>layout with js</title>
# <script type="text/javascript">
# <%= @content_for_script %>
# </script>
# <%= yield :script %>
# </script>
# </head>
# <body>
# <%= @content_for_layout %>
# <%= yield %>
# </body>
# </html>
#
@ -69,13 +68,9 @@ module ActionView
end
end
# Content_for will store the given block
# in an instance variable for later use in another template
# or in the layout.
#
# The name of the instance variable is content_for_<name>
# to stay consistent with @content_for_layout which is used
# by ActionView's layouts
# Calling content_for stores the block of markup for later use.
# Subsequently, you can make calls to it by name with <tt>yield</tt>
# in another template or in the layout.
#
# Example:
#
@ -83,10 +78,17 @@ module ActionView
# alert('hello world')
# <% end %>
#
# You can use @content_for_header anywhere in your templates.
# You can use yield :header anywhere in your templates.
#
# <%= yield :header %>
#
# NOTE: Beware that content_for is ignored in caches. So you shouldn't use it
# for elements that are going to be fragment cached.
# for elements that are going to be fragment cached.
#
# The deprecated way of accessing a content_for block was to use a instance variable
# named @@content_for_#{name_of_the_content_block}@. So <tt><%= content_for('footer') %></tt>
# would be avaiable as <tt><%= @content_for_footer %></tt>. The preferred notation now is
# <tt><%= yield :footer %></tt>.
def content_for(name, &block)
eval "@content_for_#{name} = (@content_for_#{name} || '') + capture(&block)"
end

View file

@ -310,7 +310,7 @@ module ActionView
"select", add_options(options_from_collection_for_select(collection, value_method, text_method, value), options, value), html_options
)
end
def to_country_select_tag(priority_countries, options, html_options)
html_options = html_options.stringify_keys
add_default_name_and_id(html_options)

View file

@ -27,6 +27,7 @@ module ActionView
# <tt>:url</tt>:: Specifies the url where the updated value should
# be sent after the user presses "ok".
#
#
# Addtional +options+ are:
# <tt>:rows</tt>:: Number of rows (more than 1 will use a TEXTAREA)
# <tt>:cols</tt>:: Number of characters the text input should span (works for both INPUT and TEXTAREA)
@ -122,10 +123,10 @@ module ActionView
# <tt>:on_show</tt>:: Like on_hide, only now the expression is called
# then the div is shown.
# <tt>:after_update_element</tt>:: A Javascript expression that is called when the
# user has selected one of the proposed values.
# The expression should take two variables: element and value.
# Element is a DOM element for the field, value
# is the value selected by the user.
# user has selected one of the proposed values.
# The expression should take two variables: element and value.
# Element is a DOM element for the field, value
# is the value selected by the user.
# <tt>:select</tt>:: Pick the class of the element from which the value for
# insertion should be extracted. If this is not specified,
# the entire element is used.

View file

@ -143,7 +143,7 @@ module ActionView
# background instead of the regular reloading POST arrangement. Even
# though it's using JavaScript to serialize the form elements, the form
# submission will work just like a regular submission as viewed by the
# receiving side (all elements available in @params). The options for
# receiving side (all elements available in <tt>params</tt>). The options for
# specifying the target with :url and defining callbacks is the same as
# link_to_remote.
#
@ -171,9 +171,10 @@ module ActionView
end
# Works like form_remote_tag, but uses form_for semantics.
def remote_form_for(object_name, object, options = {}, &proc)
def remote_form_for(object_name, *args, &proc)
options = args.last.is_a?(Hash) ? args.pop : {}
concat(form_remote_tag(options), proc.binding)
fields_for(object_name, object, options, &proc)
fields_for(object_name, *(args << options), &proc)
concat('</form>', proc.binding)
end
alias_method :form_remote_for, :remote_form_for

View file

@ -77,7 +77,7 @@ module ActionView
end
begin
require_library_or_gem "redcloth"
require_library_or_gem "redcloth" unless Object.const_defined?(:RedCloth)
# Returns the text with all the Textile codes turned into HTML-tags.
# <i>This method is only available if RedCloth can be required</i>.
@ -104,7 +104,7 @@ module ActionView
end
begin
require_library_or_gem "bluecloth"
require_library_or_gem "bluecloth" unless Object.const_defined?(:BlueCloth)
# Returns the text with all the Markdown codes turned into HTML-tags.
# <i>This method is only available if BlueCloth can be required</i>.
@ -116,7 +116,7 @@ module ActionView
end
# Returns +text+ transformed into HTML using very simple formatting rules
# Surrounds paragraphs with <tt>&lt;p&gt;</tt> tags, and converts line breaks into <tt>&lt;br /&gt;</tt>
# Surrounds paragraphs with <tt><p></tt> tags, and converts line breaks into <tt><br/></tt>
# Two consecutive newlines(<tt>\n\n</tt>) are considered as a paragraph, one newline (<tt>\n</tt>) is
# considered a linebreak, three or more consecutive newlines are turned into two newlines
def simple_format(text)
@ -129,7 +129,7 @@ module ActionView
end
# Turns all urls and email addresses into clickable links. The +link+ parameter can limit what should be linked.
# Options are :all (default), :email_addresses, and :urls.
# Options are <tt>:all</tt> (default), <tt>:email_addresses</tt>, and <tt>:urls</tt>.
#
# Example:
# auto_link("Go to http://www.rubyonrails.com and say hello to david@loudthinking.com") =>
@ -235,28 +235,28 @@ module ActionView
# array every time it is called. This can be used to alternate classes
# for table rows:
#
# <%- for item in @items do -%>
# <tr class="<%= cycle("even", "odd") %>">
# ... use item ...
# </tr>
# <%- end -%>
# <%- for item in @items do -%>
# <tr class="<%= cycle("even", "odd") %>">
# ... use item ...
# </tr>
# <%- end -%>
#
# You can use named cycles to prevent clashes in nested loops. You'll
# have to reset the inner cycle, manually:
#
# <%- for item in @items do -%>
# <tr class="<%= cycle("even", "odd", :name => "row_class")
# <td>
# <%- for value in item.values do -%>
# <span style="color:'<%= cycle("red", "green", "blue"
# :name => "colors") %>'">
# item
# </span>
# <%- end -%>
# <%- reset_cycle("colors") -%>
# </td>
# </tr>
# <%- end -%>
# <%- for item in @items do -%>
# <tr class="<%= cycle("even", "odd", :name => "row_class")
# <td>
# <%- for value in item.values do -%>
# <span style="color:'<%= cycle("red", "green", "blue"
# :name => "colors") %>'">
# item
# </span>
# <%- end -%>
# <%- reset_cycle("colors") -%>
# </td>
# </tr>
# <%- end -%>
def cycle(first_value, *values)
if (values.last.instance_of? Hash)
params = values.pop

View file

@ -46,8 +46,12 @@ Rake::RDocTask.new { |rdoc|
rdoc.title = "Action Pack -- On rails from request to response"
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
rdoc.rdoc_files.include('lib/**/*.rb')
if ENV['DOC_FILES']
rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
else
rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
rdoc.rdoc_files.include('lib/**/*.rb')
end
}
# Create compressed packages
@ -73,7 +77,7 @@ spec = Gem::Specification.new do |s|
s.require_path = 'lib'
s.autorequire = 'action_controller'
s.files = [ "rakefile", "install.rb", "README", "RUNNING_UNIT_TESTS", "CHANGELOG", "MIT-LICENSE", "examples/.htaccess" ]
s.files = [ "filler", "Rakefile", "install.rb", "README", "RUNNING_UNIT_TESTS", "CHANGELOG", "MIT-LICENSE", "examples/.htaccess" ]
dist_dirs.each do |dir|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
end
@ -136,116 +140,12 @@ task :pdoc => [:rdoc] do
end
desc "Publish the release files to RubyForge."
task :release => [:package] do
files = ["gem", "tgz", "zip"].map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }
task :release => [ :package ] do
`rubyforge login`
if RUBY_FORGE_PROJECT then
require 'net/http'
require 'open-uri'
project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/"
project_data = open(project_uri) { |data| data.read }
group_id = project_data[/[?&]group_id=(\d+)/, 1]
raise "Couldn't get group id" unless group_id
# This echos password to shell which is a bit sucky
if ENV["RUBY_FORGE_PASSWORD"]
password = ENV["RUBY_FORGE_PASSWORD"]
else
print "#{RUBY_FORGE_USER}@rubyforge.org's password: "
password = STDIN.gets.chomp
end
login_response = Net::HTTP.start("rubyforge.org", 80) do |http|
data = [
"login=1",
"form_loginname=#{RUBY_FORGE_USER}",
"form_pw=#{password}"
].join("&")
http.post("/account/login.php", data)
end
cookie = login_response["set-cookie"]
raise "Login failed" unless cookie
headers = { "Cookie" => cookie }
release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"
release_data = open(release_uri, headers) { |data| data.read }
package_id = release_data[/[?&]package_id=(\d+)/, 1]
raise "Couldn't get package id" unless package_id
first_file = true
release_id = ""
files.each do |filename|
basename = File.basename(filename)
file_ext = File.extname(filename)
file_data = File.open(filename, "rb") { |file| file.read }
puts "Releasing #{basename}..."
release_response = Net::HTTP.start("rubyforge.org", 80) do |http|
release_date = Time.now.strftime("%Y-%m-%d %H:%M")
type_map = {
".zip" => "3000",
".tgz" => "3110",
".gz" => "3110",
".gem" => "1400"
}; type_map.default = "9999"
type = type_map[file_ext]
boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"
query_hash = if first_file then
{
"group_id" => group_id,
"package_id" => package_id,
"release_name" => RELEASE_NAME,
"release_date" => release_date,
"type_id" => type,
"processor_id" => "8000", # Any
"release_notes" => "",
"release_changes" => "",
"preformatted" => "1",
"submit" => "1"
}
else
{
"group_id" => group_id,
"release_id" => release_id,
"package_id" => package_id,
"step2" => "1",
"type_id" => type,
"processor_id" => "8000", # Any
"submit" => "Add This File"
}
end
query = "?" + query_hash.map do |(name, value)|
[name, URI.encode(value)].join("=")
end.join("&")
data = [
"--" + boundary,
"Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
"Content-Type: application/octet-stream",
"Content-Transfer-Encoding: binary",
"", file_data, ""
].join("\x0D\x0A")
release_headers = headers.merge(
"Content-Type" => "multipart/form-data; boundary=#{boundary}"
)
target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
http.post(target + query, data, release_headers)
end
if first_file then
release_id = release_response.body[/release_id=(\d+)/, 1]
raise("Couldn't get release id") unless release_id
end
first_file = false
end
for ext in %w( gem tgz zip )
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
puts release_command
system(release_command)
end
end

View file

@ -6,6 +6,7 @@ class NotAController
end
module Admin
class << self; alias_method :const_available?, :const_defined?; end
SomeConstant = 10
class UserController < Class.new(ActionController::Base); end
class NewsFeedController < Class.new(ActionController::Base); end
end

View file

@ -0,0 +1,42 @@
require File.dirname(__FILE__) + '/../abstract_unit'
class FilterParamController < ActionController::Base
end
class FilterParamTest < Test::Unit::TestCase
def setup
@controller = FilterParamController.new
end
def test_filter_parameters
assert FilterParamController.respond_to?(:filter_parameter_logging)
assert !@controller.respond_to?(:filter_parameters)
FilterParamController.filter_parameter_logging
assert @controller.respond_to?(:filter_parameters)
test_hashes = [[{},{},[]],
[{'foo'=>'bar'},{'foo'=>'bar'},[]],
[{'foo'=>'bar'},{'foo'=>'bar'},%w'food'],
[{'foo'=>'bar'},{'foo'=>'[FILTERED]'},%w'foo'],
[{'foo'=>'bar', 'bar'=>'foo'},{'foo'=>'[FILTERED]', 'bar'=>'foo'},%w'foo baz'],
[{'foo'=>'bar', 'baz'=>'foo'},{'foo'=>'[FILTERED]', 'baz'=>'[FILTERED]'},%w'foo baz'],
[{'bar'=>{'foo'=>'bar','bar'=>'foo'}},{'bar'=>{'foo'=>'[FILTERED]','bar'=>'foo'}},%w'fo'],
[{'foo'=>{'foo'=>'bar','bar'=>'foo'}},{'foo'=>'[FILTERED]'},%w'f banana']]
test_hashes.each do |before_filter, after_filter, filter_words|
FilterParamController.filter_parameter_logging(*filter_words)
assert_equal after_filter, @controller.filter_parameters(before_filter)
filter_words.push('blah')
FilterParamController.filter_parameter_logging(*filter_words) do |key, value|
value.reverse! if key =~ /bargain/
end
before_filter['barg'] = {'bargain'=>'gain', 'blah'=>'bar', 'bar'=>{'bargain'=>{'blah'=>'foo'}}}
after_filter['barg'] = {'bargain'=>'niag', 'blah'=>'[FILTERED]', 'bar'=>{'bargain'=>{'blah'=>'[FILTERED]'}}}
assert_equal after_filter, @controller.filter_parameters(before_filter)
end
end
end

View file

@ -535,7 +535,6 @@ end
class RouteTests < Test::Unit::TestCase
def route(*args)
@route = ::ActionController::Routing::Route.new(*args) unless args.empty?
return @route
@ -972,4 +971,79 @@ class RouteSetTests < Test::Unit::TestCase
end
end
class ControllerComponentTest < Test::Unit::TestCase
def test_traverse_to_controller_should_not_load_arbitrary_files
load_path = $:.dup
base = File.dirname(File.dirname(File.expand_path(__FILE__)))
$: << File.join(base, 'fixtures')
Object.send :const_set, :RAILS_ROOT, File.join(base, 'fixtures/application_root')
assert_equal nil, ActionController::Routing::ControllerComponent.traverse_to_controller(%w(dont_load pretty please))
ensure
$:[0..-1] = load_path
Object.send :remove_const, :RAILS_ROOT
end
def test_traverse_should_not_trip_on_non_module_constants
assert_equal nil, ActionController::Routing::ControllerComponent.traverse_to_controller(%w(admin some_constant a))
end
# This is evil, but people do it.
def test_traverse_to_controller_should_pass_thru_classes
load_path = $:.dup
base = File.dirname(File.dirname(File.expand_path(__FILE__)))
$: << File.join(base, 'fixtures')
$: << File.join(base, 'fixtures/application_root/app/controllers')
$: << File.join(base, 'fixtures/application_root/app/models')
Object.send :const_set, :RAILS_ROOT, File.join(base, 'fixtures/application_root')
pair = ActionController::Routing::ControllerComponent.traverse_to_controller(%w(a_class_that_contains_a_controller poorly_placed))
# Make sure the container class was loaded properly
assert defined?(AClassThatContainsAController)
assert_kind_of Class, AClassThatContainsAController
assert_equal :you_know_it, AClassThatContainsAController.is_special?
# Make sure the controller was too
assert_kind_of Array, pair
assert_equal 2, pair[1]
klass = pair.first
assert_kind_of Class, klass
assert_equal :decidedly_so, klass.is_evil?
assert klass.ancestors.include?(ActionController::Base)
assert defined?(AClassThatContainsAController::PoorlyPlacedController)
assert_equal klass, AClassThatContainsAController::PoorlyPlacedController
ensure
$:[0..-1] = load_path
Object.send :remove_const, :RAILS_ROOT
end
def test_traverse_to_nested_controller
load_path = $:.dup
base = File.dirname(File.dirname(File.expand_path(__FILE__)))
$: << File.join(base, 'fixtures')
$: << File.join(base, 'fixtures/application_root/app/controllers')
Object.send :const_set, :RAILS_ROOT, File.join(base, 'fixtures/application_root')
pair = ActionController::Routing::ControllerComponent.traverse_to_controller(%w(module_that_holds_controllers nested))
assert_not_equal nil, pair
# Make sure that we created a module for the dir
assert defined?(ModuleThatHoldsControllers)
assert_kind_of Module, ModuleThatHoldsControllers
# Make sure the controller is ok
assert_kind_of Array, pair
assert_equal 2, pair[1]
klass = pair.first
assert_kind_of Class, klass
assert klass.ancestors.include?(ActionController::Base)
assert defined?(ModuleThatHoldsControllers::NestedController)
assert_equal klass, ModuleThatHoldsControllers::NestedController
ensure
$:[0..-1] = load_path
Object.send :remove_const, :RAILS_ROOT
end
end
end

View file

@ -85,11 +85,25 @@ class SendFileTest < Test::Unit::TestCase
assert_equal 'type', h['Content-Type']
assert_equal 'disposition; filename="filename"', h['Content-Disposition']
assert_equal 'binary', h['Content-Transfer-Encoding']
# test overriding Cache-Control: no-cache header to fix IE open/save dialog
@controller.headers = { 'Cache-Control' => 'no-cache' }
@controller.send(:send_file_headers!, options)
h = @controller.headers
assert_equal 'private', h['Cache-Control']
end
%w(file data).each do |method|
define_method "test_send_#{method}_status" do
@controller.options = { :stream => false, :status => 500 }
assert_nothing_raised { assert_not_nil process(method) }
assert_equal '500', @controller.headers['Status']
end
define_method "test_default_send_#{method}_status" do
@controller.options = { :stream => false }
assert_nothing_raised { assert_not_nil process(method) }
assert_equal ActionController::Base::DEFAULT_RENDER_STATUS_CODE, @controller.headers['Status']
end
end
end

View file

@ -0,0 +1,7 @@
class AClassThatContainsAController::PoorlyPlacedController < ActionController::Base
def self.is_evil?
:decidedly_so
end
end

View file

@ -0,0 +1,3 @@
class ModuleThatHoldsControllers::NestedController < ActionController::Base
end

View file

@ -0,0 +1,7 @@
class AClassThatContainsAController #often < ActiveRecord::Base
def self.is_special?
:you_know_it
end
end

View file

@ -0,0 +1,3 @@
# see routing/controller component tests
raise Exception, "I should never be loaded"

View file

@ -0,0 +1,134 @@
require 'test/unit'
require File.dirname(__FILE__) + '/../../lib/action_view/helpers/date_helper'
require File.dirname(__FILE__) + "/../abstract_unit"
class CompiledTemplateTests < Test::Unit::TestCase
def setup
@ct = ActionView::CompiledTemplates.new
@v = Class.new
@v.send :include, @ct
@a = './test_compile_template_a.rhtml'
@b = './test_compile_template_b.rhtml'
@s = './test_compile_template_link.rhtml'
end
def teardown
[@a, @b, @s].each do |f|
`rm #{f}` if File.exist?(f) || File.symlink?(f)
end
end
attr_reader :ct, :v
def test_name_allocation
hi_world = ct.method_names['hi world']
hi_sexy = ct.method_names['hi sexy']
wish_upon_a_star = ct.method_names['I love seeing decent error messages']
assert_equal hi_world, ct.method_names['hi world']
assert_equal hi_sexy, ct.method_names['hi sexy']
assert_equal wish_upon_a_star, ct.method_names['I love seeing decent error messages']
assert_equal 3, [hi_world, hi_sexy, wish_upon_a_star].uniq.length
end
def test_wrap_source
assert_equal(
"def aliased_assignment(value)\nself.value = value\nend",
@ct.wrap_source(:aliased_assignment, [:value], 'self.value = value')
)
assert_equal(
"def simple()\nnil\nend",
@ct.wrap_source(:simple, [], 'nil')
)
end
def test_compile_source_single_method
selector = ct.compile_source('doubling method', [:a], 'a + a')
assert_equal 2, @v.new.send(selector, 1)
assert_equal 4, @v.new.send(selector, 2)
assert_equal -4, @v.new.send(selector, -2)
assert_equal 0, @v.new.send(selector, 0)
selector
end
def test_compile_source_two_method
sel1 = test_compile_source_single_method # compile the method in the other test
sel2 = ct.compile_source('doubling method', [:a, :b], 'a + b + a + b')
assert_not_equal sel1, sel2
assert_equal 2, @v.new.send(sel1, 1)
assert_equal 4, @v.new.send(sel1, 2)
assert_equal 6, @v.new.send(sel2, 1, 2)
assert_equal 32, @v.new.send(sel2, 15, 1)
end
def test_mtime
t1 = Time.now
test_compile_source_single_method
assert (t1..Time.now).include?(ct.mtime('doubling method', [:a]))
end
def test_compile_time
`echo '#{@a}' > #{@a}; echo '#{@b}' > #{@b}; ln -s #{@a} #{@s}`
v = ActionView::Base.new
v.base_path = '.'
v.cache_template_loading = false;
sleep 1
t = Time.now
v.compile_and_render_template(:rhtml, '', @a)
v.compile_and_render_template(:rhtml, '', @b)
v.compile_and_render_template(:rhtml, '', @s)
a_n = v.method_names[@a]
b_n = v.method_names[@b]
s_n = v.method_names[@s]
# all of the files have changed since last compile
assert v.compile_time[a_n] > t
assert v.compile_time[b_n] > t
assert v.compile_time[s_n] > t
sleep 1
t = Time.now
v.compile_and_render_template(:rhtml, '', @a)
v.compile_and_render_template(:rhtml, '', @b)
v.compile_and_render_template(:rhtml, '', @s)
# none of the files have changed since last compile
assert v.compile_time[a_n] < t
assert v.compile_time[b_n] < t
assert v.compile_time[s_n] < t
`rm #{@s}; ln -s #{@b} #{@s}`
v.compile_and_render_template(:rhtml, '', @a)
v.compile_and_render_template(:rhtml, '', @b)
v.compile_and_render_template(:rhtml, '', @s)
# the symlink has changed since last compile
assert v.compile_time[a_n] < t
assert v.compile_time[b_n] < t
assert v.compile_time[s_n] > t
sleep 1
`touch #{@b}`
t = Time.now
v.compile_and_render_template(:rhtml, '', @a)
v.compile_and_render_template(:rhtml, '', @b)
v.compile_and_render_template(:rhtml, '', @s)
# the file at the end of the symlink has changed since last compile
# both the symlink and the file at the end of it should be recompiled
assert v.compile_time[a_n] < t
assert v.compile_time[b_n] > t
assert v.compile_time[s_n] > t
end
end
module ActionView
class Base
def compile_time
@@compile_time
end
def method_names
@@method_names
end
end
end

View file

@ -1,3 +1,18 @@
*1.1.5* (August 8th, 2006)
* Rely on Action Pack 1.12.4 and Active Record 1.14.4
*1.1.4* (June 29th, 2006)
* Rely on Action Pack 1.12.3
*1.1.3* (June 27th, 2006)
* Rely on Action Pack 1.12.2 and Active Record 1.14.3
*1.1.2* (April 9th, 2005)
* Rely on Active Record 1.14.2

View file

@ -71,8 +71,8 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "aws"
s.homepage = "http://www.rubyonrails.org"
s.add_dependency('actionpack', '= 1.12.1' + PKG_BUILD)
s.add_dependency('activerecord', '= 1.14.2' + PKG_BUILD)
s.add_dependency('actionpack', '= 1.12.4' + PKG_BUILD)
s.add_dependency('activerecord', '= 1.14.4' + PKG_BUILD)
s.has_rdoc = true
s.requirements << 'none'

View file

@ -2,7 +2,7 @@ module ActionWebService
module VERSION #:nodoc:
MAJOR = 1
MINOR = 1
TINY = 2
TINY = 5
STRING = [MAJOR, MINOR, TINY].join('.')
end

View file

@ -1,9 +1,31 @@
*1.14.2* (April 9th, 2005)
*1.14.4* (August 8th, 2006)
* Add warning about the proper way to validate the presence of a foreign key. #4147 [Francois Beausoleil <francois.beausoleil@gmail.com>]
* Fix syntax error in documentation. #4679 [mislav@nippur.irb.hr]
* Update inconsistent migrations documentation. #4683 [machomagna@gmail.com]
*1.14.3* (June 27th, 2006)
* Fix announcement of very long migration names. #5722 [blake@near-time.com]
* Update callbacks documentation. #3970 [Robby Russell <robby@planetargon.com>]
* Properly quote index names in migrations (closes #4764) [John Long]
* Ensure that Associations#include_eager_conditions? checks both scoped and explicit conditions [Rick]
* Associations#select_limited_ids_list adds the ORDER BY columns to the SELECT DISTINCT List for postgresql. [Rick]
*1.14.2* (April 9th, 2006)
* Fixed calculations for the Oracle Adapter (closes #4626) [Michael Schoen]
*1.14.1* (April 6th, 2005)
*1.14.1* (April 6th, 2006)
* Fix type_name_with_module to handle type names that begin with '::'. Closes #4614. [Nicholas Seckar]
@ -58,7 +80,7 @@
* Fixed broken OCIAdapter #4457 [schoenm@earthlink.net]
*1.14.0* (March 27th, 2005)
*1.14.0* (March 27th, 2006)
* Replace 'rescue Object' with a finer grained rescue. Closes #4431. [Nicholas Seckar]
@ -478,6 +500,7 @@
* Fixed :through relations when using STI inherited classes would use the inherited class's name as foreign key on the join model [Tobias Luetke]
*1.13.2* (December 13th, 2005)
* Become part of Rails 1.0

View file

@ -173,8 +173,8 @@ desc "Publish the release files to RubyForge."
task :release => [ :package ] do
`rubyforge login`
for ext in %w( gem )
release_command = "rubyforge add_release activerecord activerecord 'REL #{PKG_VERSION}' pkg/activerecord-#{PKG_VERSION}.#{ext}"
for ext in %w( gem tgz zip )
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
puts release_command
system(release_command)
end

View file

@ -1163,18 +1163,19 @@ module ActiveRecord
end
def select_limited_ids_list(options, join_dependency)
connection.select_values(
connection.select_all(
construct_finder_sql_for_association_limiting(options, join_dependency),
"#{name} Load IDs For Limited Eager Loading"
).collect { |id| connection.quote(id) }.join(", ")
).collect { |row| connection.quote(row[primary_key]) }.join(", ")
end
def construct_finder_sql_for_association_limiting(options, join_dependency)
scope = scope(:find)
#sql = "SELECT DISTINCT #{table_name}.#{primary_key} FROM #{table_name} "
sql = "SELECT "
sql << "DISTINCT #{table_name}." if include_eager_conditions?(options) || include_eager_order?(options)
sql << "#{primary_key} FROM #{table_name} "
sql << primary_key
sql << ", #{options[:order].split(',').collect { |s| s.split.first } * ', '}" if options[:order] && (include_eager_conditions?(options) || include_eager_order?(options))
sql << " FROM #{table_name} "
if include_eager_conditions?(options) || include_eager_order?(options)
sql << join_dependency.join_associations.collect{|join| join.association_join }.join
@ -1186,16 +1187,24 @@ module ActiveRecord
add_limit!(sql, options, scope)
return sanitize_sql(sql)
end
# Checks if the conditions reference a table other than the current model table
def include_eager_conditions?(options)
conditions = scope(:find, :conditions) || options[:conditions]
return false unless conditions
conditions = conditions.first if conditions.is_a?(Array)
conditions.scan(/(\w+)\.\w+/).flatten.any? do |condition_table_name|
# look in both sets of conditions
conditions = [scope(:find, :conditions), options[:conditions]].inject([]) do |all, cond|
case cond
when nil then all
when Array then all << cond.first
else all << cond
end
end
return false unless conditions.any?
conditions.join(' ').scan(/(\w+)\.\w+/).flatten.any? do |condition_table_name|
condition_table_name != table_name
end
end
# Checks if the query order references a table other than the current model's table.
def include_eager_order?(options)
order = options[:order]
return false unless order

View file

@ -175,7 +175,7 @@ module ActiveRecord #:nodoc:
# serialize :preferences
# end
#
# user = User.create(:preferences) => { "background" => "black", "display" => large })
# user = User.create(:preferences => { "background" => "black", "display" => large })
# User.find(user.id).preferences # => { "background" => "black", "display" => large }
#
# You can also specify a class option as the second parameter that'll raise an exception if a serialized object is retrieved as a

View file

@ -42,26 +42,29 @@ module ActiveRecord
#
# Note: Person.count(:all) will not work because it will use :all as the condition. Use Person.count instead.
def count(*args)
options = {}
#For backwards compatibility, we need to handle both count(conditions=nil, joins=nil) or count(options={}).
if args.size >= 0 and args.size <= 2
options = {}
column_name = :all
# For backwards compatibility, we need to handle both count(conditions=nil, joins=nil) or count(options={}) or count(column_name=:all, options={}).
if args.size >= 0 && args.size <= 2
if args.first.is_a?(Hash)
options = args.first
#should we verify the options hash???
options = args.first
elsif args[1].is_a?(Hash)
options = args[1]
column_name = args.first
options = args[1]
else
# Handle legacy paramter options: def count(conditions=nil, joins=nil)
# Handle legacy paramter options: def count(conditions=nil, joins=nil)
options.merge!(:conditions => args[0]) if args.length > 0
options.merge!(:joins => args[1]) if args.length > 1
options.merge!(:joins => args[1]) if args.length > 1
end
else
raise(ArgumentError, "Unexpected parameters passed to count(*args): expected either count(conditions=nil, joins=nil) or count(options={})")
end
(scope(:find, :include) || options[:include]) ? count_with_associations(options) : calculate(:count, :all, options)
if options[:include] || scope(:find, :include)
count_with_associations(options)
else
calculate(:count, column_name, options)
end
end
# Calculates average value on a given column. The value is returned as a float. See #calculate for examples with options.

View file

@ -243,6 +243,10 @@ module ActiveRecord
def before_save() end
# Is called _after_ Base.save (regardless of whether it's a create or update save).
#
# class Contact < ActiveRecord::Base
# after_save { logger.info( 'New contact saved!' ) }
# end
def after_save() end
def create_or_update_with_callbacks #:nodoc:
return false if callback(:before_save) == false
@ -312,9 +316,16 @@ module ActiveRecord
end
# Is called _before_ Base.destroy.
#
# Note: If you need to _destroy_ or _nullify_ associated records first,
# use the _:dependent_ option on your associations.
def before_destroy() end
# Is called _after_ Base.destroy (and all the attributes have been frozen).
#
# class Contact < ActiveRecord::Base
# after_destroy { |record| logger.info( "Contact #{record.id} was destroyed." ) }
# end
def after_destroy() end
def destroy_with_callbacks #:nodoc:
return false if callback(:before_destroy) == false

View file

@ -119,7 +119,7 @@ module ActiveRecord
# Adds a new column to the named table.
# See TableDefinition#column for details of the options you can use.
def add_column(table_name, column_name, type, options = {})
add_column_sql = "ALTER TABLE #{table_name} ADD #{column_name} #{type_to_sql(type, options[:limit])}"
add_column_sql = "ALTER TABLE #{table_name} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit])}"
add_column_options!(add_column_sql, options)
execute(add_column_sql)
end
@ -128,7 +128,7 @@ module ActiveRecord
# ===== Examples
# remove_column(:suppliers, :qualification)
def remove_column(table_name, column_name)
execute "ALTER TABLE #{table_name} DROP #{column_name}"
execute "ALTER TABLE #{table_name} DROP #{quote_column_name(column_name)}"
end
# Changes the column's definition according to the new options.
@ -184,7 +184,8 @@ module ActiveRecord
# generates
# CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
def add_index(table_name, column_name, options = {})
index_name = "#{table_name}_#{Array(column_name).first}_index"
column_names = Array(column_name)
index_name = index_name(table_name, :column => column_names.first)
if Hash === options # legacy support, since this param was a string
index_type = options[:unique] ? "UNIQUE" : ""
@ -192,8 +193,8 @@ module ActiveRecord
else
index_type = options
end
execute "CREATE #{index_type} INDEX #{index_name} ON #{table_name} (#{Array(column_name).join(", ")})"
quoted_column_names = column_names.map { |e| quote_column_name(e) }.join(", ")
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{table_name} (#{quoted_column_names})"
end
# Remove the given index from the table.
@ -209,7 +210,7 @@ module ActiveRecord
# add_index :accounts, [:username, :password]
# remove_index :accounts, :username
def remove_index(table_name, options = {})
execute "DROP INDEX #{index_name(table_name, options)} ON #{table_name}"
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))} ON #{table_name}"
end
def index_name(table_name, options) #:nodoc:

View file

@ -18,7 +18,6 @@ module ActiveRecord
end
end
config = config.symbolize_keys
host = config[:host]
port = config[:port]

View file

@ -337,8 +337,7 @@ module ActiveRecord
def remove_index(table_name, options) #:nodoc:
execute "DROP INDEX #{index_name(table_name, options)}"
end
end
private
BYTEA_COLUMN_TYPE_OID = 17

View file

@ -213,13 +213,7 @@ module ActiveRecord
end
def remove_index(table_name, options={}) #:nodoc:
if Hash === options
index_name = options[:name]
else
index_name = "#{table_name}_#{options}_index"
end
execute "DROP INDEX #{index_name}"
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
end
def rename_table(name, new_name)

View file

@ -70,8 +70,8 @@ module ActiveRecord
# * <tt>change_column(table_name, column_name, type, options)</tt>: Changes the column to a different type using the same
# parameters as add_column.
# * <tt>remove_column(table_name, column_name)</tt>: Removes the column named +column_name+ from the table called +table_name+.
# * <tt>add_index(table_name, column_name, index_type)</tt>: Add a new index with the name of the column on the column. Specify an optional index_type (e.g. UNIQUE).
# * <tt>remove_index(table_name, column_name)</tt>: Remove the index called the same as the column.
# * <tt>add_index(table_name, column_names, index_type, index_name)</tt>: Add a new index with the name of the column, or +index_name+ (if specified) on the column(s). Specify an optional +index_type+ (e.g. UNIQUE).
# * <tt>remove_index(table_name, index_name)</tt>: Remove the index specified by +index_name+.
#
# == Irreversible transformations
#
@ -243,7 +243,8 @@ module ActiveRecord
def announce(message)
text = "#{name}: #{message}"
write "== %s %s" % [ text, "=" * (75 - text.length) ]
length = [0, 75 - text.length].max
write "== %s %s" % [text, "=" * length]
end
def say(message, subitem=false)

View file

@ -381,6 +381,18 @@ module ActiveRecord
# * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
# occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
# method, proc or string should return or evaluate to a true or false value.
#
# === Warning
# Validate the presence of the foreign key, not the instance variable itself.
# Do this:
# validate_presence_of :invoice_id
#
# Not this:
# validate_presence_of :invoice
#
# If you validate the presence of the associated object, you will get
# failures on saves when both the parent object and the child object are
# new.
def validates_presence_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:blank], :on => :save }
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)

View file

@ -2,7 +2,7 @@ module ActiveRecord
module VERSION #:nodoc:
MAJOR = 1
MINOR = 14
TINY = 2
TINY = 4
STRING = [MAJOR, MINOR, TINY].join('.')
end

View file

@ -179,6 +179,42 @@ class EagerAssociationTest < Test::Unit::TestCase
assert_equal count, posts.size
end
def test_eager_with_has_many_and_limit_and_scoped_conditions_on_the_eagers
posts = nil
Post.with_scope(:find => {
:include => :comments,
:conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'"
}) do
posts = authors(:david).posts.find(:all, :limit => 2)
assert_equal 2, posts.size
end
Post.with_scope(:find => {
:include => [ :comments, :author ],
:conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')"
}) do
count = Post.count(:limit => 2)
assert_equal count, posts.size
end
end
def test_eager_with_has_many_and_limit_and_scoped_and_explicit_conditions_on_the_eagers
Post.with_scope(:find => { :conditions => "1=1" }) do
posts = authors(:david).posts.find(:all,
:include => :comments,
:conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
:limit => 2
)
assert_equal 2, posts.size
count = Post.count(
:include => [ :comments, :author ],
:conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
:limit => 2
)
assert_equal count, posts.size
end
end
def test_eager_association_loading_with_habtm
posts = Post.find(:all, :include => :categories, :order => "posts.id")
assert_equal 2, posts[0].categories.size

View file

@ -922,6 +922,16 @@ class BasicsTest < Test::Unit::TestCase
assert_equal("<baz>", inverted["quux"])
end
def test_sql_injection_via_find
assert_raises(ActiveRecord::RecordNotFound) do
Topic.find("123456 OR id > 0")
end
assert_raises(ActiveRecord::RecordNotFound) do
Topic.find(";;; this should raise an RecordNotFound error")
end
end
def test_column_name_properly_quoted
col_record = ColumnName.new
col_record.references = 40

View file

@ -34,6 +34,7 @@ if ActiveRecord::Base.connection.supports_migrations?
Reminder.reset_column_information
Person.connection.remove_column("people", "last_name") rescue nil
Person.connection.remove_column("people", "key") rescue nil
Person.connection.remove_column("people", "bio") rescue nil
Person.connection.remove_column("people", "age") rescue nil
Person.connection.remove_column("people", "height") rescue nil
@ -47,12 +48,17 @@ if ActiveRecord::Base.connection.supports_migrations?
def test_add_index
Person.connection.add_column "people", "last_name", :string
Person.connection.add_column "people", "administrator", :boolean
Person.connection.add_column "people", "key", :string
assert_nothing_raised { Person.connection.add_index("people", "last_name") }
assert_nothing_raised { Person.connection.remove_index("people", "last_name") }
assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
assert_nothing_raised { Person.connection.remove_index("people", "last_name") }
# quoting
assert_nothing_raised { Person.connection.add_index("people", ["key"], :name => "key", :unique => true) }
assert_nothing_raised { Person.connection.remove_index("people", :name => "key") }
# Sybase adapter does not support indexes on :boolean columns
unless current_adapter?(:SybaseAdapter)

View file

@ -1,11 +1,32 @@
*1.1.2* (April 9th, 2005)
*1.1.5* (August 8th, 2006)
* Mention in docs that config.frameworks doesn't work when getting Rails via Gems. #4857 [Alisdair McDiarmid]
* Change the scaffolding layout to use yield rather than @content_for_layout. [Marcel Molina Jr.]
* Includes critical security patch
*1.1.4* (June 29th, 2006)
* Remove use of opts.on { |options[:name] } style hash assignment. References #4440. [headius@headius.com]
* Updated to Action Pack 1.12.3, ActionWebService 1.1.4, ActionMailer 1.2.3
*1.1.3* (June 27th, 2006)
* Updated to Active Record 1.14.3, Action Pack 1.12.2, ActionWebService 1.1.3, ActionMailer 1.2.2
*1.1.2* (April 9th, 2006)
* Added rake rails:update:configs to update config/boot.rb from the latest (also included in rake rails:update) [DHH]
* Fixed that boot.rb would set RAILS_GEM_VERSION twice, not respect an uncommented RAILS_GEM_VERSION line, and not use require_gem [DHH]
*1.1.1* (April 6th, 2005)
*1.1.1* (April 6th, 2006)
* Enhances plugin#discover allowing it to discover svn:// like URIs (closes #4565) [ruben.nine@gmail.com]
@ -44,7 +65,7 @@
* Avoid passing escapeHTML non-string in Rails' info controller [Nicholas Seckar]
*1.1.0* (March 27th, 2005)
*1.1.0* (March 27th, 2006)
* Allow db:fixtures:load to load a subset of the applications fixtures. [Chad Fowler]
@ -185,6 +206,7 @@
* Honor ActiveRecord::Base.pluralize_table_names when creating and destroying session store table. #3204. [rails@bencurtis.com, Marcel Molina Jr.]
*1.0.0* (December 13th, 2005)
* Update instructions on how to find and install generators. #3172. [Chad Fowler]

View file

@ -124,6 +124,9 @@ application is running. You can inspect domain models, change values, and save t
database. Starting the script without arguments will launch it in the development environment.
Passing an argument will specify a different environment, like <tt>script/console production</tt>.
To reload your controllers and models after launching the console run <tt>reload!</tt>
== Description of contents

View file

@ -279,10 +279,10 @@ spec = Gem::Specification.new do |s|
s.add_dependency('rake', '>= 0.7.1')
s.add_dependency('activesupport', '= 1.3.1' + PKG_BUILD)
s.add_dependency('activerecord', '= 1.14.2' + PKG_BUILD)
s.add_dependency('actionpack', '= 1.12.1' + PKG_BUILD)
s.add_dependency('actionmailer', '= 1.2.1' + PKG_BUILD)
s.add_dependency('actionwebservice', '= 1.1.2' + PKG_BUILD)
s.add_dependency('activerecord', '= 1.14.4' + PKG_BUILD)
s.add_dependency('actionpack', '= 1.12.4' + PKG_BUILD)
s.add_dependency('actionmailer', '= 1.2.4' + PKG_BUILD)
s.add_dependency('actionwebservice', '= 1.1.5' + PKG_BUILD)
s.rdoc_options << '--exclude' << '.'
s.has_rdoc = false

View file

@ -13,7 +13,7 @@ require File.join(File.dirname(__FILE__), 'boot')
Rails::Initializer.run do |config|
# Settings in config/environments/* take precedence those specified here
# Skip frameworks you're not going to use
# Skip frameworks you're not going to use (only works if using vendor/rails)
# config.frameworks -= [ :action_web_service, :action_mailer ]
# Add additional load paths for your own custom dirs

View file

@ -4,8 +4,8 @@ require 'optparse'
options = { :sandbox => false, :irb => irb }
OptionParser.new do |opt|
opt.banner = "Usage: console [environment] [options]"
opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |options[:sandbox]| }
opt.on("--irb=[#{irb}]", 'Invoke a different irb.') { |options[:irb]| }
opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |v| options[:sandbox] = v }
opt.on("--irb=[#{irb}]", 'Invoke a different irb.') { |v| options[:irb] = v }
opt.parse!(ARGV)
end

View file

@ -117,8 +117,8 @@ ARGV.options do |opts|
opts.on(" Options:")
opts.on("-a", "--action=name", "reload|graceful|kill (default: #{OPTIONS[:action]})", String) { |OPTIONS[:action]| }
opts.on("-d", "--dispatcher=path", "default: #{OPTIONS[:dispatcher]}", String) { |OPTIONS[:dispatcher]| }
opts.on("-a", "--action=name", "reload|graceful|kill (default: #{OPTIONS[:action]})", String) { |v| OPTIONS[:action] = v }
opts.on("-d", "--dispatcher=path", "default: #{OPTIONS[:dispatcher]}", String) { |v| OPTIONS[:dispatcher] = v }
opts.separator ""

View file

@ -65,11 +65,11 @@ ARGV.options do |opts|
opts.on(" Options:")
opts.on("-p", "--port=number", Integer, "Starting port number (default: #{OPTIONS[:port]})") { |OPTIONS[:port]| }
opts.on("-i", "--instances=number", Integer, "Number of instances (default: #{OPTIONS[:instances]})") { |OPTIONS[:instances]| }
opts.on("-r", "--repeat=seconds", Integer, "Repeat spawn attempts every n seconds (default: off)") { |OPTIONS[:repeat]| }
opts.on("-e", "--environment=name", String, "test|development|production (default: #{OPTIONS[:environment]})") { |OPTIONS[:environment]| }
opts.on("-s", "--spawner=path", String, "default: #{OPTIONS[:spawner]}") { |OPTIONS[:spawner]| }
opts.on("-p", "--port=number", Integer, "Starting port number (default: #{OPTIONS[:port]})") { |v| OPTIONS[:port] = v }
opts.on("-i", "--instances=number", Integer, "Number of instances (default: #{OPTIONS[:instances]})") { |v| OPTIONS[:instances] = v }
opts.on("-r", "--repeat=seconds", Integer, "Repeat spawn attempts every n seconds (default: off)") { |v| OPTIONS[:repeat] = v }
opts.on("-e", "--environment=name", String, "test|development|production (default: #{OPTIONS[:environment]})") { |v| OPTIONS[:environment] = v }
opts.on("-s", "--spawner=path", String, "default: #{OPTIONS[:spawner]}") { |v| OPTIONS[:spawner] = v }
opts.on("-d", "--dispatcher=path", String, "default: #{OPTIONS[:dispatcher]}") { |dispatcher| OPTIONS[:dispatcher] = File.expand_path(dispatcher) }
opts.separator ""

View file

@ -36,9 +36,9 @@ ARGV.options do |opts|
opts.on(" Options:")
opts.on("-c", "--command=path", String) { |OPTIONS[:command]| }
opts.on("-i", "--interval=seconds", Float) { |OPTIONS[:interval]| }
opts.on("-d", "--daemon") { |OPTIONS[:daemon]| }
opts.on("-c", "--command=path", String) { |v| OPTIONS[:command] = v }
opts.on("-i", "--interval=seconds", Float) { |v| OPTIONS[:interval] = v }
opts.on("-d", "--daemon") { |v| OPTIONS[:daemon] = v }
opts.separator ""

View file

@ -10,7 +10,7 @@ ARGV.options do |opts|
opts.on("-e", "--environment=name", String,
"Specifies the environment for the runner to operate under (test/development/production).",
"Default: development") { |options[:environment]| }
"Default: development") { |v| options[:environment] = v }
opts.separator ""

View file

@ -19,13 +19,13 @@ ARGV.options do |opts|
opts.on("-p", "--port=port", Integer,
"Runs Rails on the specified port.",
"Default: 3000") { |OPTIONS[:port]| }
"Default: 3000") { |v| OPTIONS[:port] = v }
opts.on("-b", "--binding=ip", String,
"Binds Rails to the specified ip.",
"Default: 0.0.0.0") { |OPTIONS[:ip]| }
"Default: 0.0.0.0") { |v| OPTIONS[:ip] = v }
opts.on("-e", "--environment=name", String,
"Specifies the environment to run this server under (test/development/production).",
"Default: development") { |OPTIONS[:environment]| }
"Default: development") { |v| OPTIONS[:environment] = v }
opts.on("-m", "--mime-types=filename", String,
"Specifies an Apache style mime.types configuration file to be used for mime types",
"Default: none") { |mime_types_file| OPTIONS[:mime_types] = WEBrick::HTTPUtils::load_mime_types(mime_types_file) }
@ -36,7 +36,7 @@ ARGV.options do |opts|
opts.on("-c", "--charset=charset", String,
"Set default charset for output.",
"Default: UTF-8") { |OPTIONS[:charset]| }
"Default: UTF-8") { |v| OPTIONS[:charset] = v }
opts.separator ""

View file

@ -2,7 +2,7 @@ module Rails
module VERSION #:nodoc:
MAJOR = 1
MINOR = 1
TINY = 2
TINY = 5
STRING = [MAJOR, MINOR, TINY].join('.')
end

View file

@ -96,15 +96,15 @@ class AppGenerator < Rails::Generator::Base
opt.separator 'Options:'
opt.on("-r", "--ruby=path", String,
"Path to the Ruby binary of your choice (otherwise scripts use env, dispatchers current path).",
"Default: #{DEFAULT_SHEBANG}") { |options[:shebang]| }
"Default: #{DEFAULT_SHEBANG}") { |v| options[:shebang] = v }
opt.on("-d", "--database=name", String,
"Preconfigure for selected database (options: mysql/oracle/postgresql/sqlite2/sqlite3).",
"Default: mysql") { |options[:db]| }
"Default: mysql") { |v| options[:db] = v }
opt.on("-f", "--freeze",
"Freeze Rails in vendor/rails from the gems generating the skeleton",
"Default: false") { |options[:freeze]| }
"Default: false") { |v| options[:freeze] = v }
end
def mysql_socket_location

View file

@ -29,6 +29,6 @@ class ModelGenerator < Rails::Generator::NamedBase
opt.separator ''
opt.separator 'Options:'
opt.on("--skip-migration",
"Don't generate a migration file for this model") { |options[:skip_migration]| }
"Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
end
end

View file

@ -7,7 +7,7 @@
<p style="color: green"><%%= flash[:notice] %></p>
<%%= @content_for_layout %>
<%%= yield %>
</body>
</html>

View file

@ -121,12 +121,12 @@ module Rails
opt.separator ''
opt.separator 'General Options:'
opt.on('-p', '--pretend', 'Run but do not make any changes.') { |options[:pretend]| }
opt.on('-p', '--pretend', 'Run but do not make any changes.') { |v| options[:pretend] = v }
opt.on('-f', '--force', 'Overwrite files that already exist.') { options[:collision] = :force }
opt.on('-s', '--skip', 'Skip files that already exist.') { options[:collision] = :skip }
opt.on('-q', '--quiet', 'Suppress normal output.') { |options[:quiet]| }
opt.on('-t', '--backtrace', 'Debugging: show backtrace on errors.') { |options[:backtrace]| }
opt.on('-h', '--help', 'Show this help message.') { |options[:help]| }
opt.on('-q', '--quiet', 'Suppress normal output.') { |v| options[:quiet] = v }
opt.on('-t', '--backtrace', 'Debugging: show backtrace on errors.') { |v| options[:backtrace] = v }
opt.on('-h', '--help', 'Show this help message.') { |v| options[:help] = v }
opt.on('-c', '--svn', 'Modify files with subversion. (Note: svn must be in path)') do
options[:svn] = `svn status`.inject({}) do |opt, e|
opt[e.chomp[7..-1]] = true

View file

@ -38,7 +38,7 @@ module Rails
protected
# Override with your own script usage banner.
def banner
"Usage: #{$0} [options] generator [args]"
"Usage: #{$0} generator [options] [args]"
end
def usage_message